diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml deleted file mode 100644 index 19524a591..000000000 --- a/.azure-pipelines.yml +++ /dev/null @@ -1,205 +0,0 @@ -trigger: - branches: - include: ['*'] - tags: - include: ['*'] - -jobs: - - job: 'CI' - strategy: - matrix: - #linux-stable: - # rustup_toolchain: stable - # image_name: 'ubuntu-16.04' - linux-beta: - rustup_toolchain: beta - image_name: 'ubuntu-16.04' - linux-nightly: - rustup_toolchain: nightly-2019-09-28 - image_name: 'ubuntu-16.04' - #windows-stable: - # rustup_toolchain: stable - # image_name: 'windows-latest' - windows-beta: - rustup_toolchain: beta-gnu - image_name: 'windows-latest' - windows-nightly: - rustup_toolchain: nightly-2019-09-28 - image_name: 'ubuntu-16.04' - #apple-stable: - # rustup_toolchain: stable - # image_name: 'macOS-10.13' - #apple-beta: - # rustup_toolchain: beta - # image_name: 'macos-latest' - - pool: - vmImage: $(image_name) - - steps: - - script: export CARGO_MAKE_RUN_CODECOV="true" && export CODECOV_TOKEN=$(CODECOV_TOKEN) && export RUSTFLAGS="-C link-dead-code" - displayName: Set up environment variables - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - script: | - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" - displayName: Install Rust - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN% - echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" - displayName: Install Rust - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - script: RUSTFLAGS="-C link-dead-code" cargo build - displayName: Build - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - script: cargo build - displayName: Build - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - script: RUSTFLAGS="-C link-dead-code" cargo test - displayName: Test - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - script: cargo test - displayName: Test - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - # The following steps are not platform-dependent, - # so we only have to run them on Linux. - - - script: cargo install --debug cargo-make - displayName: Install cargo-make - condition: eq( variables['Agent.OS'], 'Linux' ) - - - script: RUSTFLAGS="-C link-dead-code" CODECOV_TOKEN=$(CODECOV_TOKEN) cargo make --no-workspace workspace-coverage - displayName: Run test coverage - condition: eq( variables['Agent.OS'], 'Linux' ) - - - script: rustup component add rustfmt - displayName: Install rustfmt - condition: and( eq( variables['Agent.OS'], 'Linux' ), eq( variables['rustup_toolchain'], 'stable') ) - - - script: cargo fmt -- --check - displayName: Verify formatting - condition: and( eq( variables['Agent.OS'], 'Linux' ), eq( variables['rustup_toolchain'], 'stable') ) - - - script: rustup component add clippy - displayName: Install clippy - condition: eq( variables['Agent.OS'], 'Linux' ) - - - script: cargo clippy --all-targets -- -D warnings - displayName: Run clippy - condition: eq( variables['Agent.OS'], 'Linux' ) - - - job: 'Publish' - condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/') - strategy: - matrix: - linux: - image_name: 'ubuntu-16.04' - platform: 'linux' - rustup_toolchain: 'beta' - windows: - image_name: 'windows-latest' - platform: 'windows' - rustup_toolchain: 'beta' - #macos: - # image_name: 'macOS-10.13' - # platform: 'macos' - - pool: - vmImage: $(image_name) - - steps: - - bash: | - TAG="$(Build.SourceBranch)" - TAG=${TAG#refs/tags/} - echo TAG - echo "##vso[task.setvariable variable=build.tag]$TAG" - displayName: "Create tag variable" - - - script: | - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - displayName: Install Rust - - - script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN% - echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" - displayName: Install Rust - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - script: cargo build --release - displayName: Build - - - script: cargo test --release - displayName: Test - - - task: CopyFiles@2 - displayName: Copy assets - inputs: - sourceFolder: '$(Build.SourcesDirectory)/target/release' - contents: feather-server - targetFolder: '$(Build.BinariesDirectory)/feather' - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - task: CopyFiles@2 - displayName: Copy assets - inputs: - sourceFolder: '$(Build.SourcesDirectory)\target\release' - contents: feather-server.exe - targetFolder: '$(Build.BinariesDirectory)\feather' - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - task: ArchiveFiles@2 - displayName: Gather assets - inputs: - rootFolderOrFile: '$(Build.BinariesDirectory)/feather' - archiveType: 'tar' - tarCompression: 'gz' - archiveFile: '$(Build.ArtifactStagingDirectory)/feather-$(build.tag)-$(platform).tar.gz' - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - task: ArchiveFiles@2 - displayName: Gather assets - inputs: - rootFolderOrFile: '$(Build.BinariesDirectory)\feather\*' - archiveType: 'zip' - archiveFile: '$(Build.ArtifactStagingDirectory)\feather-$(build.tag)-$(platform).zip' - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - - - task: GithubRelease@0 - inputs: - gitHubConnection: 'caelunshun_pat' - repositoryName: 'caelunshun/feather' - action: 'edit' - target: '$(build.sourceVersion)' - tagSource: 'manual' - tag: '$(build.tag)' - assets: '$(Build.ArtifactStagingDirectory)/feather-$(build.tag)-$(platform).tar.gz' - title: '$(build.tag)' - assetUploadMode: 'replace' - addChangeLog: false - condition: and(succeeded(), ne( variables['Agent.OS'], 'Windows_NT' )) - - - task: GithubRelease@0 - inputs: - gitHubConnection: 'caelunshun_pat' - repositoryName: 'caelunshun/feather' - action: 'edit' - target: '$(build.sourceVersion)' - tagSource: 'manual' - tag: '$(build.tag)' - assets: '$(Build.ArtifactStagingDirectory)\feather-$(build.tag)-$(platform).zip' - title: '$(build.tag)' - assetUploadMode: 'replace' - addChangeLog: false - condition: and(succeeded(), eq( variables['Agent.OS'], 'Windows_NT' )) diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index 6da851722..000000000 --- a/.codecov.yml +++ /dev/null @@ -1,18 +0,0 @@ -coverage: - status: - project: - default: - threshold: 1.5 - target: 50 - patch: - default: - threshold: 1.5 - target: 0 - -ignore: - - "blocks/src/blocks.rs" - - "items/src/item.rs" - - "item_block/src/mappings.rs" - - "core/src/biomes.rs" - - "generator" - - "codegen" # No way to run codecov on procedural macros, unfortunately \ No newline at end of file diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 710470df9..000000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -blocks/src/blocks.rs linguist-generated=true -items/src/item.rs linguist-generated=true -item_block/src/mappings.rs linguist-generated=true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 000000000..de7996692 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,42 @@ +--- +name: Bug Report +about: Found a bug? Create a report and help us improve! +labels: 'type: bug' +--- + +## Description + + + + +## Reproduction Steps + +1. +2. +3. +4. + +## What You Expected to Happen + + + + +## What Actually Happened + + + + +## Screenshots and Logs + + + + +## Your Environment + +- Operating System: +- Operating System Version: +- **Feather** Version: + + +## Additional Context + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 000000000..86f4c7706 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,30 @@ +--- +name: New Feature +about: Have an idea for a new feature? We want to hear it! +labels: 'type: feature' +--- + +# Feature Request + +## Description + + + + +## What problem does this solve? What need does it fill? + + + + +## Describe the solution you'd like + + + +## Describe alternatives you've considered + + + + +## Additional Information + + diff --git a/.github/ISSUE_TEMPLATE/missing-documentation.md b/.github/ISSUE_TEMPLATE/missing-documentation.md new file mode 100644 index 000000000..240aca09a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/missing-documentation.md @@ -0,0 +1,33 @@ +--- +name: Missing Documentation +about: Found code that's not documented? Create an issue and help us fix it! +labels: 'type: documentation' +--- + +# Missing Documentation + +## Location + +### PR + +- Linked PR: `N/A` + +### File Location + + + + + + + + + +- `path/to/file.rs#Struct` +- `path/to/file.rs#function` + +## Requirements +Should clearly explain what the purpose of the Struct is... + +## Addition Information + +It's not clear what... \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..906e11095 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,23 @@ +# TITLE - Replace + +## Status + +- [ ] Ready +- [x] Development +- [ ] Hold + +## Description + +_Short description what you did and/or fixed_ + +## Related issues + +_Leave empty if none_ + +## Checklist + +- [ ] Ran `cargo fmt`, `cargo clippy --all-targets`, `cargo build --release` and `cargo test` and fixed any generated errors! +- [ ] Removed unnecessary commented out code +- [ ] Used specific traces (if you trace actions please specify the cause i.e. the player) + +Note: if you locally don't get any errors, but GitHub Actions fails (especially at `clippy`) you might want to check your rust toolchain version. You can then feel free to fix these warnings/errors in your PR. \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..0091579ca --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,139 @@ +name: Check & Test & Lints & Build + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + fmt: + name: Cargo fmt + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - uses: Swatinem/rust-cache@v1 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + + - name: Run cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + clippy: + name: Cargo clippy + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + + - uses: Swatinem/rust-cache@v1 + + - name: Annotate commit with clippy warnings + uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --all-targets --all-features -- -D warnings + + audit: + name: Cargo audit + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - uses: Swatinem/rust-cache@v1 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + + - name: Security audit + uses: actions-rs/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + test: + name: Cargo test + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - uses: Swatinem/rust-cache@v1 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Run cargo test + uses: actions-rs/cargo@v1 + with: + command: test + + build: + name: Cargo build & test + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + use-cross: true + - os: macos-latest + target: x86_64-apple-darwin + use-cross: false + - os: macos-latest + target: aarch64-apple-darwin + use-cross: false + - os: windows-latest + target: x86_64-pc-windows-msvc + cross: false + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - uses: Swatinem/rust-cache@v1 + with: + sharedKey: ${{ matrix.target }} + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + target: ${{ matrix.target }} + override: true + + - name: Run cargo build + uses: actions-rs/cargo@v1 + with: + use-cross: ${{ matrix.use-cross }} + command: build + args: --target=${{ matrix.target }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..06cb11414 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,59 @@ +name: Release +on: + push: + branches: + - release +jobs: + build: + name: Build + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + use-cross: true + - os: ubuntu-latest + target: x86_64-unknown-freebsd + use-cross: true + - os: ubuntu-latest + target: x86_64-pc-windows-gnu + use-cross: true + - os: ubuntu-latest + target: i686-pc-windows-gnu + use-cross: true + - os: macos-latest + target: x86_64-apple-darwin + use-cross: false + - os: macos-latest + target: aarch64-apple-darwin + use-cross: false + - os: windows-latest + target: x86_64-pc-windows-msvc + cross: false + - os: windows-latest + target: i686-pc-windows-msvc + use-cross: false + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - uses: Swatinem/rust-cache@v1 + with: + sharedKey: ${{ matrix.target }} + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + target: ${{ matrix.target }} + override: true + + - name: Run cargo build + uses: actions-rs/cargo@v1 + with: + use-cross: ${{ matrix.use-cross }} + command: build + args: --release --target ${{ matrix.target }} diff --git a/.gitignore b/.gitignore index c132a9511..d0a8c67d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,17 @@ -/target -/blocks/target -/server/target -/core/target +**/target **/*.rs.bk **/.idea -feather.toml -massif.out* \ No newline at end of file +**/.vscode + +# Cargo build configuration +.cargo + +world/ +/config.toml +plugins/ + +# Python cache files (libcraft) +**/__pycache__/ + +# macOS desktop files +**/.DS_STORE diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..508da64a1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "minecraft-data"] + path = minecraft-data + url = https://github.com/PrismarineJS/minecraft-data diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 000000000..f8129fbf8 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,4 @@ +# We use rustfmt, and formatting is checked in CI. +# Please run `cargo fmt` before committing + +# Empty config: default settings! diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac76e7186..2e415952b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,15 @@ If you want to work on the codebase, please keep the following in mind: * Where possible and necessary, please write tests. * Run `cargo test` before committing to ensure you have not broken anything. -Also, please do not write code that is in any way inspired, based on, or taken from Mojang's work, including but not limited to +## Notes to your code + +For notes to your code check the Checklist from [`pull_request_template.md`](.github/pull_request_template.md) + + + +# Original code (code from Minecraft) + +> đŸ›‘ **Do not use any of code based of Minecraft's source**: Please do not write code that is in any way inspired, based on, or taken from Mojang's work, including but not limited to the vanilla server and client. Feather is a "clean-room" implementation, meaning that it is written from scratch without any involvement with proprietary code. By using code from Mojang, the project would become prone to legal issues. \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 4a94d58bc..0b4381092 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3129 +1,3632 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "adler32" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = 3 [[package]] -name = "aes" -version = "0.3.2" +name = "addr2line" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gimli 0.26.1", ] [[package]] -name = "aes-soft" -version = "0.3.3" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "aesni" -version = "0.6.0" +name = "aes" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "cipher", + "cpufeatures", + "opaque-debug", ] [[package]] name = "ahash" -version = "0.2.16" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" dependencies = [ - "const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "const-random", ] [[package]] -name = "aho-corasick" +name = "ahash" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.2.4", + "once_cell", + "version_check", ] [[package]] -name = "alga" -version = "0.9.1" +name = "aho-corasick" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ - "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] -name = "ansi_term" -version = "0.11.0" +name = "anyhow" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" + +[[package]] +name = "approx" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits", ] [[package]] name = "approx" -version = "0.1.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" +dependencies = [ + "num-traits", +] [[package]] -name = "approx" -version = "0.3.2" +name = "argh" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb41d85d92dfab96cb95ab023c265c5e4261bb956c0fb49ca06d90c570f1958" dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "argh_derive", + "argh_shared", ] [[package]] -name = "arrayvec" -version = "0.4.11" +name = "argh_derive" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be69f70ef5497dd6ab331a50bd95c6ac6b8f7f17a7967838332743fbd58dc3b5" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "argh_shared", + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "arrayvec" -version = "0.5.1" +name = "argh_shared" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f8c380fa28aa1b36107cd97f0196474bb7241bb95a453c5c01a15ac74b2eac" [[package]] -name = "as-slice" -version = "0.1.0" +name = "arrayvec" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] -name = "atom" -version = "0.3.5" +name = "arrayvec" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +dependencies = [ + "serde", +] [[package]] name = "atty" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi", ] [[package]] name = "autocfg" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.38" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" dependencies = [ - "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] -name = "backtrace-sys" -version = "0.1.31" +name = "base-x" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" [[package]] name = "base64" -version = "0.10.1" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64ct" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874f8444adcb4952a8bc51305c8be95c8ec8237bb0d2e78d2e039f771f8828a0" + +[[package]] +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "bitflags" -version = "1.2.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitvec" -version = "0.15.2" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "470fbd40e959c961f16841fbf96edbbdcff766ead89a1ae2b53d22852be20998" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] [[package]] -name = "block-cipher-trait" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "block-access" +version = "0.1.0" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quill", ] [[package]] -name = "bstr" -version = "0.2.8" +name = "block-buffer" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-place" +version = "0.1.0" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "quill", ] [[package]] name = "bumpalo" -version = "2.6.0" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "bytecheck" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314889ea31cda264cb7c3d6e6e5c9415a987ecb0e72c17c00d36fbb881d34abe" +dependencies = [ + "bytecheck_derive", + "ptr_meta", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a2b3b92c135dae665a6f760205b89187638e83bed17ef3e44e83c712cf30600" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bytecount" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e" + +[[package]] +name = "bytemuck" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "byteorder" -version = "1.3.2" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "bytes" -version = "0.4.12" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "bzip2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bzip2-sys", + "libc", ] [[package]] -name = "c2-chacha" -version = "0.2.2" +name = "bzip2-sys" +version = "0.1.11+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "pkg-config", ] [[package]] -name = "cast" -version = "0.2.2" +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-quill" +version = "0.1.0" +dependencies = [ + "anyhow", + "argh", + "cargo_metadata", + "heck 0.3.3", + "quill-plugin-format", +] + +[[package]] +name = "cargo_metadata" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" +dependencies = [ + "cargo-platform", + "semver 0.11.0", + "semver-parser 0.10.2", + "serde", + "serde_json", +] [[package]] name = "cc" -version = "1.0.45" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cesu8" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfb8" -version = "0.3.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a4b6c43bf284e617a659ce5dc149676680530a3a4a9bb6b278d1a9ed5b229d" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cipher", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" [[package]] -name = "cgmath" -version = "0.16.1" +name = "cipher" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] [[package]] -name = "chrono" -version = "0.4.9" +name = "clap" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", ] [[package]] -name = "clap" -version = "2.33.0" +name = "clap_derive" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "heck 0.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "cloudabi" -version = "0.0.3" +name = "cmake" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" dependencies = [ - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "colored" -version = "1.8.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "lazy_static", + "winapi", ] +[[package]] +name = "const-oid" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" + [[package]] name = "const-random" -version = "0.1.6" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4" dependencies = [ - "const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "const-random-macro", + "proc-macro-hack", ] [[package]] name = "const-random-macro" -version = "0.1.6" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40" dependencies = [ - "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.2.4", + "lazy_static", + "proc-macro-hack", + "tiny-keccak", ] [[package]] -name = "core-foundation" -version = "0.6.4" +name = "const_fn" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" [[package]] -name = "core-foundation-sys" -version = "0.6.2" +name = "convert_case" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] -name = "crc32fast" -version = "1.2.0" +name = "cpufeatures" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "criterion" -version = "0.3.0" +name = "cranelift-bforest" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6bea67967505247f54fa2c85cf4f6e0e31c4e5692c9b70e4ae58e339067333" dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity", ] [[package]] -name = "criterion-plot" -version = "0.4.0" +name = "cranelift-codegen" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48194035d2752bdd5bdae429e3ab88676e95f52a2b1355a5d4e809f9e39b1d74" dependencies = [ - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "gimli 0.25.0", + "log", + "regalloc", + "smallvec", + "target-lexicon 0.12.2", ] [[package]] -name = "crossbeam" -version = "0.7.2" +name = "cranelift-codegen-meta" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976efb22fcab4f2cd6bd4e9913764616a54d895c1a23530128d04e03633c555f" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen-shared", + "cranelift-entity", ] [[package]] -name = "crossbeam-channel" -version = "0.3.9" +name = "cranelift-codegen-shared" +version = "0.76.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dabb5fe66e04d4652e434195b45ae65b5c8172d520247b8f66d8df42b2b45dc" + +[[package]] +name = "cranelift-entity" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3329733e4d4b8e91c809efcaa4faee80bf66f20164e3dd16d707346bd3494799" + +[[package]] +name = "cranelift-frontend" +version = "0.76.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279afcc0d3e651b773f94837c3d581177b348c8d69e928104b2e9fccb226f921" dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon 0.12.2", ] [[package]] -name = "crossbeam-deque" -version = "0.7.1" +name = "crc32fast" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3" dependencies = [ - "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] -name = "crossbeam-epoch" -version = "0.7.2" +name = "crossbeam-channel" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "crossbeam-utils", ] [[package]] -name = "crossbeam-queue" -version = "0.1.2" +name = "crossbeam-deque" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] -name = "crossbeam-utils" -version = "0.6.6" +name = "crossbeam-epoch" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", ] [[package]] -name = "csv" -version = "1.1.1" +name = "crossbeam-utils" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" dependencies = [ - "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "lazy_static", ] [[package]] -name = "csv-core" -version = "0.1.6" +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", + "rand_core 0.6.3", + "subtle", ] [[package]] -name = "ctrlc" -version = "3.1.3" +name = "darling" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" dependencies = [ - "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core", + "darling_macro", ] [[package]] -name = "derivative" -version = "1.0.3" +name = "darling_core" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", ] [[package]] -name = "derive-new" -version = "0.5.8" +name = "darling_macro" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core", + "quote", + "syn", ] [[package]] -name = "derive_deref" -version = "1.1.0" +name = "der" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "const-oid", + "crypto-bigint", ] [[package]] name = "derive_more" -version = "0.15.0" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn", ] [[package]] -name = "downcast-rs" -version = "1.1.0" +name = "digest" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] [[package]] -name = "dtoa" -version = "0.4.4" +name = "discard" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] name = "either" -version = "1.5.3" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] -name = "encoding_rs" -version = "0.8.20" +name = "enumset" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6216d2c19a6fb5f29d1ada1dc7bc4367a8cbf0fa4af5cf12e07b5bbdde6b5b2c" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "enumset_derive", ] [[package]] -name = "failure" -version = "0.1.5" +name = "enumset_derive" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6451128aa6655d880755345d085494cf7561a6bee7c8dc821e5d77e6d267ecd4" dependencies = [ - "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "darling", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "failure_derive" -version = "0.1.5" +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "instant", +] + +[[package]] +name = "feather-base" +version = "0.1.0" +dependencies = [ + "ahash 0.4.7", + "anyhow", + "arrayvec 0.7.2", + "bitflags", + "bitvec", + "bytemuck", + "byteorder", + "feather-blocks", + "hematite-nbt", + "libcraft-blocks", + "libcraft-core", + "libcraft-inventory", + "libcraft-items", + "libcraft-particles", + "libcraft-text", + "nom", + "nom_locate", + "num-derive", + "num-traits", + "parking_lot", + "quill-common", + "rand 0.8.4", + "rand_pcg", + "serde", + "serde_json", + "serde_test", + "serde_with", + "smallvec", + "thiserror", + "uuid", + "vek", ] [[package]] name = "feather-blocks" -version = "0.5.0" +version = "0.1.0" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "feather-codegen 0.5.0", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "bincode", + "libcraft-blocks", + "num-traits", + "once_cell", + "serde", + "thiserror", + "vek", ] [[package]] -name = "feather-codegen" -version = "0.5.0" +name = "feather-blocks-generator" +version = "0.1.0" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "bincode", + "heck 0.3.3", + "indexmap", + "maplit", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", ] [[package]] -name = "feather-core" -version = "0.5.0" +name = "feather-common" +version = "0.1.0" dependencies = [ - "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitvec 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cfb8 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "feather-blocks 0.5.0", - "feather-codegen 0.5.0", - "feather-items 0.5.0", - "flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "hash32 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash32-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hematite-nbt 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "multimap 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "nalgebra-glm 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "feather-generator" -version = "0.5.0" + "ahash 0.7.6", + "anyhow", + "feather-base", + "feather-blocks", + "feather-ecs", + "feather-utils", + "feather-worldgen", + "flume", + "itertools", + "libcraft-core", + "libcraft-inventory", + "libcraft-items", + "log", + "parking_lot", + "quill-common", + "rand 0.8.4", + "rayon", + "smartstring", + "uuid", +] + +[[package]] +name = "feather-datapacks" +version = "0.1.0" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_deref 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "simple_logger 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ahash 0.4.7", + "anyhow", + "log", + "serde", + "serde_json", + "smartstring", + "thiserror", + "ureq", + "zip", ] [[package]] -name = "feather-item-block" -version = "0.5.0" +name = "feather-ecs" +version = "0.1.0" dependencies = [ - "feather-blocks 0.5.0", - "feather-items 0.5.0", + "ahash 0.7.6", + "anyhow", + "feather-utils", + "hecs", + "log", + "thiserror", ] [[package]] -name = "feather-items" -version = "0.5.0" +name = "feather-plugin-host" +version = "0.1.0" +dependencies = [ + "ahash 0.7.6", + "anyhow", + "bincode", + "bumpalo", + "bytemuck", + "feather-base", + "feather-common", + "feather-ecs", + "feather-plugin-host-macros", + "libloading", + "log", + "paste 1.0.6", + "quill-common", + "quill-plugin-format", + "serde", + "serde_json", + "tempfile", + "vec-arena", + "wasmer", + "wasmer-wasi", +] + +[[package]] +name = "feather-plugin-host-macros" +version = "0.1.0" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "feather-protocol" +version = "0.1.0" dependencies = [ - "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "aes", + "anyhow", + "bytemuck", + "byteorder", + "bytes 0.5.6", + "cfb8", + "feather-base", + "feather-blocks", + "flate2", + "hematite-nbt", + "libcraft-core", + "libcraft-items", + "num-traits", + "parking_lot", + "quill-common", + "serde", + "thiserror", + "uuid", ] [[package]] name = "feather-server" -version = "0.5.0" +version = "0.1.0" dependencies = [ - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitvec 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_deref 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "feather-blocks 0.5.0", - "feather-codegen 0.5.0", - "feather-core 0.5.0", - "feather-item-block 0.5.0", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "heapless 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hematite-nbt 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mojang-api 0.3.0 (git+https://github.com/caelunshun/mojang-api-rs?rev=6525e910ad53953fa16028f0fce74b1a19855733)", - "multimap 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "nalgebra 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nalgebra-glm 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ncollide3d 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint-dig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand-legacy 0.1.0", - "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rsa 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rsa-der 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "shrev 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "simdeez 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "simdnoise 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "simple_logger 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "feather_api" + "ahash 0.7.6", + "anyhow", + "base64", + "base64ct", + "colored", + "crossbeam-utils", + "feather-base", + "feather-common", + "feather-ecs", + "feather-plugin-host", + "feather-protocol", + "feather-utils", + "feather-worldgen", + "fern", + "flate2", + "flume", + "futures-lite", + "hematite-nbt", + "libcraft-core", + "libcraft-items", + "log", + "md-5", + "num-bigint", + "num-traits", + "once_cell", + "parking_lot", + "quill-common", + "rand 0.8.4", + "ring", + "rsa", + "rsa-der", + "serde", + "serde_json", + "sha-1", + "slab", + "time 0.3.6", + "tokio", + "toml", + "ureq", + "uuid", +] + +[[package]] +name = "feather-utils" version = "0.1.0" [[package]] -name = "fixedbitset" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "feather-worldgen" +version = "0.6.0" +dependencies = [ + "approx 0.3.2", + "bitvec", + "feather-base", + "log", + "num-traits", + "once_cell", + "rand 0.7.3", + "rand_xorshift", + "simdnoise", + "smallvec", + "strum", +] [[package]] -name = "flate2" -version = "0.2.20" +name = "fern" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "log", ] [[package]] -name = "flate2" -version = "1.0.12" +name = "filetime" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi", ] [[package]] -name = "fnv" -version = "1.0.6" +name = "flate2" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if 1.0.0", + "crc32fast", + "libc", + "libz-sys", + "miniz_oxide", +] [[package]] -name = "foreign-types" -version = "0.3.2" +name = "flume" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d04dafd11240188e146b6f6476a898004cace3be31d4ec5e08e216bf4947ac0" dependencies = [ - "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin 0.9.2", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "form_urlencoded" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] [[package]] -name = "fuchsia-zircon" -version = "0.3.3" +name = "funty" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" [[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" +name = "futures-core" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" [[package]] -name = "futures" -version = "0.1.29" +name = "futures-io" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" [[package]] -name = "futures-channel-preview" -version = "0.3.0-alpha.19" +name = "futures-lite" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" dependencies = [ - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", ] [[package]] -name = "futures-core-preview" -version = "0.3.0-alpha.19" +name = "futures-sink" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" [[package]] -name = "futures-executor-preview" -version = "0.3.0-alpha.19" +name = "generational-arena" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d3b771574f62d0548cee0ad9057857e9fc25d7a3335f140c84f6acd0bf601" dependencies = [ - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", ] [[package]] -name = "futures-io-preview" -version = "0.3.0-alpha.19" +name = "generic-array" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] [[package]] -name = "futures-join-macro-preview" -version = "0.3.0-alpha.19" +name = "getrandom" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] -name = "futures-preview" -version = "0.3.0-alpha.19" +name = "getrandom" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ - "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "js-sys", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] -name = "futures-select-macro-preview" -version = "0.3.0-alpha.19" +name = "gimli" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" dependencies = [ - "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-iterator", + "indexmap", + "stable_deref_trait", ] [[package]] -name = "futures-sink-preview" -version = "0.3.0-alpha.19" +name = "gimli" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] -name = "futures-util-preview" -version = "0.3.0-alpha.19" +name = "hashbrown" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" dependencies = [ - "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-join-macro-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-select-macro-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ahash 0.4.7", ] [[package]] -name = "generic-array" -version = "0.12.3" +name = "hashbrown" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ahash 0.7.6", ] [[package]] -name = "generic-array" -version = "0.13.2" +name = "heck" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation", ] [[package]] -name = "getrandom" -version = "0.1.12" +name = "heck" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] -name = "h2" -version = "0.2.0-alpha.3" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "hecs" +version = "0.3.2" +source = "git+https://github.com/feather-rs/feather-hecs#824712c4e4ab658e75fabf2a91a54f9d1c0b1790" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.9.1", ] [[package]] -name = "hash32" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "hematite-nbt" +version = "0.5.2" +source = "git+https://github.com/PistonDevelopers/hematite_nbt#ce60b817f31b20125644c12fbf13f981809d5324" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "cesu8", + "flate2", + "serde", ] [[package]] -name = "hash32-derive" -version = "0.1.0" +name = "hermit-abi" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "hashbrown" -version = "0.6.1" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ahash 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "heapless" -version = "0.5.1" +name = "idna" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ - "as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash32 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] -name = "heck" -version = "0.3.1" +name = "indexmap" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "hashbrown 0.11.2", + "serde", ] [[package]] -name = "hematite-nbt" -version = "0.4.1" +name = "inkwell" +version = "0.1.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2223d0eba0ae6d40a3e4680c6a3209143471e1f38b41746ea309aa36dde9f90b" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "either", + "inkwell_internals", + "libc", + "llvm-sys", + "once_cell", + "parking_lot", + "regex", ] [[package]] -name = "hibitset" -version = "0.6.2" +name = "inkwell_internals" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7090af3d300424caa81976b8c97bca41cd70e861272c072e188ae082fb49f9" dependencies = [ - "atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "http" -version = "0.1.18" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] -name = "http-body" -version = "0.2.0-alpha.3" +name = "itertools" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "either", ] [[package]] -name = "httparse" -version = "1.3.4" +name = "itoa" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] -name = "humantime" -version = "1.3.0" +name = "js-sys" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen", ] [[package]] -name = "humantime-serde" -version = "0.1.1" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2", ] [[package]] -name = "hyper" -version = "0.13.0-alpha.4" +name = "leb128" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tower-make 0.3.0-alpha.2a (registry+https://github.com/rust-lang/crates.io-index)", - "tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.5.2", + "bitflags", + "cfg-if 1.0.0", + "ryu", + "static_assertions", ] [[package]] -name = "hyper-tls" -version = "0.4.0-alpha.4" +name = "libc" +version = "0.2.113" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" + +[[package]] +name = "libcraft-blocks" +version = "0.1.0" dependencies = [ - "hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ahash 0.7.6", + "bincode", + "bytemuck", + "flate2", + "libcraft-core", + "libcraft-items", + "libcraft-macros", + "num-derive", + "num-traits", + "once_cell", + "serde", + "thiserror", ] [[package]] -name = "idna" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libcraft-core" +version = "0.1.0" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck", + "num-derive", + "num-traits", + "serde", + "strum", + "strum_macros", + "vek", ] [[package]] -name = "indexmap" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libcraft-generators" +version = "0.1.0" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "bincode", + "flate2", + "libcraft-blocks", + "serde", + "serde_json", ] [[package]] -name = "iovec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libcraft-inventory" +version = "0.1.0" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libcraft-items", + "parking_lot", ] [[package]] -name = "itertools" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libcraft-items" +version = "0.1.0" dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] -name = "itoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libcraft-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "js-sys" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libcraft-particles" +version = "0.1.0" dependencies = [ - "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck", + "libcraft-blocks", + "libcraft-items", + "num-derive", + "num-traits", + "ordinalizer", + "serde", ] [[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "libcraft-text" +version = "0.1.0" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hematite-nbt", + "nom", + "nom_locate", + "serde", + "serde_json", + "serde_with", + "thiserror", + "uuid", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "libloading" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" dependencies = [ - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "winapi", ] [[package]] -name = "libc" -version = "0.2.62" +name = "libm" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] -name = "libm" -version = "0.1.4" +name = "libz-sys" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" +dependencies = [ + "cc", + "cmake", + "libc", + "pkg-config", + "vcpkg", +] [[package]] -name = "lock_api" -version = "0.3.1" +name = "llvm-sys" +version = "120.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4897352ffc39e1b2b3f7078b632222939044b76d3a99d36666c1c47203c104cc" dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "lazy_static", + "libc", + "regex", + "semver 0.11.0", ] [[package]] -name = "log" -version = "0.4.8" +name = "lock_api" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard", ] [[package]] -name = "matches" -version = "0.1.8" +name = "log" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] [[package]] -name = "matrixmultiply" -version = "0.2.3" +name = "loupe" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" dependencies = [ - "rawpointer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap", + "loupe-derive", + "rustversion", ] [[package]] -name = "memchr" -version = "2.2.1" +name = "loupe-derive" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "quote", + "syn", ] [[package]] -name = "memoffset" -version = "0.5.1" +name = "mach" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "mime" -version = "0.3.14" +name = "maplit" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] -name = "mime_guess" -version = "2.0.1" +name = "matches" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] -name = "miniz-sys" -version = "0.1.12" +name = "md-5" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "digest", + "opaque-debug", ] [[package]] -name = "miniz_oxide" -version = "0.3.3" +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memmap2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe3179b85e1fd8b14447cbebadb75e45a1002f541b925f0bfec366d56a81c56d" dependencies = [ - "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "mio" -version = "0.6.19" +name = "memoffset" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", ] [[package]] -name = "mio-uds" -version = "0.6.7" +name = "miniz_oxide" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "adler", + "autocfg 1.0.1", ] [[package]] -name = "miow" -version = "0.2.1" +name = "mio" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "log", + "miow", + "ntapi", + "winapi", ] [[package]] -name = "mojang-api" -version = "0.3.0" -source = "git+https://github.com/caelunshun/mojang-api-rs?rev=6525e910ad53953fa16028f0fce74b1a19855733#6525e910ad53953fa16028f0fce74b1a19855733" +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.10.0-alpha.0 (git+https://github.com/seanmonstar/reqwest?rev=5b55aee1a9ddf785f82d9086c8befc50db268cb8)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] -name = "mopa" +name = "more-asserts" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] -name = "multimap" -version = "0.6.0" +name = "nanorand" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729eb334247daa1803e0a094d0a5c55711b85571179f5ec6e53eccfdf7008958" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.2.4", ] [[package]] -name = "nalgebra" -version = "0.18.1" +name = "nom" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" dependencies = [ - "alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "matrixmultiply 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lexical-core", + "memchr", + "version_check", ] [[package]] -name = "nalgebra-glm" -version = "0.4.2" +name = "nom_locate" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67484adf5711f94f2f28b653bf231bff8e438be33bf5b0f35935a0db4f618a2" dependencies = [ - "alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "nalgebra 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bytecount", + "memchr", + "nom", ] [[package]] -name = "native-tls" -version = "0.2.3" +name = "ntapi" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] -name = "ncollide3d" -version = "0.20.1" +name = "num-bigint" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ - "alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "downcast-rs 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "nalgebra 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slotmap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "num-integer", + "num-traits", ] [[package]] -name = "net2" -version = "0.2.33" +name = "num-bigint-dig" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7", + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.4", + "smallvec", + "zeroize", ] [[package]] -name = "nix" -version = "0.14.1" +name = "num-derive" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "nodrop" -version = "0.1.13" +name = "num-integer" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg 1.0.1", + "num-traits", +] [[package]] -name = "nom" -version = "4.2.3" +name = "num-iter" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "num-integer", + "num-traits", ] [[package]] -name = "num-bigint" -version = "0.2.3" +name = "num-traits" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "libm", ] [[package]] -name = "num-bigint-dig" -version = "0.4.0" +name = "num_cpus" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] [[package]] -name = "num-complex" -version = "0.2.3" +name = "num_threads" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71a1eb3a36534514077c1e079ada2fb170ef30c47d203aa6916138cf882ecd52" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "num-derive" -version = "0.3.0" +name = "object" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast", + "indexmap", + "memchr", ] [[package]] -name = "num-integer" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "observe-creativemode-flight-event" +version = "0.1.0" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quill", ] [[package]] -name = "num-iter" -version = "0.1.39" +name = "once_cell" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] -name = "num-rational" -version = "0.2.2" +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "ordinalizer" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f631c9219be3de11edcff6a906b344dcab3e927e13506a366ddaa8ec49ad7c41" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "num-traits" -version = "0.1.43" +name = "os_str_bytes" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] -name = "num-traits" -version = "0.2.8" +name = "parking" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "instant", + "lock_api", + "parking_lot_core", ] [[package]] -name = "num_cpus" -version = "1.10.1" +name = "parking_lot_core" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", ] [[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "particle-example" +version = "0.1.0" +dependencies = [ + "quill", +] [[package]] -name = "openssl" -version = "0.10.25" +name = "paste" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" dependencies = [ - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)", + "paste-impl", + "proc-macro-hack", ] [[package]] -name = "openssl-probe" -version = "0.1.2" +name = "paste" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] -name = "openssl-sys" -version = "0.9.50" +name = "paste-impl" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", ] [[package]] -name = "ordermap" -version = "0.3.5" +name = "pem-rfc7468" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f22eb0e3c593294a99e9ff4b24cf6b752d43f193aa4415fe5077c159996d497" +dependencies = [ + "base64ct", +] [[package]] -name = "parking_lot" -version = "0.9.0" +name = "percent-encoding" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] -name = "parking_lot_core" -version = "0.6.2" +name = "pest" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ucd-trie", ] [[package]] -name = "paste" -version = "0.1.6" +name = "pin-project" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" dependencies = [ - "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-internal", ] [[package]] -name = "paste-impl" -version = "0.1.6" +name = "pin-project-internal" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" dependencies = [ - "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "percent-encoding" -version = "2.1.0" +name = "pin-project-lite" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" [[package]] -name = "petgraph" -version = "0.4.13" +name = "pkcs1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "116bee8279d783c0cf370efa1a94632f2108e5ef0bb32df31f051647810a4e2c" dependencies = [ - "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "der", + "pem-rfc7468", + "zeroize", ] [[package]] -name = "pin-project" -version = "0.4.2" +name = "pkcs8" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" dependencies = [ - "pin-project-internal 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "der", + "pem-rfc7468", + "pkcs1", + "spki", + "zeroize", ] [[package]] -name = "pin-project-internal" -version = "0.4.2" +name = "pkg-config" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "plugin-macro" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "plugin-message" +version = "0.1.0" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quill", ] [[package]] -name = "pin-utils" -version = "0.1.0-alpha.4" +name = "ppv-lite86" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] -name = "pkg-config" -version = "0.3.16" +name = "pretty-hex" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" [[package]] -name = "ppv-lite86" -version = "0.2.5" +name = "proc-macro-error" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] [[package]] -name = "proc-macro-hack" -version = "0.5.10" +name = "proc-macro-error-attr" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "version_check", ] [[package]] -name = "proc-macro-nested" -version = "0.1.3" +name = "proc-macro-hack" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "0.3.8" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "proxy" +version = "0.1.0" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "clap", + "colored", + "feather-protocol", + "fern", + "log", + "pretty-hex", + "time 0.3.6", ] [[package]] -name = "proc-macro2" -version = "1.0.5" +name = "ptr_meta" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ptr_meta_derive", ] [[package]] -name = "quick-error" -version = "1.2.2" +name = "ptr_meta_derive" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "quote" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "query-entities" +version = "0.1.0" dependencies = [ - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quill", + "rand 0.8.4", ] [[package]] -name = "quote" -version = "0.6.13" +name = "quickcheck" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.8.4", ] [[package]] -name = "quote" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "quill" +version = "0.1.0" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode", + "bytemuck", + "itertools", + "libcraft-blocks", + "libcraft-core", + "libcraft-particles", + "libcraft-text", + "plugin-macro", + "quill-common", + "quill-sys", + "serde_json", + "thiserror", + "uuid", ] [[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "quill-common" +version = "0.1.0" dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode", + "bytemuck", + "derive_more", + "libcraft-core", + "libcraft-particles", + "libcraft-text", + "quill", + "serde", + "smartstring", + "uuid", ] [[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "quill-plugin-format" +version = "0.1.0" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "flate2", + "serde", + "serde_json", + "serde_with", + "tar", + "target-lexicon 0.11.2", ] [[package]] -name = "rand" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "quill-sys" +version = "0.1.0" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quill-common", + "quill-sys-macros", ] [[package]] -name = "rand-legacy" +name = "quill-sys-macros" version = "0.1.0" dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "rand_chacha" -version = "0.1.1" +name = "quote" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] -name = "rand_chacha" -version = "0.2.1" +name = "radium" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", ] [[package]] -name = "rand_core" -version = "0.3.1" +name = "rand" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] -name = "rand_core" -version = "0.4.2" +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", +] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.16", ] [[package]] -name = "rand_hc" -version = "0.1.0" +name = "rand_core" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.2.4", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1", ] [[package]] -name = "rand_isaac" -version = "0.1.1" +name = "rand_hc" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.6.3", ] [[package]] -name = "rand_jitter" -version = "0.1.4" +name = "rand_pcg" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.6.3", ] [[package]] -name = "rand_os" -version = "0.1.3" +name = "rand_xorshift" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1", ] [[package]] -name = "rand_os" -version = "0.2.2" +name = "rayon" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "crossbeam-deque", + "either", + "rayon-core", ] [[package]] -name = "rand_pcg" -version = "0.1.2" +name = "rayon-core" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", ] [[package]] -name = "rand_xorshift" -version = "0.1.1" +name = "redox_syscall" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", ] [[package]] -name = "rand_xorshift" -version = "0.2.0" +name = "regalloc" +version = "0.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "rustc-hash", + "smallvec", ] [[package]] -name = "rand_xoshiro" -version = "0.3.1" +name = "regex" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] -name = "rawpointer" -version = "0.2.1" +name = "regex-syntax" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] -name = "rayon" -version = "1.2.0" +name = "region" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" dependencies = [ - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "libc", + "mach", + "winapi", ] [[package]] -name = "rayon-core" -version = "1.6.0" +name = "remove_dir_all" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] -name = "rdrand" -version = "0.4.0" +name = "rend" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytecheck", ] [[package]] -name = "redox_syscall" -version = "0.1.56" +name = "ring" +version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] [[package]] -name = "regex" -version = "1.3.1" +name = "rkyv" +version = "0.7.29" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a37de5dfc60bae2d94961dacd03c7b80e426b66a99fa1b17799570dbdd8f96" dependencies = [ - "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bytecheck", + "hashbrown 0.11.2", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", ] [[package]] -name = "regex-automata" -version = "0.1.8" +name = "rkyv_derive" +version = "0.7.29" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719d447dd0e84b23cee6cb5b32d97e21efb112a3e3c636c8da36647b938475a1" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "regex-syntax" -version = "0.6.12" +name = "rsa" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d" +dependencies = [ + "byteorder", + "digest", + "lazy_static", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8", + "rand 0.8.4", + "subtle", + "zeroize", +] [[package]] -name = "remove_dir_all" -version = "0.5.2" +name = "rsa-der" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19473b2de3164677ff38e4309c42448ba8d0fe5ad5fa722e7d278f991859aa6" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "simple_asn1", ] [[package]] -name = "reqwest" -version = "0.10.0-alpha.0" -source = "git+https://github.com/seanmonstar/reqwest?rev=5b55aee1a9ddf785f82d9086c8befc50db268cb8#5b55aee1a9ddf785f82d9086c8befc50db268cb8" +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.4.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", - "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0", ] [[package]] -name = "rgb" -version = "0.8.14" +name = "rustc_version" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.4", +] [[package]] -name = "rsa" -version = "0.1.3" +name = "rustls" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint-dig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "ring", + "sct", + "webpki", ] [[package]] -name = "rsa-der" -version = "0.2.1" +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" + +[[package]] +name = "ryu" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "simple_asn1 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] -name = "rustc-demangle" -version = "0.1.16" +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "semver" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] [[package]] -name = "rustc_version" -version = "0.2.3" +name = "semver" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser 0.10.2", + "serde", ] [[package]] -name = "ryu" -version = "1.0.0" +name = "semver" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] -name = "same-file" -version = "1.0.5" +name = "semver-parser" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] -name = "schannel" -version = "0.1.16" +name = "semver-parser" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pest", ] [[package]] -name = "scopeguard" -version = "1.0.0" +name = "serde" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b3c34c1690edf8174f5b289a336ab03f568a4460d8c6df75f2f3a692b3bc6a" +dependencies = [ + "serde_derive", +] [[package]] -name = "security-framework" -version = "0.3.1" +name = "serde_bytes" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" dependencies = [ - "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] -name = "security-framework-sys" -version = "0.3.1" +name = "serde_derive" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784ed1fbfa13fe191077537b0d70ec8ad1e903cfe04831da608aa36457cb653d" dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "semver" -version = "0.9.0" +name = "serde_json" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "651bca88044a8a5166bd0fd984a7ca558301079cf08365ca6287b2bb608cca3e" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] -name = "semver-parser" -version = "0.7.0" +name = "serde_test" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2616dbe01183e562d89c3614f03818b0ae90c218ad149034d957436fb5cba3f4" +dependencies = [ + "serde", +] [[package]] -name = "serde" -version = "1.0.101" +name = "serde_with" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad6056b4cb69b6e43e3a0f055def223380baecc99da683884f205bf347f7c4b3" dependencies = [ - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion", + "serde", + "serde_with_macros", ] [[package]] -name = "serde_derive" -version = "1.0.101" +name = "serde_with_macros" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "darling", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "serde_json" -version = "1.0.41" +name = "sha-1" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "cfg-if 1.0.0", + "cpufeatures", + "digest", + "opaque-debug", ] [[package]] -name = "serde_urlencoded" +name = "sha1" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" dependencies = [ - "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1_smol", ] [[package]] -name = "sha1" -version = "0.6.0" +name = "sha1_smol" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" [[package]] -name = "shred" -version = "0.9.3" +name = "signal-hook-registry" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mopa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] -[[package]] -name = "shrev" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "simdeez" -version = "0.6.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4032959efda4ba5e9c0108c4c88bfa79b2f6eaf1f1e965290d6e8cd058f50887" dependencies = [ - "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "paste 0.1.18", ] [[package]] name = "simdnoise" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "3.1.7" +source = "git+https://github.com/jackmott/rust-simd-noise?rev=3a4f3e6#3a4f3e6f79608616b6ee186dc665b601d015dc1e" dependencies = [ - "simdeez 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "simdeez", ] [[package]] -name = "simple_asn1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "simple-plugin" +version = "0.1.0" dependencies = [ - "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quill", + "rand 0.8.4", ] [[package]] -name = "simple_logger" -version = "1.3.0" +name = "simple_asn1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a762b1c38b9b990c694b9c2f8abe3372ce6a9ceaae6bca39cfc46e054f45745" dependencies = [ - "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint", + "num-traits", + "thiserror", + "time 0.3.6", ] [[package]] name = "slab" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] -name = "slotmap" -version = "0.3.0" +name = "smallvec" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] -name = "smallvec" -version = "0.6.10" +name = "smartstring" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa6a31c0c2b21327ce875f7e8952322acfcfd0c27569a6e18a647281352c9b" +dependencies = [ + "serde", + "static_assertions", +] [[package]] -name = "sourcefile" -version = "0.1.4" +name = "spin" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] -name = "specs" -version = "0.15.1" +name = "spin" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" dependencies = [ - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hibitset 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "shred 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "shrev 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tuple_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api", ] [[package]] -name = "spin" -version = "0.5.2" +name = "spki" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" +dependencies = [ + "der", +] [[package]] name = "stable_deref_trait" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "stream-cipher" -version = "0.3.2" +name = "standback" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check", ] [[package]] -name = "string" -version = "0.2.1" +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", ] +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "strsim" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.16.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" [[package]] name = "strum_macros" -version = "0.16.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "subtle" -version = "2.2.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "0.13.11" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" dependencies = [ - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] -name = "syn" -version = "0.15.44" +name = "synstructure" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", + "unicode-xid", ] [[package]] -name = "syn" -version = "1.0.5" +name = "tap" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] -name = "synstructure" -version = "0.10.2" +name = "tar" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime", + "libc", + "xattr", ] +[[package]] +name = "target-lexicon" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95" + +[[package]] +name = "target-lexicon" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bffcddbc2458fa3e6058414599e3c838a022abae82e5c67b4f7f80298d5bff" + [[package]] name = "tempfile" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "termcolor" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] -name = "thread_local" -version = "0.3.6" +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + +[[package]] +name = "thiserror" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl", ] [[package]] -name = "thread_local" -version = "1.0.0" +name = "thiserror-impl" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "time" -version = "0.1.42" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros 0.1.1", + "version_check", + "winapi", ] [[package]] -name = "tinytemplate" -version = "1.0.2" +name = "time" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d54b9298e05179c335de2b9645d061255bcd5155f843b3e328d2cfe0a5b413" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "libc", + "num_threads", + "quickcheck", + "time-macros 0.2.3", ] [[package]] -name = "tokio" -version = "0.2.0-alpha.6" +name = "time-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-macros 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tracing-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "time-macros-impl", ] [[package]] -name = "tokio-codec" -version = "0.2.0-alpha.6" +name = "time-macros" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" [[package]] -name = "tokio-executor" -version = "0.2.0-alpha.6" +name = "time-macros-impl" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ - "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tracing 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", ] [[package]] -name = "tokio-fs" -version = "0.2.0-alpha.6" +name = "tiny-keccak" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy", ] [[package]] -name = "tokio-io" -version = "0.2.0-alpha.6" +name = "tinyvec" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec_macros", ] [[package]] -name = "tokio-macros" -version = "0.2.0-alpha.6" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "titles" +version = "0.1.0" dependencies = [ - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quill", ] [[package]] -name = "tokio-net" -version = "0.2.0-alpha.6" +name = "tokio" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tracing 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 1.1.0", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", ] [[package]] -name = "tokio-sync" -version = "0.2.0-alpha.6" +name = "tokio-macros" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "tokio-timer" -version = "0.3.0-alpha.6" +name = "toml" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] -name = "tokio-tls" -version = "0.3.0-alpha.6" +name = "tracing" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "toml" -version = "0.5.3" +name = "tracing-attributes" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "tower-make" -version = "0.3.0-alpha.2a" +name = "tracing-core" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ - "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", ] [[package]] -name = "tower-service" -version = "0.3.0-alpha.2" +name = "typenum" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] -name = "tracing" -version = "0.1.9" +name = "ucd-trie" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tracing-attributes 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tracing-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] -name = "tracing-attributes" -version = "0.1.4" +name = "unicode-bidi" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] -name = "tracing-core" -version = "0.1.6" +name = "unicode-normalization" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec", ] [[package]] -name = "try-lock" +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] -name = "tuple_utils" -version = "0.3.0" +name = "untrusted" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] -name = "typenum" -version = "1.11.2" +name = "ureq" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5" +dependencies = [ + "base64", + "chunked_transfer", + "flate2", + "log", + "once_cell", + "rustls", + "serde", + "serde_json", + "url", + "webpki", + "webpki-roots", +] [[package]] -name = "unicase" -version = "2.5.1" +name = "url" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "form_urlencoded", + "idna", + "matches", + "percent-encoding", ] [[package]] -name = "unicode-bidi" -version = "0.3.4" +name = "uuid" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.2.4", + "serde", ] [[package]] -name = "unicode-normalization" -version = "0.1.8" +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec-arena" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae23c56872cdb2d1b1ddb90112da26615654fa4d4e3ee84e2d3b3e9c9853145" + +[[package]] +name = "vek" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d6626f32b226e2c5b35f23ea87eaf683f3d93eaeb16b4084d0683479616f0f" dependencies = [ - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "approx 0.4.0", + "num-integer", + "num-traits", + "rustc_version 0.2.3", + "serde", + "static_assertions", ] [[package]] -name = "unicode-segmentation" -version = "1.3.0" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "unicode-width" -version = "0.1.6" +name = "waker-fn" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] -name = "unicode-xid" -version = "0.1.0" +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] -name = "unicode-xid" -version = "0.2.0" +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] -name = "url" -version = "2.1.0" +name = "wasm-bindgen" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" dependencies = [ - "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "wasm-bindgen-macro", ] [[package]] -name = "uuid" -version = "0.7.4" +name = "wasm-bindgen-backend" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", ] [[package]] -name = "vcpkg" -version = "0.2.7" +name = "wasm-bindgen-macro" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] [[package]] -name = "vec_map" -version = "0.8.1" +name = "wasm-bindgen-macro-support" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] [[package]] -name = "version_check" -version = "0.1.5" +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "wasmer" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f0188c23fc1b7de9bd7f8b834d0b1cd5edbe66e287452e8ce36d24418114f7" +dependencies = [ + "cfg-if 1.0.0", + "indexmap", + "js-sys", + "loupe", + "more-asserts", + "target-lexicon 0.12.2", + "thiserror", + "wasm-bindgen", + "wasmer-compiler", + "wasmer-compiler-cranelift", + "wasmer-compiler-llvm", + "wasmer-derive", + "wasmer-engine", + "wasmer-engine-dylib", + "wasmer-engine-universal", + "wasmer-types", + "wasmer-vm", + "winapi", +] [[package]] -name = "void" -version = "1.0.2" +name = "wasmer-compiler" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c51cc589772c5f90bd329244c2416976d6cb2ee00d59429aaa8f421d9fe447" +dependencies = [ + "enumset", + "loupe", + "rkyv", + "serde", + "serde_bytes", + "smallvec", + "target-lexicon 0.12.2", + "thiserror", + "wasmer-types", + "wasmer-vm", + "wasmparser", +] + +[[package]] +name = "wasmer-compiler-cranelift" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09691e3e323b4e1128d2127f60f9cd988b66ce49afc8184b071c2b5ab16793f2" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "gimli 0.25.0", + "loupe", + "more-asserts", + "rayon", + "smallvec", + "target-lexicon 0.12.2", + "tracing", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-compiler-llvm" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51c7fcf88c86c1ba050dfe1dd8fe3613ad1072a58b07a8c50148145cee249" +dependencies = [ + "byteorder", + "cc", + "inkwell", + "itertools", + "lazy_static", + "libc", + "loupe", + "object", + "rayon", + "regex", + "rustc_version 0.4.0", + "semver 1.0.4", + "smallvec", + "target-lexicon 0.12.2", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] [[package]] -name = "walkdir" -version = "2.2.9" +name = "wasmer-derive" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f5cb7b09640e09f1215da95d6fb7477d2db572f064b803ff705f39ff079cc5" dependencies = [ - "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "want" -version = "0.3.0" +name = "wasmer-engine" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab20311c354fe2c12bc766417e0a1a45f399c1cd8ff262127d1dc86d0588971a" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "enumset", + "lazy_static", + "loupe", + "memmap2", + "more-asserts", + "rustc-demangle", + "serde", + "serde_bytes", + "target-lexicon 0.12.2", + "thiserror", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", ] [[package]] -name = "wasi" -version = "0.7.0" +name = "wasmer-engine-dylib" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd5b7a74731e1dcccaf10a8ff5f72216c82f12972ce17cc81c6caa1afff75ea" +dependencies = [ + "cfg-if 1.0.0", + "enumset", + "leb128", + "libloading", + "loupe", + "rkyv", + "serde", + "tempfile", + "tracing", + "wasmer-compiler", + "wasmer-engine", + "wasmer-object", + "wasmer-types", + "wasmer-vm", + "which", +] [[package]] -name = "wasm-bindgen" -version = "0.2.51" +name = "wasmer-engine-universal" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfeae8d5b825ad7abcf9a34e66eb11e1507b21020efe7bbf9897e3dd8d7869e2" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "enumset", + "leb128", + "loupe", + "region", + "rkyv", + "wasmer-compiler", + "wasmer-engine", + "wasmer-types", + "wasmer-vm", + "winapi", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.51" +name = "wasmer-object" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d4714e4f3bdc3b2157c24284417d19cd99de036da31d00ec5664712dcb72f7" dependencies = [ - "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "object", + "thiserror", + "wasmer-compiler", + "wasmer-types", ] [[package]] -name = "wasm-bindgen-futures" -version = "0.3.27" +name = "wasmer-types" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434e1c0177da0a74ecca90b2aa7d5e86198260f07e8ba83be89feb5f0a4aeead" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap", + "loupe", + "rkyv", + "serde", + "thiserror", ] [[package]] -name = "wasm-bindgen-macro" -version = "0.2.51" +name = "wasmer-vfs" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3a58a3700781aa4f5344915ea082086e75ba7ebe294f60ae499614db92dd00" dependencies = [ - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "thiserror", + "tracing", ] [[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.51" +name = "wasmer-vm" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8f964ebba70d9f81340228b98a164782591f00239fc7f01e1b67afcf0e0156" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "cc", + "cfg-if 1.0.0", + "indexmap", + "libc", + "loupe", + "memoffset", + "more-asserts", + "region", + "rkyv", + "serde", + "thiserror", + "wasmer-types", + "winapi", ] [[package]] -name = "wasm-bindgen-shared" -version = "0.2.51" +name = "wasmer-wasi" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2b1d981ad312dac6e74a41a35b9bca41a6d1157c3e6a575fb1041e4b516610" +dependencies = [ + "cfg-if 1.0.0", + "generational-arena", + "getrandom 0.2.4", + "libc", + "thiserror", + "tracing", + "wasm-bindgen", + "wasmer", + "wasmer-vfs", + "wasmer-wasi-types", + "winapi", +] [[package]] -name = "wasm-bindgen-webidl" -version = "0.2.51" +name = "wasmer-wasi-types" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7731240c0ae536623414beb73091dddf68d1a080f49086fc31ec916536b1af98" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "time 0.2.27", + "wasmer-types", ] +[[package]] +name = "wasmparser" +version = "0.78.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" + [[package]] name = "web-sys" -version = "0.3.28" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", - "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-webidl 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "weedle" -version = "0.10.0" +name = "webpki" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] -name = "winapi" -version = "0.2.8" +name = "webpki-roots" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +dependencies = [ + "webpki", +] [[package]] -name = "winapi" -version = "0.3.8" +name = "which" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either", + "lazy_static", + "libc", ] [[package]] -name = "winapi-build" -version = "0.1.1" +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.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[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 = "winconsole" -version = "0.10.0" +name = "wyz" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" [[package]] -name = "winreg" -version = "0.6.2" +name = "xattr" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "ws2_32-sys" -version = "0.2.1" +name = "zeroize" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize_derive", ] [[package]] -name = "yaml-rust" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "zeroize" -version = "0.6.0" +name = "zeroize_derive" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e8f13fef10b63c06356d65d416b070798ddabcadc10d3ece0c5be9b3c7eddb" dependencies = [ - "zeroize_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", + "synstructure", ] [[package]] -name = "zeroize_derive" -version = "0.1.0" +name = "zip" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" -"checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" -"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" -"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum ahash 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "b35dfc96a657c1842b4eb73180b65e37152d4b94d0eb5cb51708aee7826950b4" -"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d708cb68c7106ed1844de68f50f0157a7788c2909a6926fad5a87546ef6a4ff8" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" -"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "293dac66b274fab06f95e7efb05ec439a6b70136081ea522d270bc351ae5bb27" -"checksum atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" -"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5" -"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" -"checksum bitvec 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a993f74b4c99c1908d156b8d2e0fb6277736b0ecbd833982fd1241d39b2766a6" -"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" -"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708" -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" -"checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -"checksum cfb8 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1b310afa67a25a8d5189eacaf5b14418c8dc3d8bcc5755619d89cab87871260d" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" -"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" -"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b641a8c9867e341f3295564203b1c250eb8ce6cb6126e007941f78c4d2ed7fe" -"checksum const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c750ec12b83377637110d5a57f5ae08e895b06c4b16e2bdbf1a94ef717428c59" -"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" -"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" -"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c" -"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" -"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" -"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" -"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" -"checksum ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7dfd2d8b4c82121dfdff120f818e09fc4380b0b7e17a742081a89b94853e87f" -"checksum derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a" -"checksum derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "71f31892cd5c62e414316f2963c5689242c43d8e7bbcaaeca97e5e28c95d91d9" -"checksum derive_deref 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11554fdb0aa42363a442e0c4278f51c9621e20c1ce3bac51d79e60646f3b8b8f" -"checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" -"checksum downcast-rs 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5fe414cc2fd4447b7da94b27ddfb6831a8a06f35f6d077ab5613ec703866c49a" -"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" -"checksum encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)" = "87240518927716f79692c2ed85bfe6e98196d18c6401ec75355760233a7e12e9" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" -"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" -"checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423" -"checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" -"checksum futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a" -"checksum futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a" -"checksum futures-executor-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "75236e88bd9fe88e5e8bfcd175b665d0528fe03ca4c5207fabc028c8f9d93e98" -"checksum futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "f4914ae450db1921a56c91bde97a27846287d062087d4a652efc09bb3a01ebda" -"checksum futures-join-macro-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "59e260e6b48ce7d99936c40a7088d782a499a67bef41da5481d21b439454bcea" -"checksum futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3b1dce2a0267ada5c6ff75a8ba864b4e679a9e2aa44262af7a3b5516d530d76e" -"checksum futures-select-macro-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "df2ae43560eb10b5e50604c53bead6c9c75eade7081390cd3cce66e1582958f7" -"checksum futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "86f148ef6b69f75bb610d4f9a2336d4fc88c4b5b67129d1a340dd0fd362efeec" -"checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d" -"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0ed1e761351b56f54eb9dcd0cfaca9fd0daecf93918e1cfc01c8a3d26ee7adcd" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" -"checksum h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f107db1419ef8271686187b1a5d47c6431af4a7f4d98b495e7b7fc249bb0a78" -"checksum hash32 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12d790435639c06a7b798af9e1e331ae245b7ef915b92f70a39b4cf8c00686af" -"checksum hash32-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebc0efbd154a17cddc3616d83faef479c0076d871a2143c157b310cc7ca799a2" -"checksum hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6587d09be37fb98a11cb08b9000a3f592451c1b1b613ca69d949160e313a430a" -"checksum heapless 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f339aa7d51777fc0af6aa7cbeb277dfc6e6c029cbdeda48d0fbb92c2337f0e69" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hematite-nbt 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "98b407a33bb1715a4cf0276edfe8df52352c55b2a3703c5079adedf398b92932" -"checksum hibitset 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47e7292fd9f7fe89fa35c98048f2d0a69b79ed243604234d18f6f8a1aa6f408d" -"checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" -"checksum http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f3aef6f3de2bd8585f5b366f3f550b5774500b4764d00cf00f903c95749eec3" -"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum humantime-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f59e8a805c18bc9ded3f4e596cb5f0157d88a235e875480a7593b5926f95065" -"checksum hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d05aa523087ac0b9d8b93dd80d5d482a697308ed3b0dca7b0667511a7fa7cdc" -"checksum hyper-tls 0.4.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "47cb3975f80cc809efe5dfcc52b73c9b281fde33f2df35a2e5f79f35e384ae7f" -"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum js-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "2cc9a97d7cec30128fd8b28a7c1f9df1c001ceb9b441e2b755e24130a6b43c79" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" -"checksum libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" -"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum matrixmultiply 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f" -"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" -"checksum mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1d63acd1b78403cc0c325605908475dd9b9a3acbf65ed8bcab97e27014afcf" -"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599" -"checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" -"checksum miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "304f66c19be2afa56530fa7c39796192eef38618da8d19df725ad7c6d6b2aaae" -"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" -"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum mojang-api 0.3.0 (git+https://github.com/caelunshun/mojang-api-rs?rev=6525e910ad53953fa16028f0fce74b1a19855733)" = "" -"checksum mopa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a785740271256c230f57462d3b83e52f998433a7062fc18f96d5999474a9f915" -"checksum multimap 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de234f818d54830a7103b9be18ad0861d75aeb5e3c89759bc3f9a004cc39cfa3" -"checksum nalgebra 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa9fddbc34c8c35dd2108515587b8ce0cab396f17977b8c738568e4edb521a2" -"checksum nalgebra-glm 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a4cd007520d46d2ca24002ddf538fce40ea2a34ed0ffcd3e2ae0b6ba18811d3" -"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" -"checksum ncollide3d 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ee57cac70a2892e89fab7d5fd295b0ad544d1f877fa70fe8ae4be477514dd61" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" -"checksum num-bigint-dig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cd60678022301da54082fcc383647fc895cba2795f868c871d58d29c8922595" -"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" -"checksum num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" -"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" -"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" -"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2f372b2b53ce10fb823a337aaa674e3a7d072b957c6264d0f4ff0bd86e657449" -"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)" = "2c42dcccb832556b5926bc9ae61e8775f2a61e725ab07ab3d1e7fcf8ae62c3b6" -"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49" -"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" -"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" -"checksum pin-project 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d9156ea5979ae30ecc0460cd848738daf24cfb89eb11a41e0c369ba1f0e6aeb" -"checksum pin-project-internal 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1a375fffcd7bf53d8302fb95c1e2f3e0a1a92bd57edcab796f26f9e527c2f3da" -"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" -"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "114cdf1f426eb7f550f01af5f53a33c0946156f6814aec939b3bd77e844f9a9d" -"checksum proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e" -"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" -"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" -"checksum rawpointer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" -"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" -"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" -"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" -"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum reqwest 0.10.0-alpha.0 (git+https://github.com/seanmonstar/reqwest?rev=5b55aee1a9ddf785f82d9086c8befc50db268cb8)" = "" -"checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" -"checksum rsa 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6ad8d3632f6745bb671c8637e2aa44015537c5e384789d2ea3235739301ed1e0" -"checksum rsa-der 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1170c86c683547fa781a0e39e6e281ebaedd4515be8a806022984f427ea3d44d" -"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" -"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" -"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" -"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" -"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" -"checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" -"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" -"checksum shred 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d15d46c92f8c0aed110a132f3c68a8cdd390048f51fa547c89dc571ba1e01191" -"checksum shrev 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5752e017e03af9d735b4b069f53b7a7fd90fefafa04d8bd0c25581b0bff437f" -"checksum simdeez 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4204ae48b2a871f428dc20426f005be250413fa6263e6f3d93094a36b29504dc" -"checksum simdnoise 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86a9e4c1c3369eab7105ac7e1582a601942fed0a63877cb2e1afcf57f34ed7b3" -"checksum simple_asn1 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b25ecba7165254f0c97d6c22a64b1122a03634b18d20a34daf21e18f892e618" -"checksum simple_logger 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a4756ecc75607ba957820ac0a2413a6c27e6c61191cda0c62c6dcea4da88870" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum slotmap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "759fd553261805f128e2900bf69ab3d034260bc338caf7f0ee54dbf035c85acd" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" -"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" -"checksum specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4943fde8c5d3d14c3d19d2a4c7abbd7b626c270a19e6cd35252294a48feb698c" -"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" -"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22" -"checksum strum_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81" -"checksum subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3af2eb31c42e8f0ccf43548232556c42737e01a96db6e1777b0be108e79799" -"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88ddf1ad580c7e3d1efff877d972bcc93f995556b9087a5a259630985c88ceab" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" -"checksum tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f17f5d6ab0f35c1506678b28fb1798bdf74fcb737e9843c7b17b73e426eba38" -"checksum tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9f5d22fd1e84bd4045d28813491cb7d7caae34d45c80517c2213f09a85e8787a" -"checksum tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee9ceecf69145923834ea73f32ba40c790fd877b74a7817dd0b089f1eb9c7c8" -"checksum tokio-fs 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bf85e16971e06e680c622e0c1b455be94b086275c5ddcd6d4a83a2bfbb83cda" -"checksum tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "112784d5543df30660b04a72ca423bfbd90e8bb32f94dcf610f15401218b22c5" -"checksum tokio-macros 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "86b616374bcdadd95974e1f0dfca07dc913f1163c53840c0d664aca35114964e" -"checksum tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a441682cd32f3559383112c4a7f372f5c9fa1950c5cf8c8dd05274a2ce8c2654" -"checksum tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f1aaeb685540f7407ea0e27f1c9757d258c7c6bf4e3eb19da6fc59b747239d2" -"checksum tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b97c1587fe71018eb245a4a9daa13a5a3b681bbc1f7fdadfe24720e141472c13" -"checksum tokio-tls 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "566b4086589c7eebb86aa625d302ab80720ef2aa088649dcae18ec4d754cbd16" -"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" -"checksum tower-make 0.3.0-alpha.2a (registry+https://github.com/rust-lang/crates.io-index)" = "316d47dd40cde4ac5d88110eaf9a10a4e2a68612d9c056cd2aa24e37dcb484cd" -"checksum tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "63ff37396cd966ce43bea418bfa339f802857495f797dafa00bea5b7221ebdfa" -"checksum tracing 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c21ff9457accc293386c20e8f754d0b059e67e325edf2284f04230d125d7e5ff" -"checksum tracing-attributes 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff978fd9c9afe2cc9c671e247713421c6406b3422305cbdce5de695d3ab4c3c" -"checksum tracing-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "528c8ebaaa16cdac34795180b046c031775b0d56402704d98c096788f33d646a" -"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum tuple_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44834418e2c5b16f47bedf35c28e148db099187dd5feee6367fb2525863af4f1" -"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" -"checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" -"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" -"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" -"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" -"checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" -"checksum wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "cd34c5ba0d228317ce388e87724633c57edca3e7531feb4e25e35aaa07a656af" -"checksum wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "927196b315c23eed2748442ba675a4c54a1a079d90d9bdc5ad16ce31cf90b15b" -"checksum wasm-bindgen-futures 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c" -"checksum wasm-bindgen-macro 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "92c2442bf04d89792816650820c3fb407af8da987a9f10028d5317f5b04c2b4a" -"checksum wasm-bindgen-macro-support 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9c075d27b7991c68ca0f77fe628c3513e64f8c477d422b859e03f28751b46fc5" -"checksum wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "83d61fe986a7af038dd8b5ec660e5849cbd9f38e7492b9404cc48b2b4df731d1" -"checksum wasm-bindgen-webidl 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9b979afb0535fe4749906a674082db1211de8aef466331d43232f63accb7c07c" -"checksum web-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "c84440699cd02ca23bed6f045ffb1497bc18a3c2628bd13e2093186faaaacf6b" -"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" -"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" -"checksum zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e68403b858b6af538b11614e62dfe9ab2facba9f13a0cafb974855cfb495ec95" -"checksum zeroize_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3f07490820219949839d0027b965ffdd659d75be9220c00798762e36c6cd281" + "byteorder", + "bzip2", + "crc32fast", + "flate2", + "thiserror", +] diff --git a/Cargo.toml b/Cargo.toml index 4c9bd66dd..d133b40c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,52 @@ [workspace] members = [ - "core", - "api", - "server", - "blocks", - "items", - "item_block", - "codegen", - "generator", - "util/rand-legacy", -] \ No newline at end of file + # libcraft + "libcraft/core", + "libcraft/blocks", + "libcraft/generators", + "libcraft/items", + "libcraft/macros", + "libcraft/particles", + "libcraft/text", + "libcraft/inventory", + + # Quill + "quill/sys-macros", + "quill/sys", + "quill/common", + "quill/api", + "quill/api/plugin-macro", + "quill/plugin-format", + "quill/cargo-quill", + + # Quill example plugins + "quill/example-plugins/titles", + "quill/example-plugins/block-access", + "quill/example-plugins/block-place", + "quill/example-plugins/particle-example", + "quill/example-plugins/plugin-message", + "quill/example-plugins/query-entities", + "quill/example-plugins/simple", + "quill/example-plugins/observe-creativemode-flight-event", + + # Feather (common and server) + "feather/utils", + "feather/blocks", + "feather/blocks/generator", + "feather/base", + "feather/ecs", + "feather/datapacks", + "feather/worldgen", + "feather/common", + "feather/protocol", + "feather/plugin-host/macros", + "feather/plugin-host", + "feather/server", + + # Other + "proxy", +] + +# No longer need to use release for "development": +[profile.dev.package."*"] +opt-level = 2 \ No newline at end of file diff --git a/README.md b/README.md index 049d72ae4..93f6f99ff 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,49 @@ # Feather -[![build](https://dev.azure.com/caelunshun/feather/_apis/build/status/caelunshun.feather?branchName=develop)](https://dev.azure.com/caelunshun/feather/_build/latest?definitionId=1&branchName=develop) -[![coverage](https://codecov.io/gh/caelunshun/feather/branch/develop/graph/badge.svg)](https://codecov.io/gh/caelunshun/feather) -[![Discord](https://img.shields.io/discord/619316022800809995)](https://discordapp.com/invite/4eYmK69) - -An experimental Minecraft server implementation written in Rust. - -### Features -Many basic features are already implemented: -- [x] Highly scalable architecture -- [x] Anvil world loading and saving -- [x] Physics -- [x] Basic world generation -- [x] Chunk streaming -- [x] Day/night cycle -- [x] Arrow shooting -- [x] Falling blocks -- [x] Block placement and breaking -- [x] Item dropping and collection -- [x] Chat -- [x] Inventory handling -- [x] Movement broadcasting - -Development is currently quite active, and features should be added at a fast pace over the next few months. +[![build](https://github.com/feather-rs/feather/workflows/build/badge.svg)](https://github.com/feather-rs/feather/actions) +[![Discord](https://img.shields.io/discord/619316022800809995?logo=discord)](https://discordapp.com/invite/4eYmK69) + +A Minecraft server implementation written in Rust. + +__Note__: This project is currently inactive. Consider contributing to [`valence`](https://github.com/valence-rs/valence) instead. + +### Supported Minecraft versions + +Feather supports 1.16.5 clients and world saves. We do not currently have plans to support multiple versions at once, but +we may consider this in the future. + +### Goals + +The Feather project aims to provide a Minecraft server that is _fast_, _modular_, and paired with an ergonomic plugin API. + +Our mid-term goal is to make Feather usable on hub and minigame servers. The limited set of gameplay features available in Feather +is not a problem for such servers that require a small subset of vanilla functionality. On the other hand, Feather's modularity +and performance lends itself to these types of servers. Therefore, our current focus is +on building a rich plugin API to enable these use cases. + +In the long term, Feather could be used on larger, more survival-like servers, where its performance should allow many players to simultaneously play on the same world requiring very few resources. + +### Ecosystem + +The Feather ecosystem consists of several repositories: +* [`libcraft`](https://github.com/feather-rs/feather/tree/main/libcraft), a set of Rust crates providing Minecraft functionality. +* [`quill`](https://github.com/feather-rs/feather/tree/main/quill), our work-in-progress plugin API. Quill plugins are written in Rust and compiled to WebAssembly. Feather runs them in a sandboxed WebAssembly VM. +* `feather`, the server software built on top of `libcraft` and `quill`. + +### Performance + +Comparisons to vanilla performance _will_ be extremely misleading, because Feather implements so few features. But if you really want them: + +* Feather can handle 1,000,000 entities spawned by a plugin before it starts to max out the CPU. The vanilla server will croak long before then. +* Feather can handle 500 concurrent player connections with each player walking in a random direction. + +These results _will_ change after more features are implemented in Feather, so take them with a grain of salt. + +Memory usage in Feather is proportional to the number of loaded chunks, not player counts. In the 500 player test, the server uses ~40 MiB of RAM +until the players start to spread out. In the 1,000,000 entities test, it uses 400 MiB of RAM without any chunks loaded. ### Running -We offer precompiled binaries for Windows and Linux at [GitHub Releases](https://github.com/caelunshun/feather/releases). +We offer precompiled binaries for Windows, Linux, and macOS at [GitHub Actions](https://github.com/feather-rs/feather/actions/workflows/main.yml). +NB: Do **NOT** use github releases, they are majorly outdated To run Feather: * Extract the downloaded archive. @@ -32,7 +51,7 @@ To run Feather: * On Linux and macOS: `./feather-server` in the server directory * On Windows: double-click `feather-server.exe` -The server will create a configuration file (`feather.toml`) which you can modify. +The server will create a configuration file (`config.toml`) which you can modify. Feather will generate a world by default. If you want to load a vanilla world, copy the world save to the server directory under the name "world" (by default). @@ -41,14 +60,36 @@ Warning: Feather world persistence is fairly new and will likely cause problems when attempting to open Feather worlds in vanilla. Do not let Feather touch worlds you care about unless they have been backed up. -Feather currently only supports 1.13.2 clients and world saves. In the future, additional versions will be supported. - ### Compiling If you are on another platform, compile the server yourself to try it out: ```bash -git clone https://github.com/caelunshun/feather +git clone https://github.com/feather-rs/feather cd feather cargo build --release ``` +Compiling from source requires the latest stable version of Rust. Older Rust versions may be able +to compile Feather, but they are not guaranteed to keep working. + The server executable will be located in `target/release`. + +### Architecture + +For contributors, we have a work-in-progress explanation of Feather's architecture [here](docs/architecture.md). + +### FAQ + +* Is Feather production ready? + +Not yet. There are numerous bugs and missing features which have yet to be resolved, +and the codebase has not been tested enough to consider the server production ready. + +* How can I contribute? + +Check out our [issue tracker](https://github.com/feather-rs/feather/issues) to find out what needs to be worked on. Feel free +to join [our Discord](https://discordapp.com/invite/4eYmK69) and ask questions whenever you need. Thanks for your interest in contributing! + +* Are there other ways I can help? + +Yes! We're always looking for people to test out the server and find bugs. If you find anything that doesn't +seem right to you, please submit an issue on the issue tracker. diff --git a/api/Cargo.toml b/api/Cargo.toml deleted file mode 100644 index f8c384e2c..000000000 --- a/api/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "feather_api" -version = "0.1.0" -authors = ["caelunshun "] -edition = "2018" - -[dependencies] diff --git a/api/src/lib.rs b/api/src/lib.rs deleted file mode 100644 index 8b1378917..000000000 --- a/api/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/assets/dimension.nbt b/assets/dimension.nbt new file mode 100644 index 000000000..4e3238334 Binary files /dev/null and b/assets/dimension.nbt differ diff --git a/assets/dimension_codec.nbt b/assets/dimension_codec.nbt new file mode 100644 index 000000000..59c3fcd57 Binary files /dev/null and b/assets/dimension_codec.nbt differ diff --git a/blocks/Cargo.toml b/blocks/Cargo.toml deleted file mode 100644 index c9297a5b3..000000000 --- a/blocks/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "feather-blocks" -version = "0.5.0" -authors = ["caelunshun "] -edition = "2018" - -[dependencies] -feather-codegen = { path = "../codegen" } -lazy_static = "1.4" -byteorder = "1.3" -failure = "0.1" -num-traits = "0.2" -num-derive = "0.3" - -[dev-dependencies] -criterion = "0.3" - -[[bench]] -name = "block_id_mappings" -harness = false diff --git a/blocks/benches/block_id_mappings.rs b/blocks/benches/block_id_mappings.rs deleted file mode 100644 index 5ea31b9c0..000000000 --- a/blocks/benches/block_id_mappings.rs +++ /dev/null @@ -1,33 +0,0 @@ -#[macro_use] -extern crate criterion; - -use criterion::{black_box, Criterion}; -use feather_blocks::{ - Block, BlockExt, RedSandstoneStairsData, RedSandstoneStairsFacing, RedSandstoneStairsHalf, - RedSandstoneStairsShape, -}; - -fn to_id_complex_state(c: &mut Criterion) { - c.bench_function("to_id_complex_state", |b| { - b.iter(|| { - let _id = black_box(Block::RedSandstoneStairs(RedSandstoneStairsData { - waterlogged: true, - half: RedSandstoneStairsHalf::Top, - shape: RedSandstoneStairsShape::Straight, - facing: RedSandstoneStairsFacing::South, - })) - .native_state_id(); - }); - }); -} - -fn from_id_complex_state(c: &mut Criterion) { - c.bench_function("from_id_complex_state", |b| { - b.iter(|| { - let _block = Block::from_native_state_id(black_box(7198)); - }); - }); -} - -criterion_group!(benches, to_id_complex_state, from_id_complex_state); -criterion_main!(benches); diff --git a/blocks/data/1.13.2.dat b/blocks/data/1.13.2.dat deleted file mode 100644 index 0858c3c55..000000000 Binary files a/blocks/data/1.13.2.dat and /dev/null differ diff --git a/blocks/data/1.14.4.dat b/blocks/data/1.14.4.dat deleted file mode 100644 index f399f7e33..000000000 Binary files a/blocks/data/1.14.4.dat and /dev/null differ diff --git a/blocks/src/blocks.rs b/blocks/src/blocks.rs deleted file mode 100644 index ffa29ab5c..000000000 --- a/blocks/src/blocks.rs +++ /dev/null @@ -1,29949 +0,0 @@ -//! This file was generated by /generators/blocks -use feather_codegen::{FromSnakeCase, ToSnakeCase}; -use num_traits::FromPrimitive; -use std::collections::HashMap; -const INTERNAL_ID_OFFSETS: [usize; 598usize] = [ - 0usize, 1usize, 2usize, 3usize, 4usize, 5usize, 6usize, 7usize, 8usize, 10usize, 11usize, - 12usize, 14usize, 15usize, 16usize, 17usize, 18usize, 19usize, 20usize, 21usize, 23usize, - 25usize, 27usize, 29usize, 31usize, 33usize, 34usize, 50usize, 66usize, 67usize, 68usize, - 69usize, 70usize, 71usize, 72usize, 75usize, 78usize, 81usize, 84usize, 87usize, 90usize, - 93usize, 96usize, 99usize, 102usize, 105usize, 108usize, 111usize, 114usize, 117usize, - 120usize, 123usize, 126usize, 129usize, 132usize, 135usize, 138usize, 141usize, 144usize, - 158usize, 172usize, 186usize, 200usize, 214usize, 228usize, 229usize, 230usize, 231usize, - 232usize, 233usize, 245usize, 246usize, 247usize, 248usize, 748usize, 764usize, 780usize, - 796usize, 812usize, 828usize, 844usize, 860usize, 876usize, 892usize, 908usize, 924usize, - 940usize, 956usize, 972usize, 988usize, 1004usize, 1016usize, 1028usize, 1040usize, 1041usize, - 1042usize, 1043usize, 1044usize, 1045usize, 1047usize, 1059usize, 1083usize, 1084usize, - 1085usize, 1086usize, 1087usize, 1088usize, 1089usize, 1090usize, 1091usize, 1092usize, - 1093usize, 1094usize, 1095usize, 1096usize, 1097usize, 1098usize, 1099usize, 1111usize, - 1112usize, 1113usize, 1114usize, 1115usize, 1116usize, 1117usize, 1118usize, 1119usize, - 1120usize, 1121usize, 1122usize, 1123usize, 1124usize, 1125usize, 1126usize, 1128usize, - 1129usize, 1130usize, 1131usize, 1132usize, 1136usize, 1648usize, 1649usize, 1729usize, - 1753usize, 3049usize, 3050usize, 3051usize, 3052usize, 3060usize, 3068usize, 3076usize, - 3108usize, 3172usize, 3180usize, 3190usize, 3270usize, 3278usize, 3302usize, 3304usize, - 3368usize, 3370usize, 3372usize, 3374usize, 3376usize, 3378usize, 3380usize, 3382usize, - 3384usize, 3392usize, 3416usize, 3424usize, 3425usize, 3426usize, 3442usize, 3443usize, - 3459usize, 3461usize, 3493usize, 3494usize, 3495usize, 3496usize, 3497usize, 3499usize, - 3503usize, 3507usize, 3514usize, 3578usize, 3579usize, 3580usize, 3581usize, 3582usize, - 3583usize, 3584usize, 3585usize, 3586usize, 3587usize, 3588usize, 3589usize, 3590usize, - 3591usize, 3592usize, 3593usize, 3594usize, 3658usize, 3722usize, 3786usize, 3850usize, - 3914usize, 3978usize, 3979usize, 3980usize, 3981usize, 3982usize, 3983usize, 3984usize, - 3985usize, 3986usize, 3987usize, 3988usize, 4052usize, 4116usize, 4180usize, 4212usize, - 4244usize, 4245usize, 4249usize, 4253usize, 4261usize, 4269usize, 4301usize, 4333usize, - 4413usize, 4493usize, 4495usize, 4496usize, 4497usize, 4529usize, 4609usize, 4613usize, - 4614usize, 4622usize, 4626usize, 4627usize, 4635usize, 4636usize, 4637usize, 4639usize, - 4651usize, 4731usize, 4732usize, 4740usize, 4756usize, 4884usize, 4885usize, 4965usize, - 5045usize, 5125usize, 5137usize, 5138usize, 5202usize, 5266usize, 5267usize, 5268usize, - 5269usize, 5270usize, 5271usize, 5272usize, 5273usize, 5274usize, 5275usize, 5276usize, - 5277usize, 5278usize, 5279usize, 5280usize, 5281usize, 5282usize, 5283usize, 5284usize, - 5285usize, 5286usize, 5287usize, 5288usize, 5296usize, 5304usize, 5328usize, 5352usize, - 5376usize, 5400usize, 5424usize, 5448usize, 5452usize, 5468usize, 5472usize, 5488usize, - 5492usize, 5508usize, 5512usize, 5528usize, 5532usize, 5548usize, 5552usize, 5568usize, - 5572usize, 5576usize, 5580usize, 5604usize, 5620usize, 5636usize, 5652usize, 5684usize, - 5685usize, 5686usize, 5696usize, 5697usize, 5698usize, 5701usize, 5781usize, 5793usize, - 5805usize, 5806usize, 5807usize, 5808usize, 5809usize, 5810usize, 5811usize, 5812usize, - 5813usize, 5814usize, 5815usize, 5816usize, 5817usize, 5818usize, 5819usize, 5820usize, - 5821usize, 5853usize, 5885usize, 5917usize, 5949usize, 5981usize, 6013usize, 6045usize, - 6077usize, 6109usize, 6141usize, 6173usize, 6205usize, 6237usize, 6269usize, 6301usize, - 6333usize, 6413usize, 6493usize, 6494usize, 6495usize, 6559usize, 6560usize, 6561usize, - 6562usize, 6642usize, 6722usize, 6802usize, 6808usize, 6814usize, 6820usize, 6821usize, - 6824usize, 6825usize, 6826usize, 6827usize, 6828usize, 6829usize, 6830usize, 6831usize, - 6832usize, 6833usize, 6834usize, 6835usize, 6836usize, 6837usize, 6838usize, 6839usize, - 6840usize, 6841usize, 6842usize, 6843usize, 6845usize, 6847usize, 6849usize, 6851usize, - 6853usize, 6855usize, 6871usize, 6887usize, 6903usize, 6919usize, 6935usize, 6951usize, - 6967usize, 6983usize, 6999usize, 7015usize, 7031usize, 7047usize, 7063usize, 7079usize, - 7095usize, 7111usize, 7115usize, 7119usize, 7123usize, 7127usize, 7131usize, 7135usize, - 7139usize, 7143usize, 7147usize, 7151usize, 7155usize, 7159usize, 7163usize, 7167usize, - 7171usize, 7175usize, 7176usize, 7177usize, 7178usize, 7258usize, 7264usize, 7270usize, - 7276usize, 7282usize, 7288usize, 7294usize, 7300usize, 7306usize, 7312usize, 7318usize, - 7324usize, 7330usize, 7336usize, 7342usize, 7348usize, 7354usize, 7355usize, 7356usize, - 7357usize, 7358usize, 7390usize, 7422usize, 7454usize, 7486usize, 7518usize, 7550usize, - 7582usize, 7614usize, 7646usize, 7678usize, 7742usize, 7806usize, 7870usize, 7934usize, - 7998usize, 8004usize, 8068usize, 8074usize, 8075usize, 8078usize, 8158usize, 8159usize, - 8163usize, 8164usize, 8165usize, 8177usize, 8189usize, 8193usize, 8194usize, 8195usize, - 8196usize, 8199usize, 8200usize, 8212usize, 8218usize, 8224usize, 8230usize, 8236usize, - 8242usize, 8248usize, 8254usize, 8260usize, 8266usize, 8272usize, 8278usize, 8284usize, - 8290usize, 8296usize, 8302usize, 8308usize, 8314usize, 8318usize, 8322usize, 8326usize, - 8330usize, 8334usize, 8338usize, 8342usize, 8346usize, 8350usize, 8354usize, 8358usize, - 8362usize, 8366usize, 8370usize, 8374usize, 8378usize, 8379usize, 8380usize, 8381usize, - 8382usize, 8383usize, 8384usize, 8385usize, 8386usize, 8387usize, 8388usize, 8389usize, - 8390usize, 8391usize, 8392usize, 8393usize, 8394usize, 8395usize, 8396usize, 8397usize, - 8398usize, 8399usize, 8400usize, 8401usize, 8402usize, 8403usize, 8404usize, 8405usize, - 8406usize, 8407usize, 8408usize, 8409usize, 8410usize, 8436usize, 8437usize, 8438usize, - 8450usize, 8451usize, 8452usize, 8453usize, 8454usize, 8455usize, 8456usize, 8457usize, - 8458usize, 8459usize, 8460usize, 8462usize, 8464usize, 8466usize, 8468usize, 8470usize, - 8472usize, 8474usize, 8476usize, 8478usize, 8480usize, 8488usize, 8496usize, 8504usize, - 8512usize, 8520usize, 8528usize, 8536usize, 8544usize, 8552usize, 8560usize, 8562usize, - 8564usize, 8566usize, 8568usize, 8570usize, 8572usize, 8574usize, 8576usize, 8578usize, - 8580usize, 8588usize, 8589usize, 8591usize, 8592usize, 8593usize, 8595usize, -]; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Block { - Air, - Stone, - Granite, - PolishedGranite, - Diorite, - PolishedDiorite, - Andesite, - PolishedAndesite, - GrassBlock(GrassBlockData), - Dirt, - CoarseDirt, - Podzol(PodzolData), - Cobblestone, - OakPlanks, - SprucePlanks, - BirchPlanks, - JunglePlanks, - AcaciaPlanks, - DarkOakPlanks, - OakSapling(OakSaplingData), - SpruceSapling(SpruceSaplingData), - BirchSapling(BirchSaplingData), - JungleSapling(JungleSaplingData), - AcaciaSapling(AcaciaSaplingData), - DarkOakSapling(DarkOakSaplingData), - Bedrock, - Water(WaterData), - Lava(LavaData), - Sand, - RedSand, - Gravel, - GoldOre, - IronOre, - CoalOre, - OakLog(OakLogData), - SpruceLog(SpruceLogData), - BirchLog(BirchLogData), - JungleLog(JungleLogData), - AcaciaLog(AcaciaLogData), - DarkOakLog(DarkOakLogData), - StrippedSpruceLog(StrippedSpruceLogData), - StrippedBirchLog(StrippedBirchLogData), - StrippedJungleLog(StrippedJungleLogData), - StrippedAcaciaLog(StrippedAcaciaLogData), - StrippedDarkOakLog(StrippedDarkOakLogData), - StrippedOakLog(StrippedOakLogData), - OakWood(OakWoodData), - SpruceWood(SpruceWoodData), - BirchWood(BirchWoodData), - JungleWood(JungleWoodData), - AcaciaWood(AcaciaWoodData), - DarkOakWood(DarkOakWoodData), - StrippedOakWood(StrippedOakWoodData), - StrippedSpruceWood(StrippedSpruceWoodData), - StrippedBirchWood(StrippedBirchWoodData), - StrippedJungleWood(StrippedJungleWoodData), - StrippedAcaciaWood(StrippedAcaciaWoodData), - StrippedDarkOakWood(StrippedDarkOakWoodData), - OakLeaves(OakLeavesData), - SpruceLeaves(SpruceLeavesData), - BirchLeaves(BirchLeavesData), - JungleLeaves(JungleLeavesData), - AcaciaLeaves(AcaciaLeavesData), - DarkOakLeaves(DarkOakLeavesData), - Sponge, - WetSponge, - Glass, - LapisOre, - LapisBlock, - Dispenser(DispenserData), - Sandstone, - ChiseledSandstone, - CutSandstone, - NoteBlock(NoteBlockData), - WhiteBed(WhiteBedData), - OrangeBed(OrangeBedData), - MagentaBed(MagentaBedData), - LightBlueBed(LightBlueBedData), - YellowBed(YellowBedData), - LimeBed(LimeBedData), - PinkBed(PinkBedData), - GrayBed(GrayBedData), - LightGrayBed(LightGrayBedData), - CyanBed(CyanBedData), - PurpleBed(PurpleBedData), - BlueBed(BlueBedData), - BrownBed(BrownBedData), - GreenBed(GreenBedData), - RedBed(RedBedData), - BlackBed(BlackBedData), - PoweredRail(PoweredRailData), - DetectorRail(DetectorRailData), - StickyPiston(StickyPistonData), - Cobweb, - Grass, - Fern, - DeadBush, - Seagrass, - TallSeagrass(TallSeagrassData), - Piston(PistonData), - PistonHead(PistonHeadData), - WhiteWool, - OrangeWool, - MagentaWool, - LightBlueWool, - YellowWool, - LimeWool, - PinkWool, - GrayWool, - LightGrayWool, - CyanWool, - PurpleWool, - BlueWool, - BrownWool, - GreenWool, - RedWool, - BlackWool, - MovingPiston(MovingPistonData), - Dandelion, - Poppy, - BlueOrchid, - Allium, - AzureBluet, - RedTulip, - OrangeTulip, - WhiteTulip, - PinkTulip, - OxeyeDaisy, - BrownMushroom, - RedMushroom, - GoldBlock, - IronBlock, - Bricks, - Tnt(TntData), - Bookshelf, - MossyCobblestone, - Obsidian, - Torch, - WallTorch(WallTorchData), - Fire(FireData), - Spawner, - OakStairs(OakStairsData), - Chest(ChestData), - RedstoneWire(RedstoneWireData), - DiamondOre, - DiamondBlock, - CraftingTable, - Wheat(WheatData), - Farmland(FarmlandData), - Furnace(FurnaceData), - Sign(SignData), - OakDoor(OakDoorData), - Ladder(LadderData), - Rail(RailData), - CobblestoneStairs(CobblestoneStairsData), - WallSign(WallSignData), - Lever(LeverData), - StonePressurePlate(StonePressurePlateData), - IronDoor(IronDoorData), - OakPressurePlate(OakPressurePlateData), - SprucePressurePlate(SprucePressurePlateData), - BirchPressurePlate(BirchPressurePlateData), - JunglePressurePlate(JunglePressurePlateData), - AcaciaPressurePlate(AcaciaPressurePlateData), - DarkOakPressurePlate(DarkOakPressurePlateData), - RedstoneOre(RedstoneOreData), - RedstoneTorch(RedstoneTorchData), - RedstoneWallTorch(RedstoneWallTorchData), - StoneButton(StoneButtonData), - Snow(SnowData), - Ice, - SnowBlock, - Cactus(CactusData), - Clay, - SugarCane(SugarCaneData), - Jukebox(JukeboxData), - OakFence(OakFenceData), - Pumpkin, - Netherrack, - SoulSand, - Glowstone, - NetherPortal(NetherPortalData), - CarvedPumpkin(CarvedPumpkinData), - JackOLantern(JackOLanternData), - Cake(CakeData), - Repeater(RepeaterData), - WhiteStainedGlass, - OrangeStainedGlass, - MagentaStainedGlass, - LightBlueStainedGlass, - YellowStainedGlass, - LimeStainedGlass, - PinkStainedGlass, - GrayStainedGlass, - LightGrayStainedGlass, - CyanStainedGlass, - PurpleStainedGlass, - BlueStainedGlass, - BrownStainedGlass, - GreenStainedGlass, - RedStainedGlass, - BlackStainedGlass, - OakTrapdoor(OakTrapdoorData), - SpruceTrapdoor(SpruceTrapdoorData), - BirchTrapdoor(BirchTrapdoorData), - JungleTrapdoor(JungleTrapdoorData), - AcaciaTrapdoor(AcaciaTrapdoorData), - DarkOakTrapdoor(DarkOakTrapdoorData), - InfestedStone, - InfestedCobblestone, - InfestedStoneBricks, - InfestedMossyStoneBricks, - InfestedCrackedStoneBricks, - InfestedChiseledStoneBricks, - StoneBricks, - MossyStoneBricks, - CrackedStoneBricks, - ChiseledStoneBricks, - BrownMushroomBlock(BrownMushroomBlockData), - RedMushroomBlock(RedMushroomBlockData), - MushroomStem(MushroomStemData), - IronBars(IronBarsData), - GlassPane(GlassPaneData), - Melon, - AttachedPumpkinStem(AttachedPumpkinStemData), - AttachedMelonStem(AttachedMelonStemData), - PumpkinStem(PumpkinStemData), - MelonStem(MelonStemData), - Vine(VineData), - OakFenceGate(OakFenceGateData), - BrickStairs(BrickStairsData), - StoneBrickStairs(StoneBrickStairsData), - Mycelium(MyceliumData), - LilyPad, - NetherBricks, - NetherBrickFence(NetherBrickFenceData), - NetherBrickStairs(NetherBrickStairsData), - NetherWart(NetherWartData), - EnchantingTable, - BrewingStand(BrewingStandData), - Cauldron(CauldronData), - EndPortal, - EndPortalFrame(EndPortalFrameData), - EndStone, - DragonEgg, - RedstoneLamp(RedstoneLampData), - Cocoa(CocoaData), - SandstoneStairs(SandstoneStairsData), - EmeraldOre, - EnderChest(EnderChestData), - TripwireHook(TripwireHookData), - Tripwire(TripwireData), - EmeraldBlock, - SpruceStairs(SpruceStairsData), - BirchStairs(BirchStairsData), - JungleStairs(JungleStairsData), - CommandBlock(CommandBlockData), - Beacon, - CobblestoneWall(CobblestoneWallData), - MossyCobblestoneWall(MossyCobblestoneWallData), - FlowerPot, - PottedOakSapling, - PottedSpruceSapling, - PottedBirchSapling, - PottedJungleSapling, - PottedAcaciaSapling, - PottedDarkOakSapling, - PottedFern, - PottedDandelion, - PottedPoppy, - PottedBlueOrchid, - PottedAllium, - PottedAzureBluet, - PottedRedTulip, - PottedOrangeTulip, - PottedWhiteTulip, - PottedPinkTulip, - PottedOxeyeDaisy, - PottedRedMushroom, - PottedBrownMushroom, - PottedDeadBush, - PottedCactus, - Carrots(CarrotsData), - Potatoes(PotatoesData), - OakButton(OakButtonData), - SpruceButton(SpruceButtonData), - BirchButton(BirchButtonData), - JungleButton(JungleButtonData), - AcaciaButton(AcaciaButtonData), - DarkOakButton(DarkOakButtonData), - SkeletonWallSkull(SkeletonWallSkullData), - SkeletonSkull(SkeletonSkullData), - WitherSkeletonWallSkull(WitherSkeletonWallSkullData), - WitherSkeletonSkull(WitherSkeletonSkullData), - ZombieWallHead(ZombieWallHeadData), - ZombieHead(ZombieHeadData), - PlayerWallHead(PlayerWallHeadData), - PlayerHead(PlayerHeadData), - CreeperWallHead(CreeperWallHeadData), - CreeperHead(CreeperHeadData), - DragonWallHead(DragonWallHeadData), - DragonHead(DragonHeadData), - Anvil(AnvilData), - ChippedAnvil(ChippedAnvilData), - DamagedAnvil(DamagedAnvilData), - TrappedChest(TrappedChestData), - LightWeightedPressurePlate(LightWeightedPressurePlateData), - HeavyWeightedPressurePlate(HeavyWeightedPressurePlateData), - Comparator(ComparatorData), - DaylightDetector(DaylightDetectorData), - RedstoneBlock, - NetherQuartzOre, - Hopper(HopperData), - QuartzBlock, - ChiseledQuartzBlock, - QuartzPillar(QuartzPillarData), - QuartzStairs(QuartzStairsData), - ActivatorRail(ActivatorRailData), - Dropper(DropperData), - WhiteTerracotta, - OrangeTerracotta, - MagentaTerracotta, - LightBlueTerracotta, - YellowTerracotta, - LimeTerracotta, - PinkTerracotta, - GrayTerracotta, - LightGrayTerracotta, - CyanTerracotta, - PurpleTerracotta, - BlueTerracotta, - BrownTerracotta, - GreenTerracotta, - RedTerracotta, - BlackTerracotta, - WhiteStainedGlassPane(WhiteStainedGlassPaneData), - OrangeStainedGlassPane(OrangeStainedGlassPaneData), - MagentaStainedGlassPane(MagentaStainedGlassPaneData), - LightBlueStainedGlassPane(LightBlueStainedGlassPaneData), - YellowStainedGlassPane(YellowStainedGlassPaneData), - LimeStainedGlassPane(LimeStainedGlassPaneData), - PinkStainedGlassPane(PinkStainedGlassPaneData), - GrayStainedGlassPane(GrayStainedGlassPaneData), - LightGrayStainedGlassPane(LightGrayStainedGlassPaneData), - CyanStainedGlassPane(CyanStainedGlassPaneData), - PurpleStainedGlassPane(PurpleStainedGlassPaneData), - BlueStainedGlassPane(BlueStainedGlassPaneData), - BrownStainedGlassPane(BrownStainedGlassPaneData), - GreenStainedGlassPane(GreenStainedGlassPaneData), - RedStainedGlassPane(RedStainedGlassPaneData), - BlackStainedGlassPane(BlackStainedGlassPaneData), - AcaciaStairs(AcaciaStairsData), - DarkOakStairs(DarkOakStairsData), - SlimeBlock, - Barrier, - IronTrapdoor(IronTrapdoorData), - Prismarine, - PrismarineBricks, - DarkPrismarine, - PrismarineStairs(PrismarineStairsData), - PrismarineBrickStairs(PrismarineBrickStairsData), - DarkPrismarineStairs(DarkPrismarineStairsData), - PrismarineSlab(PrismarineSlabData), - PrismarineBrickSlab(PrismarineBrickSlabData), - DarkPrismarineSlab(DarkPrismarineSlabData), - SeaLantern, - HayBlock(HayBlockData), - WhiteCarpet, - OrangeCarpet, - MagentaCarpet, - LightBlueCarpet, - YellowCarpet, - LimeCarpet, - PinkCarpet, - GrayCarpet, - LightGrayCarpet, - CyanCarpet, - PurpleCarpet, - BlueCarpet, - BrownCarpet, - GreenCarpet, - RedCarpet, - BlackCarpet, - Terracotta, - CoalBlock, - PackedIce, - Sunflower(SunflowerData), - Lilac(LilacData), - RoseBush(RoseBushData), - Peony(PeonyData), - TallGrass(TallGrassData), - LargeFern(LargeFernData), - WhiteBanner(WhiteBannerData), - OrangeBanner(OrangeBannerData), - MagentaBanner(MagentaBannerData), - LightBlueBanner(LightBlueBannerData), - YellowBanner(YellowBannerData), - LimeBanner(LimeBannerData), - PinkBanner(PinkBannerData), - GrayBanner(GrayBannerData), - LightGrayBanner(LightGrayBannerData), - CyanBanner(CyanBannerData), - PurpleBanner(PurpleBannerData), - BlueBanner(BlueBannerData), - BrownBanner(BrownBannerData), - GreenBanner(GreenBannerData), - RedBanner(RedBannerData), - BlackBanner(BlackBannerData), - WhiteWallBanner(WhiteWallBannerData), - OrangeWallBanner(OrangeWallBannerData), - MagentaWallBanner(MagentaWallBannerData), - LightBlueWallBanner(LightBlueWallBannerData), - YellowWallBanner(YellowWallBannerData), - LimeWallBanner(LimeWallBannerData), - PinkWallBanner(PinkWallBannerData), - GrayWallBanner(GrayWallBannerData), - LightGrayWallBanner(LightGrayWallBannerData), - CyanWallBanner(CyanWallBannerData), - PurpleWallBanner(PurpleWallBannerData), - BlueWallBanner(BlueWallBannerData), - BrownWallBanner(BrownWallBannerData), - GreenWallBanner(GreenWallBannerData), - RedWallBanner(RedWallBannerData), - BlackWallBanner(BlackWallBannerData), - RedSandstone, - ChiseledRedSandstone, - CutRedSandstone, - RedSandstoneStairs(RedSandstoneStairsData), - OakSlab(OakSlabData), - SpruceSlab(SpruceSlabData), - BirchSlab(BirchSlabData), - JungleSlab(JungleSlabData), - AcaciaSlab(AcaciaSlabData), - DarkOakSlab(DarkOakSlabData), - StoneSlab(StoneSlabData), - SandstoneSlab(SandstoneSlabData), - PetrifiedOakSlab(PetrifiedOakSlabData), - CobblestoneSlab(CobblestoneSlabData), - BrickSlab(BrickSlabData), - StoneBrickSlab(StoneBrickSlabData), - NetherBrickSlab(NetherBrickSlabData), - QuartzSlab(QuartzSlabData), - RedSandstoneSlab(RedSandstoneSlabData), - PurpurSlab(PurpurSlabData), - SmoothStone, - SmoothSandstone, - SmoothQuartz, - SmoothRedSandstone, - SpruceFenceGate(SpruceFenceGateData), - BirchFenceGate(BirchFenceGateData), - JungleFenceGate(JungleFenceGateData), - AcaciaFenceGate(AcaciaFenceGateData), - DarkOakFenceGate(DarkOakFenceGateData), - SpruceFence(SpruceFenceData), - BirchFence(BirchFenceData), - JungleFence(JungleFenceData), - AcaciaFence(AcaciaFenceData), - DarkOakFence(DarkOakFenceData), - SpruceDoor(SpruceDoorData), - BirchDoor(BirchDoorData), - JungleDoor(JungleDoorData), - AcaciaDoor(AcaciaDoorData), - DarkOakDoor(DarkOakDoorData), - EndRod(EndRodData), - ChorusPlant(ChorusPlantData), - ChorusFlower(ChorusFlowerData), - PurpurBlock, - PurpurPillar(PurpurPillarData), - PurpurStairs(PurpurStairsData), - EndStoneBricks, - Beetroots(BeetrootsData), - GrassPath, - EndGateway, - RepeatingCommandBlock(RepeatingCommandBlockData), - ChainCommandBlock(ChainCommandBlockData), - FrostedIce(FrostedIceData), - MagmaBlock, - NetherWartBlock, - RedNetherBricks, - BoneBlock(BoneBlockData), - StructureVoid, - Observer(ObserverData), - ShulkerBox(ShulkerBoxData), - WhiteShulkerBox(WhiteShulkerBoxData), - OrangeShulkerBox(OrangeShulkerBoxData), - MagentaShulkerBox(MagentaShulkerBoxData), - LightBlueShulkerBox(LightBlueShulkerBoxData), - YellowShulkerBox(YellowShulkerBoxData), - LimeShulkerBox(LimeShulkerBoxData), - PinkShulkerBox(PinkShulkerBoxData), - GrayShulkerBox(GrayShulkerBoxData), - LightGrayShulkerBox(LightGrayShulkerBoxData), - CyanShulkerBox(CyanShulkerBoxData), - PurpleShulkerBox(PurpleShulkerBoxData), - BlueShulkerBox(BlueShulkerBoxData), - BrownShulkerBox(BrownShulkerBoxData), - GreenShulkerBox(GreenShulkerBoxData), - RedShulkerBox(RedShulkerBoxData), - BlackShulkerBox(BlackShulkerBoxData), - WhiteGlazedTerracotta(WhiteGlazedTerracottaData), - OrangeGlazedTerracotta(OrangeGlazedTerracottaData), - MagentaGlazedTerracotta(MagentaGlazedTerracottaData), - LightBlueGlazedTerracotta(LightBlueGlazedTerracottaData), - YellowGlazedTerracotta(YellowGlazedTerracottaData), - LimeGlazedTerracotta(LimeGlazedTerracottaData), - PinkGlazedTerracotta(PinkGlazedTerracottaData), - GrayGlazedTerracotta(GrayGlazedTerracottaData), - LightGrayGlazedTerracotta(LightGrayGlazedTerracottaData), - CyanGlazedTerracotta(CyanGlazedTerracottaData), - PurpleGlazedTerracotta(PurpleGlazedTerracottaData), - BlueGlazedTerracotta(BlueGlazedTerracottaData), - BrownGlazedTerracotta(BrownGlazedTerracottaData), - GreenGlazedTerracotta(GreenGlazedTerracottaData), - RedGlazedTerracotta(RedGlazedTerracottaData), - BlackGlazedTerracotta(BlackGlazedTerracottaData), - WhiteConcrete, - OrangeConcrete, - MagentaConcrete, - LightBlueConcrete, - YellowConcrete, - LimeConcrete, - PinkConcrete, - GrayConcrete, - LightGrayConcrete, - CyanConcrete, - PurpleConcrete, - BlueConcrete, - BrownConcrete, - GreenConcrete, - RedConcrete, - BlackConcrete, - WhiteConcretePowder, - OrangeConcretePowder, - MagentaConcretePowder, - LightBlueConcretePowder, - YellowConcretePowder, - LimeConcretePowder, - PinkConcretePowder, - GrayConcretePowder, - LightGrayConcretePowder, - CyanConcretePowder, - PurpleConcretePowder, - BlueConcretePowder, - BrownConcretePowder, - GreenConcretePowder, - RedConcretePowder, - BlackConcretePowder, - Kelp(KelpData), - KelpPlant, - DriedKelpBlock, - TurtleEgg(TurtleEggData), - DeadTubeCoralBlock, - DeadBrainCoralBlock, - DeadBubbleCoralBlock, - DeadFireCoralBlock, - DeadHornCoralBlock, - TubeCoralBlock, - BrainCoralBlock, - BubbleCoralBlock, - FireCoralBlock, - HornCoralBlock, - DeadTubeCoral(DeadTubeCoralData), - DeadBrainCoral(DeadBrainCoralData), - DeadBubbleCoral(DeadBubbleCoralData), - DeadFireCoral(DeadFireCoralData), - DeadHornCoral(DeadHornCoralData), - TubeCoral(TubeCoralData), - BrainCoral(BrainCoralData), - BubbleCoral(BubbleCoralData), - FireCoral(FireCoralData), - HornCoral(HornCoralData), - DeadTubeCoralWallFan(DeadTubeCoralWallFanData), - DeadBrainCoralWallFan(DeadBrainCoralWallFanData), - DeadBubbleCoralWallFan(DeadBubbleCoralWallFanData), - DeadFireCoralWallFan(DeadFireCoralWallFanData), - DeadHornCoralWallFan(DeadHornCoralWallFanData), - TubeCoralWallFan(TubeCoralWallFanData), - BrainCoralWallFan(BrainCoralWallFanData), - BubbleCoralWallFan(BubbleCoralWallFanData), - FireCoralWallFan(FireCoralWallFanData), - HornCoralWallFan(HornCoralWallFanData), - DeadTubeCoralFan(DeadTubeCoralFanData), - DeadBrainCoralFan(DeadBrainCoralFanData), - DeadBubbleCoralFan(DeadBubbleCoralFanData), - DeadFireCoralFan(DeadFireCoralFanData), - DeadHornCoralFan(DeadHornCoralFanData), - TubeCoralFan(TubeCoralFanData), - BrainCoralFan(BrainCoralFanData), - BubbleCoralFan(BubbleCoralFanData), - FireCoralFan(FireCoralFanData), - HornCoralFan(HornCoralFanData), - SeaPickle(SeaPickleData), - BlueIce, - Conduit(ConduitData), - VoidAir, - CaveAir, - BubbleColumn(BubbleColumnData), - StructureBlock(StructureBlockData), -} -impl Block { - fn internal_type_id(&self) -> usize { - match self { - Block::Air => 0usize, - Block::Stone => 1usize, - Block::Granite => 2usize, - Block::PolishedGranite => 3usize, - Block::Diorite => 4usize, - Block::PolishedDiorite => 5usize, - Block::Andesite => 6usize, - Block::PolishedAndesite => 7usize, - Block::GrassBlock(_) => 8usize, - Block::Dirt => 9usize, - Block::CoarseDirt => 10usize, - Block::Podzol(_) => 11usize, - Block::Cobblestone => 12usize, - Block::OakPlanks => 13usize, - Block::SprucePlanks => 14usize, - Block::BirchPlanks => 15usize, - Block::JunglePlanks => 16usize, - Block::AcaciaPlanks => 17usize, - Block::DarkOakPlanks => 18usize, - Block::OakSapling(_) => 19usize, - Block::SpruceSapling(_) => 20usize, - Block::BirchSapling(_) => 21usize, - Block::JungleSapling(_) => 22usize, - Block::AcaciaSapling(_) => 23usize, - Block::DarkOakSapling(_) => 24usize, - Block::Bedrock => 25usize, - Block::Water(_) => 26usize, - Block::Lava(_) => 27usize, - Block::Sand => 28usize, - Block::RedSand => 29usize, - Block::Gravel => 30usize, - Block::GoldOre => 31usize, - Block::IronOre => 32usize, - Block::CoalOre => 33usize, - Block::OakLog(_) => 34usize, - Block::SpruceLog(_) => 35usize, - Block::BirchLog(_) => 36usize, - Block::JungleLog(_) => 37usize, - Block::AcaciaLog(_) => 38usize, - Block::DarkOakLog(_) => 39usize, - Block::StrippedSpruceLog(_) => 40usize, - Block::StrippedBirchLog(_) => 41usize, - Block::StrippedJungleLog(_) => 42usize, - Block::StrippedAcaciaLog(_) => 43usize, - Block::StrippedDarkOakLog(_) => 44usize, - Block::StrippedOakLog(_) => 45usize, - Block::OakWood(_) => 46usize, - Block::SpruceWood(_) => 47usize, - Block::BirchWood(_) => 48usize, - Block::JungleWood(_) => 49usize, - Block::AcaciaWood(_) => 50usize, - Block::DarkOakWood(_) => 51usize, - Block::StrippedOakWood(_) => 52usize, - Block::StrippedSpruceWood(_) => 53usize, - Block::StrippedBirchWood(_) => 54usize, - Block::StrippedJungleWood(_) => 55usize, - Block::StrippedAcaciaWood(_) => 56usize, - Block::StrippedDarkOakWood(_) => 57usize, - Block::OakLeaves(_) => 58usize, - Block::SpruceLeaves(_) => 59usize, - Block::BirchLeaves(_) => 60usize, - Block::JungleLeaves(_) => 61usize, - Block::AcaciaLeaves(_) => 62usize, - Block::DarkOakLeaves(_) => 63usize, - Block::Sponge => 64usize, - Block::WetSponge => 65usize, - Block::Glass => 66usize, - Block::LapisOre => 67usize, - Block::LapisBlock => 68usize, - Block::Dispenser(_) => 69usize, - Block::Sandstone => 70usize, - Block::ChiseledSandstone => 71usize, - Block::CutSandstone => 72usize, - Block::NoteBlock(_) => 73usize, - Block::WhiteBed(_) => 74usize, - Block::OrangeBed(_) => 75usize, - Block::MagentaBed(_) => 76usize, - Block::LightBlueBed(_) => 77usize, - Block::YellowBed(_) => 78usize, - Block::LimeBed(_) => 79usize, - Block::PinkBed(_) => 80usize, - Block::GrayBed(_) => 81usize, - Block::LightGrayBed(_) => 82usize, - Block::CyanBed(_) => 83usize, - Block::PurpleBed(_) => 84usize, - Block::BlueBed(_) => 85usize, - Block::BrownBed(_) => 86usize, - Block::GreenBed(_) => 87usize, - Block::RedBed(_) => 88usize, - Block::BlackBed(_) => 89usize, - Block::PoweredRail(_) => 90usize, - Block::DetectorRail(_) => 91usize, - Block::StickyPiston(_) => 92usize, - Block::Cobweb => 93usize, - Block::Grass => 94usize, - Block::Fern => 95usize, - Block::DeadBush => 96usize, - Block::Seagrass => 97usize, - Block::TallSeagrass(_) => 98usize, - Block::Piston(_) => 99usize, - Block::PistonHead(_) => 100usize, - Block::WhiteWool => 101usize, - Block::OrangeWool => 102usize, - Block::MagentaWool => 103usize, - Block::LightBlueWool => 104usize, - Block::YellowWool => 105usize, - Block::LimeWool => 106usize, - Block::PinkWool => 107usize, - Block::GrayWool => 108usize, - Block::LightGrayWool => 109usize, - Block::CyanWool => 110usize, - Block::PurpleWool => 111usize, - Block::BlueWool => 112usize, - Block::BrownWool => 113usize, - Block::GreenWool => 114usize, - Block::RedWool => 115usize, - Block::BlackWool => 116usize, - Block::MovingPiston(_) => 117usize, - Block::Dandelion => 118usize, - Block::Poppy => 119usize, - Block::BlueOrchid => 120usize, - Block::Allium => 121usize, - Block::AzureBluet => 122usize, - Block::RedTulip => 123usize, - Block::OrangeTulip => 124usize, - Block::WhiteTulip => 125usize, - Block::PinkTulip => 126usize, - Block::OxeyeDaisy => 127usize, - Block::BrownMushroom => 128usize, - Block::RedMushroom => 129usize, - Block::GoldBlock => 130usize, - Block::IronBlock => 131usize, - Block::Bricks => 132usize, - Block::Tnt(_) => 133usize, - Block::Bookshelf => 134usize, - Block::MossyCobblestone => 135usize, - Block::Obsidian => 136usize, - Block::Torch => 137usize, - Block::WallTorch(_) => 138usize, - Block::Fire(_) => 139usize, - Block::Spawner => 140usize, - Block::OakStairs(_) => 141usize, - Block::Chest(_) => 142usize, - Block::RedstoneWire(_) => 143usize, - Block::DiamondOre => 144usize, - Block::DiamondBlock => 145usize, - Block::CraftingTable => 146usize, - Block::Wheat(_) => 147usize, - Block::Farmland(_) => 148usize, - Block::Furnace(_) => 149usize, - Block::Sign(_) => 150usize, - Block::OakDoor(_) => 151usize, - Block::Ladder(_) => 152usize, - Block::Rail(_) => 153usize, - Block::CobblestoneStairs(_) => 154usize, - Block::WallSign(_) => 155usize, - Block::Lever(_) => 156usize, - Block::StonePressurePlate(_) => 157usize, - Block::IronDoor(_) => 158usize, - Block::OakPressurePlate(_) => 159usize, - Block::SprucePressurePlate(_) => 160usize, - Block::BirchPressurePlate(_) => 161usize, - Block::JunglePressurePlate(_) => 162usize, - Block::AcaciaPressurePlate(_) => 163usize, - Block::DarkOakPressurePlate(_) => 164usize, - Block::RedstoneOre(_) => 165usize, - Block::RedstoneTorch(_) => 166usize, - Block::RedstoneWallTorch(_) => 167usize, - Block::StoneButton(_) => 168usize, - Block::Snow(_) => 169usize, - Block::Ice => 170usize, - Block::SnowBlock => 171usize, - Block::Cactus(_) => 172usize, - Block::Clay => 173usize, - Block::SugarCane(_) => 174usize, - Block::Jukebox(_) => 175usize, - Block::OakFence(_) => 176usize, - Block::Pumpkin => 177usize, - Block::Netherrack => 178usize, - Block::SoulSand => 179usize, - Block::Glowstone => 180usize, - Block::NetherPortal(_) => 181usize, - Block::CarvedPumpkin(_) => 182usize, - Block::JackOLantern(_) => 183usize, - Block::Cake(_) => 184usize, - Block::Repeater(_) => 185usize, - Block::WhiteStainedGlass => 186usize, - Block::OrangeStainedGlass => 187usize, - Block::MagentaStainedGlass => 188usize, - Block::LightBlueStainedGlass => 189usize, - Block::YellowStainedGlass => 190usize, - Block::LimeStainedGlass => 191usize, - Block::PinkStainedGlass => 192usize, - Block::GrayStainedGlass => 193usize, - Block::LightGrayStainedGlass => 194usize, - Block::CyanStainedGlass => 195usize, - Block::PurpleStainedGlass => 196usize, - Block::BlueStainedGlass => 197usize, - Block::BrownStainedGlass => 198usize, - Block::GreenStainedGlass => 199usize, - Block::RedStainedGlass => 200usize, - Block::BlackStainedGlass => 201usize, - Block::OakTrapdoor(_) => 202usize, - Block::SpruceTrapdoor(_) => 203usize, - Block::BirchTrapdoor(_) => 204usize, - Block::JungleTrapdoor(_) => 205usize, - Block::AcaciaTrapdoor(_) => 206usize, - Block::DarkOakTrapdoor(_) => 207usize, - Block::InfestedStone => 208usize, - Block::InfestedCobblestone => 209usize, - Block::InfestedStoneBricks => 210usize, - Block::InfestedMossyStoneBricks => 211usize, - Block::InfestedCrackedStoneBricks => 212usize, - Block::InfestedChiseledStoneBricks => 213usize, - Block::StoneBricks => 214usize, - Block::MossyStoneBricks => 215usize, - Block::CrackedStoneBricks => 216usize, - Block::ChiseledStoneBricks => 217usize, - Block::BrownMushroomBlock(_) => 218usize, - Block::RedMushroomBlock(_) => 219usize, - Block::MushroomStem(_) => 220usize, - Block::IronBars(_) => 221usize, - Block::GlassPane(_) => 222usize, - Block::Melon => 223usize, - Block::AttachedPumpkinStem(_) => 224usize, - Block::AttachedMelonStem(_) => 225usize, - Block::PumpkinStem(_) => 226usize, - Block::MelonStem(_) => 227usize, - Block::Vine(_) => 228usize, - Block::OakFenceGate(_) => 229usize, - Block::BrickStairs(_) => 230usize, - Block::StoneBrickStairs(_) => 231usize, - Block::Mycelium(_) => 232usize, - Block::LilyPad => 233usize, - Block::NetherBricks => 234usize, - Block::NetherBrickFence(_) => 235usize, - Block::NetherBrickStairs(_) => 236usize, - Block::NetherWart(_) => 237usize, - Block::EnchantingTable => 238usize, - Block::BrewingStand(_) => 239usize, - Block::Cauldron(_) => 240usize, - Block::EndPortal => 241usize, - Block::EndPortalFrame(_) => 242usize, - Block::EndStone => 243usize, - Block::DragonEgg => 244usize, - Block::RedstoneLamp(_) => 245usize, - Block::Cocoa(_) => 246usize, - Block::SandstoneStairs(_) => 247usize, - Block::EmeraldOre => 248usize, - Block::EnderChest(_) => 249usize, - Block::TripwireHook(_) => 250usize, - Block::Tripwire(_) => 251usize, - Block::EmeraldBlock => 252usize, - Block::SpruceStairs(_) => 253usize, - Block::BirchStairs(_) => 254usize, - Block::JungleStairs(_) => 255usize, - Block::CommandBlock(_) => 256usize, - Block::Beacon => 257usize, - Block::CobblestoneWall(_) => 258usize, - Block::MossyCobblestoneWall(_) => 259usize, - Block::FlowerPot => 260usize, - Block::PottedOakSapling => 261usize, - Block::PottedSpruceSapling => 262usize, - Block::PottedBirchSapling => 263usize, - Block::PottedJungleSapling => 264usize, - Block::PottedAcaciaSapling => 265usize, - Block::PottedDarkOakSapling => 266usize, - Block::PottedFern => 267usize, - Block::PottedDandelion => 268usize, - Block::PottedPoppy => 269usize, - Block::PottedBlueOrchid => 270usize, - Block::PottedAllium => 271usize, - Block::PottedAzureBluet => 272usize, - Block::PottedRedTulip => 273usize, - Block::PottedOrangeTulip => 274usize, - Block::PottedWhiteTulip => 275usize, - Block::PottedPinkTulip => 276usize, - Block::PottedOxeyeDaisy => 277usize, - Block::PottedRedMushroom => 278usize, - Block::PottedBrownMushroom => 279usize, - Block::PottedDeadBush => 280usize, - Block::PottedCactus => 281usize, - Block::Carrots(_) => 282usize, - Block::Potatoes(_) => 283usize, - Block::OakButton(_) => 284usize, - Block::SpruceButton(_) => 285usize, - Block::BirchButton(_) => 286usize, - Block::JungleButton(_) => 287usize, - Block::AcaciaButton(_) => 288usize, - Block::DarkOakButton(_) => 289usize, - Block::SkeletonWallSkull(_) => 290usize, - Block::SkeletonSkull(_) => 291usize, - Block::WitherSkeletonWallSkull(_) => 292usize, - Block::WitherSkeletonSkull(_) => 293usize, - Block::ZombieWallHead(_) => 294usize, - Block::ZombieHead(_) => 295usize, - Block::PlayerWallHead(_) => 296usize, - Block::PlayerHead(_) => 297usize, - Block::CreeperWallHead(_) => 298usize, - Block::CreeperHead(_) => 299usize, - Block::DragonWallHead(_) => 300usize, - Block::DragonHead(_) => 301usize, - Block::Anvil(_) => 302usize, - Block::ChippedAnvil(_) => 303usize, - Block::DamagedAnvil(_) => 304usize, - Block::TrappedChest(_) => 305usize, - Block::LightWeightedPressurePlate(_) => 306usize, - Block::HeavyWeightedPressurePlate(_) => 307usize, - Block::Comparator(_) => 308usize, - Block::DaylightDetector(_) => 309usize, - Block::RedstoneBlock => 310usize, - Block::NetherQuartzOre => 311usize, - Block::Hopper(_) => 312usize, - Block::QuartzBlock => 313usize, - Block::ChiseledQuartzBlock => 314usize, - Block::QuartzPillar(_) => 315usize, - Block::QuartzStairs(_) => 316usize, - Block::ActivatorRail(_) => 317usize, - Block::Dropper(_) => 318usize, - Block::WhiteTerracotta => 319usize, - Block::OrangeTerracotta => 320usize, - Block::MagentaTerracotta => 321usize, - Block::LightBlueTerracotta => 322usize, - Block::YellowTerracotta => 323usize, - Block::LimeTerracotta => 324usize, - Block::PinkTerracotta => 325usize, - Block::GrayTerracotta => 326usize, - Block::LightGrayTerracotta => 327usize, - Block::CyanTerracotta => 328usize, - Block::PurpleTerracotta => 329usize, - Block::BlueTerracotta => 330usize, - Block::BrownTerracotta => 331usize, - Block::GreenTerracotta => 332usize, - Block::RedTerracotta => 333usize, - Block::BlackTerracotta => 334usize, - Block::WhiteStainedGlassPane(_) => 335usize, - Block::OrangeStainedGlassPane(_) => 336usize, - Block::MagentaStainedGlassPane(_) => 337usize, - Block::LightBlueStainedGlassPane(_) => 338usize, - Block::YellowStainedGlassPane(_) => 339usize, - Block::LimeStainedGlassPane(_) => 340usize, - Block::PinkStainedGlassPane(_) => 341usize, - Block::GrayStainedGlassPane(_) => 342usize, - Block::LightGrayStainedGlassPane(_) => 343usize, - Block::CyanStainedGlassPane(_) => 344usize, - Block::PurpleStainedGlassPane(_) => 345usize, - Block::BlueStainedGlassPane(_) => 346usize, - Block::BrownStainedGlassPane(_) => 347usize, - Block::GreenStainedGlassPane(_) => 348usize, - Block::RedStainedGlassPane(_) => 349usize, - Block::BlackStainedGlassPane(_) => 350usize, - Block::AcaciaStairs(_) => 351usize, - Block::DarkOakStairs(_) => 352usize, - Block::SlimeBlock => 353usize, - Block::Barrier => 354usize, - Block::IronTrapdoor(_) => 355usize, - Block::Prismarine => 356usize, - Block::PrismarineBricks => 357usize, - Block::DarkPrismarine => 358usize, - Block::PrismarineStairs(_) => 359usize, - Block::PrismarineBrickStairs(_) => 360usize, - Block::DarkPrismarineStairs(_) => 361usize, - Block::PrismarineSlab(_) => 362usize, - Block::PrismarineBrickSlab(_) => 363usize, - Block::DarkPrismarineSlab(_) => 364usize, - Block::SeaLantern => 365usize, - Block::HayBlock(_) => 366usize, - Block::WhiteCarpet => 367usize, - Block::OrangeCarpet => 368usize, - Block::MagentaCarpet => 369usize, - Block::LightBlueCarpet => 370usize, - Block::YellowCarpet => 371usize, - Block::LimeCarpet => 372usize, - Block::PinkCarpet => 373usize, - Block::GrayCarpet => 374usize, - Block::LightGrayCarpet => 375usize, - Block::CyanCarpet => 376usize, - Block::PurpleCarpet => 377usize, - Block::BlueCarpet => 378usize, - Block::BrownCarpet => 379usize, - Block::GreenCarpet => 380usize, - Block::RedCarpet => 381usize, - Block::BlackCarpet => 382usize, - Block::Terracotta => 383usize, - Block::CoalBlock => 384usize, - Block::PackedIce => 385usize, - Block::Sunflower(_) => 386usize, - Block::Lilac(_) => 387usize, - Block::RoseBush(_) => 388usize, - Block::Peony(_) => 389usize, - Block::TallGrass(_) => 390usize, - Block::LargeFern(_) => 391usize, - Block::WhiteBanner(_) => 392usize, - Block::OrangeBanner(_) => 393usize, - Block::MagentaBanner(_) => 394usize, - Block::LightBlueBanner(_) => 395usize, - Block::YellowBanner(_) => 396usize, - Block::LimeBanner(_) => 397usize, - Block::PinkBanner(_) => 398usize, - Block::GrayBanner(_) => 399usize, - Block::LightGrayBanner(_) => 400usize, - Block::CyanBanner(_) => 401usize, - Block::PurpleBanner(_) => 402usize, - Block::BlueBanner(_) => 403usize, - Block::BrownBanner(_) => 404usize, - Block::GreenBanner(_) => 405usize, - Block::RedBanner(_) => 406usize, - Block::BlackBanner(_) => 407usize, - Block::WhiteWallBanner(_) => 408usize, - Block::OrangeWallBanner(_) => 409usize, - Block::MagentaWallBanner(_) => 410usize, - Block::LightBlueWallBanner(_) => 411usize, - Block::YellowWallBanner(_) => 412usize, - Block::LimeWallBanner(_) => 413usize, - Block::PinkWallBanner(_) => 414usize, - Block::GrayWallBanner(_) => 415usize, - Block::LightGrayWallBanner(_) => 416usize, - Block::CyanWallBanner(_) => 417usize, - Block::PurpleWallBanner(_) => 418usize, - Block::BlueWallBanner(_) => 419usize, - Block::BrownWallBanner(_) => 420usize, - Block::GreenWallBanner(_) => 421usize, - Block::RedWallBanner(_) => 422usize, - Block::BlackWallBanner(_) => 423usize, - Block::RedSandstone => 424usize, - Block::ChiseledRedSandstone => 425usize, - Block::CutRedSandstone => 426usize, - Block::RedSandstoneStairs(_) => 427usize, - Block::OakSlab(_) => 428usize, - Block::SpruceSlab(_) => 429usize, - Block::BirchSlab(_) => 430usize, - Block::JungleSlab(_) => 431usize, - Block::AcaciaSlab(_) => 432usize, - Block::DarkOakSlab(_) => 433usize, - Block::StoneSlab(_) => 434usize, - Block::SandstoneSlab(_) => 435usize, - Block::PetrifiedOakSlab(_) => 436usize, - Block::CobblestoneSlab(_) => 437usize, - Block::BrickSlab(_) => 438usize, - Block::StoneBrickSlab(_) => 439usize, - Block::NetherBrickSlab(_) => 440usize, - Block::QuartzSlab(_) => 441usize, - Block::RedSandstoneSlab(_) => 442usize, - Block::PurpurSlab(_) => 443usize, - Block::SmoothStone => 444usize, - Block::SmoothSandstone => 445usize, - Block::SmoothQuartz => 446usize, - Block::SmoothRedSandstone => 447usize, - Block::SpruceFenceGate(_) => 448usize, - Block::BirchFenceGate(_) => 449usize, - Block::JungleFenceGate(_) => 450usize, - Block::AcaciaFenceGate(_) => 451usize, - Block::DarkOakFenceGate(_) => 452usize, - Block::SpruceFence(_) => 453usize, - Block::BirchFence(_) => 454usize, - Block::JungleFence(_) => 455usize, - Block::AcaciaFence(_) => 456usize, - Block::DarkOakFence(_) => 457usize, - Block::SpruceDoor(_) => 458usize, - Block::BirchDoor(_) => 459usize, - Block::JungleDoor(_) => 460usize, - Block::AcaciaDoor(_) => 461usize, - Block::DarkOakDoor(_) => 462usize, - Block::EndRod(_) => 463usize, - Block::ChorusPlant(_) => 464usize, - Block::ChorusFlower(_) => 465usize, - Block::PurpurBlock => 466usize, - Block::PurpurPillar(_) => 467usize, - Block::PurpurStairs(_) => 468usize, - Block::EndStoneBricks => 469usize, - Block::Beetroots(_) => 470usize, - Block::GrassPath => 471usize, - Block::EndGateway => 472usize, - Block::RepeatingCommandBlock(_) => 473usize, - Block::ChainCommandBlock(_) => 474usize, - Block::FrostedIce(_) => 475usize, - Block::MagmaBlock => 476usize, - Block::NetherWartBlock => 477usize, - Block::RedNetherBricks => 478usize, - Block::BoneBlock(_) => 479usize, - Block::StructureVoid => 480usize, - Block::Observer(_) => 481usize, - Block::ShulkerBox(_) => 482usize, - Block::WhiteShulkerBox(_) => 483usize, - Block::OrangeShulkerBox(_) => 484usize, - Block::MagentaShulkerBox(_) => 485usize, - Block::LightBlueShulkerBox(_) => 486usize, - Block::YellowShulkerBox(_) => 487usize, - Block::LimeShulkerBox(_) => 488usize, - Block::PinkShulkerBox(_) => 489usize, - Block::GrayShulkerBox(_) => 490usize, - Block::LightGrayShulkerBox(_) => 491usize, - Block::CyanShulkerBox(_) => 492usize, - Block::PurpleShulkerBox(_) => 493usize, - Block::BlueShulkerBox(_) => 494usize, - Block::BrownShulkerBox(_) => 495usize, - Block::GreenShulkerBox(_) => 496usize, - Block::RedShulkerBox(_) => 497usize, - Block::BlackShulkerBox(_) => 498usize, - Block::WhiteGlazedTerracotta(_) => 499usize, - Block::OrangeGlazedTerracotta(_) => 500usize, - Block::MagentaGlazedTerracotta(_) => 501usize, - Block::LightBlueGlazedTerracotta(_) => 502usize, - Block::YellowGlazedTerracotta(_) => 503usize, - Block::LimeGlazedTerracotta(_) => 504usize, - Block::PinkGlazedTerracotta(_) => 505usize, - Block::GrayGlazedTerracotta(_) => 506usize, - Block::LightGrayGlazedTerracotta(_) => 507usize, - Block::CyanGlazedTerracotta(_) => 508usize, - Block::PurpleGlazedTerracotta(_) => 509usize, - Block::BlueGlazedTerracotta(_) => 510usize, - Block::BrownGlazedTerracotta(_) => 511usize, - Block::GreenGlazedTerracotta(_) => 512usize, - Block::RedGlazedTerracotta(_) => 513usize, - Block::BlackGlazedTerracotta(_) => 514usize, - Block::WhiteConcrete => 515usize, - Block::OrangeConcrete => 516usize, - Block::MagentaConcrete => 517usize, - Block::LightBlueConcrete => 518usize, - Block::YellowConcrete => 519usize, - Block::LimeConcrete => 520usize, - Block::PinkConcrete => 521usize, - Block::GrayConcrete => 522usize, - Block::LightGrayConcrete => 523usize, - Block::CyanConcrete => 524usize, - Block::PurpleConcrete => 525usize, - Block::BlueConcrete => 526usize, - Block::BrownConcrete => 527usize, - Block::GreenConcrete => 528usize, - Block::RedConcrete => 529usize, - Block::BlackConcrete => 530usize, - Block::WhiteConcretePowder => 531usize, - Block::OrangeConcretePowder => 532usize, - Block::MagentaConcretePowder => 533usize, - Block::LightBlueConcretePowder => 534usize, - Block::YellowConcretePowder => 535usize, - Block::LimeConcretePowder => 536usize, - Block::PinkConcretePowder => 537usize, - Block::GrayConcretePowder => 538usize, - Block::LightGrayConcretePowder => 539usize, - Block::CyanConcretePowder => 540usize, - Block::PurpleConcretePowder => 541usize, - Block::BlueConcretePowder => 542usize, - Block::BrownConcretePowder => 543usize, - Block::GreenConcretePowder => 544usize, - Block::RedConcretePowder => 545usize, - Block::BlackConcretePowder => 546usize, - Block::Kelp(_) => 547usize, - Block::KelpPlant => 548usize, - Block::DriedKelpBlock => 549usize, - Block::TurtleEgg(_) => 550usize, - Block::DeadTubeCoralBlock => 551usize, - Block::DeadBrainCoralBlock => 552usize, - Block::DeadBubbleCoralBlock => 553usize, - Block::DeadFireCoralBlock => 554usize, - Block::DeadHornCoralBlock => 555usize, - Block::TubeCoralBlock => 556usize, - Block::BrainCoralBlock => 557usize, - Block::BubbleCoralBlock => 558usize, - Block::FireCoralBlock => 559usize, - Block::HornCoralBlock => 560usize, - Block::DeadTubeCoral(_) => 561usize, - Block::DeadBrainCoral(_) => 562usize, - Block::DeadBubbleCoral(_) => 563usize, - Block::DeadFireCoral(_) => 564usize, - Block::DeadHornCoral(_) => 565usize, - Block::TubeCoral(_) => 566usize, - Block::BrainCoral(_) => 567usize, - Block::BubbleCoral(_) => 568usize, - Block::FireCoral(_) => 569usize, - Block::HornCoral(_) => 570usize, - Block::DeadTubeCoralWallFan(_) => 571usize, - Block::DeadBrainCoralWallFan(_) => 572usize, - Block::DeadBubbleCoralWallFan(_) => 573usize, - Block::DeadFireCoralWallFan(_) => 574usize, - Block::DeadHornCoralWallFan(_) => 575usize, - Block::TubeCoralWallFan(_) => 576usize, - Block::BrainCoralWallFan(_) => 577usize, - Block::BubbleCoralWallFan(_) => 578usize, - Block::FireCoralWallFan(_) => 579usize, - Block::HornCoralWallFan(_) => 580usize, - Block::DeadTubeCoralFan(_) => 581usize, - Block::DeadBrainCoralFan(_) => 582usize, - Block::DeadBubbleCoralFan(_) => 583usize, - Block::DeadFireCoralFan(_) => 584usize, - Block::DeadHornCoralFan(_) => 585usize, - Block::TubeCoralFan(_) => 586usize, - Block::BrainCoralFan(_) => 587usize, - Block::BubbleCoralFan(_) => 588usize, - Block::FireCoralFan(_) => 589usize, - Block::HornCoralFan(_) => 590usize, - Block::SeaPickle(_) => 591usize, - Block::BlueIce => 592usize, - Block::Conduit(_) => 593usize, - Block::VoidAir => 594usize, - Block::CaveAir => 595usize, - Block::BubbleColumn(_) => 596usize, - Block::StructureBlock(_) => 597usize, - } - } - fn internal_id_data_offset(&self) -> usize { - match self { - Block::Air => 0, - Block::Stone => 0, - Block::Granite => 0, - Block::PolishedGranite => 0, - Block::Diorite => 0, - Block::PolishedDiorite => 0, - Block::Andesite => 0, - Block::PolishedAndesite => 0, - Block::GrassBlock(data) => data.value(), - Block::Dirt => 0, - Block::CoarseDirt => 0, - Block::Podzol(data) => data.value(), - Block::Cobblestone => 0, - Block::OakPlanks => 0, - Block::SprucePlanks => 0, - Block::BirchPlanks => 0, - Block::JunglePlanks => 0, - Block::AcaciaPlanks => 0, - Block::DarkOakPlanks => 0, - Block::OakSapling(data) => data.value(), - Block::SpruceSapling(data) => data.value(), - Block::BirchSapling(data) => data.value(), - Block::JungleSapling(data) => data.value(), - Block::AcaciaSapling(data) => data.value(), - Block::DarkOakSapling(data) => data.value(), - Block::Bedrock => 0, - Block::Water(data) => data.value(), - Block::Lava(data) => data.value(), - Block::Sand => 0, - Block::RedSand => 0, - Block::Gravel => 0, - Block::GoldOre => 0, - Block::IronOre => 0, - Block::CoalOre => 0, - Block::OakLog(data) => data.value(), - Block::SpruceLog(data) => data.value(), - Block::BirchLog(data) => data.value(), - Block::JungleLog(data) => data.value(), - Block::AcaciaLog(data) => data.value(), - Block::DarkOakLog(data) => data.value(), - Block::StrippedSpruceLog(data) => data.value(), - Block::StrippedBirchLog(data) => data.value(), - Block::StrippedJungleLog(data) => data.value(), - Block::StrippedAcaciaLog(data) => data.value(), - Block::StrippedDarkOakLog(data) => data.value(), - Block::StrippedOakLog(data) => data.value(), - Block::OakWood(data) => data.value(), - Block::SpruceWood(data) => data.value(), - Block::BirchWood(data) => data.value(), - Block::JungleWood(data) => data.value(), - Block::AcaciaWood(data) => data.value(), - Block::DarkOakWood(data) => data.value(), - Block::StrippedOakWood(data) => data.value(), - Block::StrippedSpruceWood(data) => data.value(), - Block::StrippedBirchWood(data) => data.value(), - Block::StrippedJungleWood(data) => data.value(), - Block::StrippedAcaciaWood(data) => data.value(), - Block::StrippedDarkOakWood(data) => data.value(), - Block::OakLeaves(data) => data.value(), - Block::SpruceLeaves(data) => data.value(), - Block::BirchLeaves(data) => data.value(), - Block::JungleLeaves(data) => data.value(), - Block::AcaciaLeaves(data) => data.value(), - Block::DarkOakLeaves(data) => data.value(), - Block::Sponge => 0, - Block::WetSponge => 0, - Block::Glass => 0, - Block::LapisOre => 0, - Block::LapisBlock => 0, - Block::Dispenser(data) => data.value(), - Block::Sandstone => 0, - Block::ChiseledSandstone => 0, - Block::CutSandstone => 0, - Block::NoteBlock(data) => data.value(), - Block::WhiteBed(data) => data.value(), - Block::OrangeBed(data) => data.value(), - Block::MagentaBed(data) => data.value(), - Block::LightBlueBed(data) => data.value(), - Block::YellowBed(data) => data.value(), - Block::LimeBed(data) => data.value(), - Block::PinkBed(data) => data.value(), - Block::GrayBed(data) => data.value(), - Block::LightGrayBed(data) => data.value(), - Block::CyanBed(data) => data.value(), - Block::PurpleBed(data) => data.value(), - Block::BlueBed(data) => data.value(), - Block::BrownBed(data) => data.value(), - Block::GreenBed(data) => data.value(), - Block::RedBed(data) => data.value(), - Block::BlackBed(data) => data.value(), - Block::PoweredRail(data) => data.value(), - Block::DetectorRail(data) => data.value(), - Block::StickyPiston(data) => data.value(), - Block::Cobweb => 0, - Block::Grass => 0, - Block::Fern => 0, - Block::DeadBush => 0, - Block::Seagrass => 0, - Block::TallSeagrass(data) => data.value(), - Block::Piston(data) => data.value(), - Block::PistonHead(data) => data.value(), - Block::WhiteWool => 0, - Block::OrangeWool => 0, - Block::MagentaWool => 0, - Block::LightBlueWool => 0, - Block::YellowWool => 0, - Block::LimeWool => 0, - Block::PinkWool => 0, - Block::GrayWool => 0, - Block::LightGrayWool => 0, - Block::CyanWool => 0, - Block::PurpleWool => 0, - Block::BlueWool => 0, - Block::BrownWool => 0, - Block::GreenWool => 0, - Block::RedWool => 0, - Block::BlackWool => 0, - Block::MovingPiston(data) => data.value(), - Block::Dandelion => 0, - Block::Poppy => 0, - Block::BlueOrchid => 0, - Block::Allium => 0, - Block::AzureBluet => 0, - Block::RedTulip => 0, - Block::OrangeTulip => 0, - Block::WhiteTulip => 0, - Block::PinkTulip => 0, - Block::OxeyeDaisy => 0, - Block::BrownMushroom => 0, - Block::RedMushroom => 0, - Block::GoldBlock => 0, - Block::IronBlock => 0, - Block::Bricks => 0, - Block::Tnt(data) => data.value(), - Block::Bookshelf => 0, - Block::MossyCobblestone => 0, - Block::Obsidian => 0, - Block::Torch => 0, - Block::WallTorch(data) => data.value(), - Block::Fire(data) => data.value(), - Block::Spawner => 0, - Block::OakStairs(data) => data.value(), - Block::Chest(data) => data.value(), - Block::RedstoneWire(data) => data.value(), - Block::DiamondOre => 0, - Block::DiamondBlock => 0, - Block::CraftingTable => 0, - Block::Wheat(data) => data.value(), - Block::Farmland(data) => data.value(), - Block::Furnace(data) => data.value(), - Block::Sign(data) => data.value(), - Block::OakDoor(data) => data.value(), - Block::Ladder(data) => data.value(), - Block::Rail(data) => data.value(), - Block::CobblestoneStairs(data) => data.value(), - Block::WallSign(data) => data.value(), - Block::Lever(data) => data.value(), - Block::StonePressurePlate(data) => data.value(), - Block::IronDoor(data) => data.value(), - Block::OakPressurePlate(data) => data.value(), - Block::SprucePressurePlate(data) => data.value(), - Block::BirchPressurePlate(data) => data.value(), - Block::JunglePressurePlate(data) => data.value(), - Block::AcaciaPressurePlate(data) => data.value(), - Block::DarkOakPressurePlate(data) => data.value(), - Block::RedstoneOre(data) => data.value(), - Block::RedstoneTorch(data) => data.value(), - Block::RedstoneWallTorch(data) => data.value(), - Block::StoneButton(data) => data.value(), - Block::Snow(data) => data.value(), - Block::Ice => 0, - Block::SnowBlock => 0, - Block::Cactus(data) => data.value(), - Block::Clay => 0, - Block::SugarCane(data) => data.value(), - Block::Jukebox(data) => data.value(), - Block::OakFence(data) => data.value(), - Block::Pumpkin => 0, - Block::Netherrack => 0, - Block::SoulSand => 0, - Block::Glowstone => 0, - Block::NetherPortal(data) => data.value(), - Block::CarvedPumpkin(data) => data.value(), - Block::JackOLantern(data) => data.value(), - Block::Cake(data) => data.value(), - Block::Repeater(data) => data.value(), - Block::WhiteStainedGlass => 0, - Block::OrangeStainedGlass => 0, - Block::MagentaStainedGlass => 0, - Block::LightBlueStainedGlass => 0, - Block::YellowStainedGlass => 0, - Block::LimeStainedGlass => 0, - Block::PinkStainedGlass => 0, - Block::GrayStainedGlass => 0, - Block::LightGrayStainedGlass => 0, - Block::CyanStainedGlass => 0, - Block::PurpleStainedGlass => 0, - Block::BlueStainedGlass => 0, - Block::BrownStainedGlass => 0, - Block::GreenStainedGlass => 0, - Block::RedStainedGlass => 0, - Block::BlackStainedGlass => 0, - Block::OakTrapdoor(data) => data.value(), - Block::SpruceTrapdoor(data) => data.value(), - Block::BirchTrapdoor(data) => data.value(), - Block::JungleTrapdoor(data) => data.value(), - Block::AcaciaTrapdoor(data) => data.value(), - Block::DarkOakTrapdoor(data) => data.value(), - Block::InfestedStone => 0, - Block::InfestedCobblestone => 0, - Block::InfestedStoneBricks => 0, - Block::InfestedMossyStoneBricks => 0, - Block::InfestedCrackedStoneBricks => 0, - Block::InfestedChiseledStoneBricks => 0, - Block::StoneBricks => 0, - Block::MossyStoneBricks => 0, - Block::CrackedStoneBricks => 0, - Block::ChiseledStoneBricks => 0, - Block::BrownMushroomBlock(data) => data.value(), - Block::RedMushroomBlock(data) => data.value(), - Block::MushroomStem(data) => data.value(), - Block::IronBars(data) => data.value(), - Block::GlassPane(data) => data.value(), - Block::Melon => 0, - Block::AttachedPumpkinStem(data) => data.value(), - Block::AttachedMelonStem(data) => data.value(), - Block::PumpkinStem(data) => data.value(), - Block::MelonStem(data) => data.value(), - Block::Vine(data) => data.value(), - Block::OakFenceGate(data) => data.value(), - Block::BrickStairs(data) => data.value(), - Block::StoneBrickStairs(data) => data.value(), - Block::Mycelium(data) => data.value(), - Block::LilyPad => 0, - Block::NetherBricks => 0, - Block::NetherBrickFence(data) => data.value(), - Block::NetherBrickStairs(data) => data.value(), - Block::NetherWart(data) => data.value(), - Block::EnchantingTable => 0, - Block::BrewingStand(data) => data.value(), - Block::Cauldron(data) => data.value(), - Block::EndPortal => 0, - Block::EndPortalFrame(data) => data.value(), - Block::EndStone => 0, - Block::DragonEgg => 0, - Block::RedstoneLamp(data) => data.value(), - Block::Cocoa(data) => data.value(), - Block::SandstoneStairs(data) => data.value(), - Block::EmeraldOre => 0, - Block::EnderChest(data) => data.value(), - Block::TripwireHook(data) => data.value(), - Block::Tripwire(data) => data.value(), - Block::EmeraldBlock => 0, - Block::SpruceStairs(data) => data.value(), - Block::BirchStairs(data) => data.value(), - Block::JungleStairs(data) => data.value(), - Block::CommandBlock(data) => data.value(), - Block::Beacon => 0, - Block::CobblestoneWall(data) => data.value(), - Block::MossyCobblestoneWall(data) => data.value(), - Block::FlowerPot => 0, - Block::PottedOakSapling => 0, - Block::PottedSpruceSapling => 0, - Block::PottedBirchSapling => 0, - Block::PottedJungleSapling => 0, - Block::PottedAcaciaSapling => 0, - Block::PottedDarkOakSapling => 0, - Block::PottedFern => 0, - Block::PottedDandelion => 0, - Block::PottedPoppy => 0, - Block::PottedBlueOrchid => 0, - Block::PottedAllium => 0, - Block::PottedAzureBluet => 0, - Block::PottedRedTulip => 0, - Block::PottedOrangeTulip => 0, - Block::PottedWhiteTulip => 0, - Block::PottedPinkTulip => 0, - Block::PottedOxeyeDaisy => 0, - Block::PottedRedMushroom => 0, - Block::PottedBrownMushroom => 0, - Block::PottedDeadBush => 0, - Block::PottedCactus => 0, - Block::Carrots(data) => data.value(), - Block::Potatoes(data) => data.value(), - Block::OakButton(data) => data.value(), - Block::SpruceButton(data) => data.value(), - Block::BirchButton(data) => data.value(), - Block::JungleButton(data) => data.value(), - Block::AcaciaButton(data) => data.value(), - Block::DarkOakButton(data) => data.value(), - Block::SkeletonWallSkull(data) => data.value(), - Block::SkeletonSkull(data) => data.value(), - Block::WitherSkeletonWallSkull(data) => data.value(), - Block::WitherSkeletonSkull(data) => data.value(), - Block::ZombieWallHead(data) => data.value(), - Block::ZombieHead(data) => data.value(), - Block::PlayerWallHead(data) => data.value(), - Block::PlayerHead(data) => data.value(), - Block::CreeperWallHead(data) => data.value(), - Block::CreeperHead(data) => data.value(), - Block::DragonWallHead(data) => data.value(), - Block::DragonHead(data) => data.value(), - Block::Anvil(data) => data.value(), - Block::ChippedAnvil(data) => data.value(), - Block::DamagedAnvil(data) => data.value(), - Block::TrappedChest(data) => data.value(), - Block::LightWeightedPressurePlate(data) => data.value(), - Block::HeavyWeightedPressurePlate(data) => data.value(), - Block::Comparator(data) => data.value(), - Block::DaylightDetector(data) => data.value(), - Block::RedstoneBlock => 0, - Block::NetherQuartzOre => 0, - Block::Hopper(data) => data.value(), - Block::QuartzBlock => 0, - Block::ChiseledQuartzBlock => 0, - Block::QuartzPillar(data) => data.value(), - Block::QuartzStairs(data) => data.value(), - Block::ActivatorRail(data) => data.value(), - Block::Dropper(data) => data.value(), - Block::WhiteTerracotta => 0, - Block::OrangeTerracotta => 0, - Block::MagentaTerracotta => 0, - Block::LightBlueTerracotta => 0, - Block::YellowTerracotta => 0, - Block::LimeTerracotta => 0, - Block::PinkTerracotta => 0, - Block::GrayTerracotta => 0, - Block::LightGrayTerracotta => 0, - Block::CyanTerracotta => 0, - Block::PurpleTerracotta => 0, - Block::BlueTerracotta => 0, - Block::BrownTerracotta => 0, - Block::GreenTerracotta => 0, - Block::RedTerracotta => 0, - Block::BlackTerracotta => 0, - Block::WhiteStainedGlassPane(data) => data.value(), - Block::OrangeStainedGlassPane(data) => data.value(), - Block::MagentaStainedGlassPane(data) => data.value(), - Block::LightBlueStainedGlassPane(data) => data.value(), - Block::YellowStainedGlassPane(data) => data.value(), - Block::LimeStainedGlassPane(data) => data.value(), - Block::PinkStainedGlassPane(data) => data.value(), - Block::GrayStainedGlassPane(data) => data.value(), - Block::LightGrayStainedGlassPane(data) => data.value(), - Block::CyanStainedGlassPane(data) => data.value(), - Block::PurpleStainedGlassPane(data) => data.value(), - Block::BlueStainedGlassPane(data) => data.value(), - Block::BrownStainedGlassPane(data) => data.value(), - Block::GreenStainedGlassPane(data) => data.value(), - Block::RedStainedGlassPane(data) => data.value(), - Block::BlackStainedGlassPane(data) => data.value(), - Block::AcaciaStairs(data) => data.value(), - Block::DarkOakStairs(data) => data.value(), - Block::SlimeBlock => 0, - Block::Barrier => 0, - Block::IronTrapdoor(data) => data.value(), - Block::Prismarine => 0, - Block::PrismarineBricks => 0, - Block::DarkPrismarine => 0, - Block::PrismarineStairs(data) => data.value(), - Block::PrismarineBrickStairs(data) => data.value(), - Block::DarkPrismarineStairs(data) => data.value(), - Block::PrismarineSlab(data) => data.value(), - Block::PrismarineBrickSlab(data) => data.value(), - Block::DarkPrismarineSlab(data) => data.value(), - Block::SeaLantern => 0, - Block::HayBlock(data) => data.value(), - Block::WhiteCarpet => 0, - Block::OrangeCarpet => 0, - Block::MagentaCarpet => 0, - Block::LightBlueCarpet => 0, - Block::YellowCarpet => 0, - Block::LimeCarpet => 0, - Block::PinkCarpet => 0, - Block::GrayCarpet => 0, - Block::LightGrayCarpet => 0, - Block::CyanCarpet => 0, - Block::PurpleCarpet => 0, - Block::BlueCarpet => 0, - Block::BrownCarpet => 0, - Block::GreenCarpet => 0, - Block::RedCarpet => 0, - Block::BlackCarpet => 0, - Block::Terracotta => 0, - Block::CoalBlock => 0, - Block::PackedIce => 0, - Block::Sunflower(data) => data.value(), - Block::Lilac(data) => data.value(), - Block::RoseBush(data) => data.value(), - Block::Peony(data) => data.value(), - Block::TallGrass(data) => data.value(), - Block::LargeFern(data) => data.value(), - Block::WhiteBanner(data) => data.value(), - Block::OrangeBanner(data) => data.value(), - Block::MagentaBanner(data) => data.value(), - Block::LightBlueBanner(data) => data.value(), - Block::YellowBanner(data) => data.value(), - Block::LimeBanner(data) => data.value(), - Block::PinkBanner(data) => data.value(), - Block::GrayBanner(data) => data.value(), - Block::LightGrayBanner(data) => data.value(), - Block::CyanBanner(data) => data.value(), - Block::PurpleBanner(data) => data.value(), - Block::BlueBanner(data) => data.value(), - Block::BrownBanner(data) => data.value(), - Block::GreenBanner(data) => data.value(), - Block::RedBanner(data) => data.value(), - Block::BlackBanner(data) => data.value(), - Block::WhiteWallBanner(data) => data.value(), - Block::OrangeWallBanner(data) => data.value(), - Block::MagentaWallBanner(data) => data.value(), - Block::LightBlueWallBanner(data) => data.value(), - Block::YellowWallBanner(data) => data.value(), - Block::LimeWallBanner(data) => data.value(), - Block::PinkWallBanner(data) => data.value(), - Block::GrayWallBanner(data) => data.value(), - Block::LightGrayWallBanner(data) => data.value(), - Block::CyanWallBanner(data) => data.value(), - Block::PurpleWallBanner(data) => data.value(), - Block::BlueWallBanner(data) => data.value(), - Block::BrownWallBanner(data) => data.value(), - Block::GreenWallBanner(data) => data.value(), - Block::RedWallBanner(data) => data.value(), - Block::BlackWallBanner(data) => data.value(), - Block::RedSandstone => 0, - Block::ChiseledRedSandstone => 0, - Block::CutRedSandstone => 0, - Block::RedSandstoneStairs(data) => data.value(), - Block::OakSlab(data) => data.value(), - Block::SpruceSlab(data) => data.value(), - Block::BirchSlab(data) => data.value(), - Block::JungleSlab(data) => data.value(), - Block::AcaciaSlab(data) => data.value(), - Block::DarkOakSlab(data) => data.value(), - Block::StoneSlab(data) => data.value(), - Block::SandstoneSlab(data) => data.value(), - Block::PetrifiedOakSlab(data) => data.value(), - Block::CobblestoneSlab(data) => data.value(), - Block::BrickSlab(data) => data.value(), - Block::StoneBrickSlab(data) => data.value(), - Block::NetherBrickSlab(data) => data.value(), - Block::QuartzSlab(data) => data.value(), - Block::RedSandstoneSlab(data) => data.value(), - Block::PurpurSlab(data) => data.value(), - Block::SmoothStone => 0, - Block::SmoothSandstone => 0, - Block::SmoothQuartz => 0, - Block::SmoothRedSandstone => 0, - Block::SpruceFenceGate(data) => data.value(), - Block::BirchFenceGate(data) => data.value(), - Block::JungleFenceGate(data) => data.value(), - Block::AcaciaFenceGate(data) => data.value(), - Block::DarkOakFenceGate(data) => data.value(), - Block::SpruceFence(data) => data.value(), - Block::BirchFence(data) => data.value(), - Block::JungleFence(data) => data.value(), - Block::AcaciaFence(data) => data.value(), - Block::DarkOakFence(data) => data.value(), - Block::SpruceDoor(data) => data.value(), - Block::BirchDoor(data) => data.value(), - Block::JungleDoor(data) => data.value(), - Block::AcaciaDoor(data) => data.value(), - Block::DarkOakDoor(data) => data.value(), - Block::EndRod(data) => data.value(), - Block::ChorusPlant(data) => data.value(), - Block::ChorusFlower(data) => data.value(), - Block::PurpurBlock => 0, - Block::PurpurPillar(data) => data.value(), - Block::PurpurStairs(data) => data.value(), - Block::EndStoneBricks => 0, - Block::Beetroots(data) => data.value(), - Block::GrassPath => 0, - Block::EndGateway => 0, - Block::RepeatingCommandBlock(data) => data.value(), - Block::ChainCommandBlock(data) => data.value(), - Block::FrostedIce(data) => data.value(), - Block::MagmaBlock => 0, - Block::NetherWartBlock => 0, - Block::RedNetherBricks => 0, - Block::BoneBlock(data) => data.value(), - Block::StructureVoid => 0, - Block::Observer(data) => data.value(), - Block::ShulkerBox(data) => data.value(), - Block::WhiteShulkerBox(data) => data.value(), - Block::OrangeShulkerBox(data) => data.value(), - Block::MagentaShulkerBox(data) => data.value(), - Block::LightBlueShulkerBox(data) => data.value(), - Block::YellowShulkerBox(data) => data.value(), - Block::LimeShulkerBox(data) => data.value(), - Block::PinkShulkerBox(data) => data.value(), - Block::GrayShulkerBox(data) => data.value(), - Block::LightGrayShulkerBox(data) => data.value(), - Block::CyanShulkerBox(data) => data.value(), - Block::PurpleShulkerBox(data) => data.value(), - Block::BlueShulkerBox(data) => data.value(), - Block::BrownShulkerBox(data) => data.value(), - Block::GreenShulkerBox(data) => data.value(), - Block::RedShulkerBox(data) => data.value(), - Block::BlackShulkerBox(data) => data.value(), - Block::WhiteGlazedTerracotta(data) => data.value(), - Block::OrangeGlazedTerracotta(data) => data.value(), - Block::MagentaGlazedTerracotta(data) => data.value(), - Block::LightBlueGlazedTerracotta(data) => data.value(), - Block::YellowGlazedTerracotta(data) => data.value(), - Block::LimeGlazedTerracotta(data) => data.value(), - Block::PinkGlazedTerracotta(data) => data.value(), - Block::GrayGlazedTerracotta(data) => data.value(), - Block::LightGrayGlazedTerracotta(data) => data.value(), - Block::CyanGlazedTerracotta(data) => data.value(), - Block::PurpleGlazedTerracotta(data) => data.value(), - Block::BlueGlazedTerracotta(data) => data.value(), - Block::BrownGlazedTerracotta(data) => data.value(), - Block::GreenGlazedTerracotta(data) => data.value(), - Block::RedGlazedTerracotta(data) => data.value(), - Block::BlackGlazedTerracotta(data) => data.value(), - Block::WhiteConcrete => 0, - Block::OrangeConcrete => 0, - Block::MagentaConcrete => 0, - Block::LightBlueConcrete => 0, - Block::YellowConcrete => 0, - Block::LimeConcrete => 0, - Block::PinkConcrete => 0, - Block::GrayConcrete => 0, - Block::LightGrayConcrete => 0, - Block::CyanConcrete => 0, - Block::PurpleConcrete => 0, - Block::BlueConcrete => 0, - Block::BrownConcrete => 0, - Block::GreenConcrete => 0, - Block::RedConcrete => 0, - Block::BlackConcrete => 0, - Block::WhiteConcretePowder => 0, - Block::OrangeConcretePowder => 0, - Block::MagentaConcretePowder => 0, - Block::LightBlueConcretePowder => 0, - Block::YellowConcretePowder => 0, - Block::LimeConcretePowder => 0, - Block::PinkConcretePowder => 0, - Block::GrayConcretePowder => 0, - Block::LightGrayConcretePowder => 0, - Block::CyanConcretePowder => 0, - Block::PurpleConcretePowder => 0, - Block::BlueConcretePowder => 0, - Block::BrownConcretePowder => 0, - Block::GreenConcretePowder => 0, - Block::RedConcretePowder => 0, - Block::BlackConcretePowder => 0, - Block::Kelp(data) => data.value(), - Block::KelpPlant => 0, - Block::DriedKelpBlock => 0, - Block::TurtleEgg(data) => data.value(), - Block::DeadTubeCoralBlock => 0, - Block::DeadBrainCoralBlock => 0, - Block::DeadBubbleCoralBlock => 0, - Block::DeadFireCoralBlock => 0, - Block::DeadHornCoralBlock => 0, - Block::TubeCoralBlock => 0, - Block::BrainCoralBlock => 0, - Block::BubbleCoralBlock => 0, - Block::FireCoralBlock => 0, - Block::HornCoralBlock => 0, - Block::DeadTubeCoral(data) => data.value(), - Block::DeadBrainCoral(data) => data.value(), - Block::DeadBubbleCoral(data) => data.value(), - Block::DeadFireCoral(data) => data.value(), - Block::DeadHornCoral(data) => data.value(), - Block::TubeCoral(data) => data.value(), - Block::BrainCoral(data) => data.value(), - Block::BubbleCoral(data) => data.value(), - Block::FireCoral(data) => data.value(), - Block::HornCoral(data) => data.value(), - Block::DeadTubeCoralWallFan(data) => data.value(), - Block::DeadBrainCoralWallFan(data) => data.value(), - Block::DeadBubbleCoralWallFan(data) => data.value(), - Block::DeadFireCoralWallFan(data) => data.value(), - Block::DeadHornCoralWallFan(data) => data.value(), - Block::TubeCoralWallFan(data) => data.value(), - Block::BrainCoralWallFan(data) => data.value(), - Block::BubbleCoralWallFan(data) => data.value(), - Block::FireCoralWallFan(data) => data.value(), - Block::HornCoralWallFan(data) => data.value(), - Block::DeadTubeCoralFan(data) => data.value(), - Block::DeadBrainCoralFan(data) => data.value(), - Block::DeadBubbleCoralFan(data) => data.value(), - Block::DeadFireCoralFan(data) => data.value(), - Block::DeadHornCoralFan(data) => data.value(), - Block::TubeCoralFan(data) => data.value(), - Block::BrainCoralFan(data) => data.value(), - Block::BubbleCoralFan(data) => data.value(), - Block::FireCoralFan(data) => data.value(), - Block::HornCoralFan(data) => data.value(), - Block::SeaPickle(data) => data.value(), - Block::BlueIce => 0, - Block::Conduit(data) => data.value(), - Block::VoidAir => 0, - Block::CaveAir => 0, - Block::BubbleColumn(data) => data.value(), - Block::StructureBlock(data) => data.value(), - } - } - pub fn internal_state_id(&self) -> usize { - let type_offset = INTERNAL_ID_OFFSETS[self.internal_type_id()]; - let data_offset = self.internal_id_data_offset(); - type_offset + data_offset - } - pub fn from_name_and_props(name: &str, props: &HashMap) -> Option { - match name { - "minecraft:air" => Some(Block::Air), - "minecraft:stone" => Some(Block::Stone), - "minecraft:granite" => Some(Block::Granite), - "minecraft:polished_granite" => Some(Block::PolishedGranite), - "minecraft:diorite" => Some(Block::Diorite), - "minecraft:polished_diorite" => Some(Block::PolishedDiorite), - "minecraft:andesite" => Some(Block::Andesite), - "minecraft:polished_andesite" => Some(Block::PolishedAndesite), - "minecraft:grass_block" => { - let data = GrassBlockData::from_map(props)?; - Some(Block::GrassBlock(data)) - } - "minecraft:dirt" => Some(Block::Dirt), - "minecraft:coarse_dirt" => Some(Block::CoarseDirt), - "minecraft:podzol" => { - let data = PodzolData::from_map(props)?; - Some(Block::Podzol(data)) - } - "minecraft:cobblestone" => Some(Block::Cobblestone), - "minecraft:oak_planks" => Some(Block::OakPlanks), - "minecraft:spruce_planks" => Some(Block::SprucePlanks), - "minecraft:birch_planks" => Some(Block::BirchPlanks), - "minecraft:jungle_planks" => Some(Block::JunglePlanks), - "minecraft:acacia_planks" => Some(Block::AcaciaPlanks), - "minecraft:dark_oak_planks" => Some(Block::DarkOakPlanks), - "minecraft:oak_sapling" => { - let data = OakSaplingData::from_map(props)?; - Some(Block::OakSapling(data)) - } - "minecraft:spruce_sapling" => { - let data = SpruceSaplingData::from_map(props)?; - Some(Block::SpruceSapling(data)) - } - "minecraft:birch_sapling" => { - let data = BirchSaplingData::from_map(props)?; - Some(Block::BirchSapling(data)) - } - "minecraft:jungle_sapling" => { - let data = JungleSaplingData::from_map(props)?; - Some(Block::JungleSapling(data)) - } - "minecraft:acacia_sapling" => { - let data = AcaciaSaplingData::from_map(props)?; - Some(Block::AcaciaSapling(data)) - } - "minecraft:dark_oak_sapling" => { - let data = DarkOakSaplingData::from_map(props)?; - Some(Block::DarkOakSapling(data)) - } - "minecraft:bedrock" => Some(Block::Bedrock), - "minecraft:water" => { - let data = WaterData::from_map(props)?; - Some(Block::Water(data)) - } - "minecraft:lava" => { - let data = LavaData::from_map(props)?; - Some(Block::Lava(data)) - } - "minecraft:sand" => Some(Block::Sand), - "minecraft:red_sand" => Some(Block::RedSand), - "minecraft:gravel" => Some(Block::Gravel), - "minecraft:gold_ore" => Some(Block::GoldOre), - "minecraft:iron_ore" => Some(Block::IronOre), - "minecraft:coal_ore" => Some(Block::CoalOre), - "minecraft:oak_log" => { - let data = OakLogData::from_map(props)?; - Some(Block::OakLog(data)) - } - "minecraft:spruce_log" => { - let data = SpruceLogData::from_map(props)?; - Some(Block::SpruceLog(data)) - } - "minecraft:birch_log" => { - let data = BirchLogData::from_map(props)?; - Some(Block::BirchLog(data)) - } - "minecraft:jungle_log" => { - let data = JungleLogData::from_map(props)?; - Some(Block::JungleLog(data)) - } - "minecraft:acacia_log" => { - let data = AcaciaLogData::from_map(props)?; - Some(Block::AcaciaLog(data)) - } - "minecraft:dark_oak_log" => { - let data = DarkOakLogData::from_map(props)?; - Some(Block::DarkOakLog(data)) - } - "minecraft:stripped_spruce_log" => { - let data = StrippedSpruceLogData::from_map(props)?; - Some(Block::StrippedSpruceLog(data)) - } - "minecraft:stripped_birch_log" => { - let data = StrippedBirchLogData::from_map(props)?; - Some(Block::StrippedBirchLog(data)) - } - "minecraft:stripped_jungle_log" => { - let data = StrippedJungleLogData::from_map(props)?; - Some(Block::StrippedJungleLog(data)) - } - "minecraft:stripped_acacia_log" => { - let data = StrippedAcaciaLogData::from_map(props)?; - Some(Block::StrippedAcaciaLog(data)) - } - "minecraft:stripped_dark_oak_log" => { - let data = StrippedDarkOakLogData::from_map(props)?; - Some(Block::StrippedDarkOakLog(data)) - } - "minecraft:stripped_oak_log" => { - let data = StrippedOakLogData::from_map(props)?; - Some(Block::StrippedOakLog(data)) - } - "minecraft:oak_wood" => { - let data = OakWoodData::from_map(props)?; - Some(Block::OakWood(data)) - } - "minecraft:spruce_wood" => { - let data = SpruceWoodData::from_map(props)?; - Some(Block::SpruceWood(data)) - } - "minecraft:birch_wood" => { - let data = BirchWoodData::from_map(props)?; - Some(Block::BirchWood(data)) - } - "minecraft:jungle_wood" => { - let data = JungleWoodData::from_map(props)?; - Some(Block::JungleWood(data)) - } - "minecraft:acacia_wood" => { - let data = AcaciaWoodData::from_map(props)?; - Some(Block::AcaciaWood(data)) - } - "minecraft:dark_oak_wood" => { - let data = DarkOakWoodData::from_map(props)?; - Some(Block::DarkOakWood(data)) - } - "minecraft:stripped_oak_wood" => { - let data = StrippedOakWoodData::from_map(props)?; - Some(Block::StrippedOakWood(data)) - } - "minecraft:stripped_spruce_wood" => { - let data = StrippedSpruceWoodData::from_map(props)?; - Some(Block::StrippedSpruceWood(data)) - } - "minecraft:stripped_birch_wood" => { - let data = StrippedBirchWoodData::from_map(props)?; - Some(Block::StrippedBirchWood(data)) - } - "minecraft:stripped_jungle_wood" => { - let data = StrippedJungleWoodData::from_map(props)?; - Some(Block::StrippedJungleWood(data)) - } - "minecraft:stripped_acacia_wood" => { - let data = StrippedAcaciaWoodData::from_map(props)?; - Some(Block::StrippedAcaciaWood(data)) - } - "minecraft:stripped_dark_oak_wood" => { - let data = StrippedDarkOakWoodData::from_map(props)?; - Some(Block::StrippedDarkOakWood(data)) - } - "minecraft:oak_leaves" => { - let data = OakLeavesData::from_map(props)?; - Some(Block::OakLeaves(data)) - } - "minecraft:spruce_leaves" => { - let data = SpruceLeavesData::from_map(props)?; - Some(Block::SpruceLeaves(data)) - } - "minecraft:birch_leaves" => { - let data = BirchLeavesData::from_map(props)?; - Some(Block::BirchLeaves(data)) - } - "minecraft:jungle_leaves" => { - let data = JungleLeavesData::from_map(props)?; - Some(Block::JungleLeaves(data)) - } - "minecraft:acacia_leaves" => { - let data = AcaciaLeavesData::from_map(props)?; - Some(Block::AcaciaLeaves(data)) - } - "minecraft:dark_oak_leaves" => { - let data = DarkOakLeavesData::from_map(props)?; - Some(Block::DarkOakLeaves(data)) - } - "minecraft:sponge" => Some(Block::Sponge), - "minecraft:wet_sponge" => Some(Block::WetSponge), - "minecraft:glass" => Some(Block::Glass), - "minecraft:lapis_ore" => Some(Block::LapisOre), - "minecraft:lapis_block" => Some(Block::LapisBlock), - "minecraft:dispenser" => { - let data = DispenserData::from_map(props)?; - Some(Block::Dispenser(data)) - } - "minecraft:sandstone" => Some(Block::Sandstone), - "minecraft:chiseled_sandstone" => Some(Block::ChiseledSandstone), - "minecraft:cut_sandstone" => Some(Block::CutSandstone), - "minecraft:note_block" => { - let data = NoteBlockData::from_map(props)?; - Some(Block::NoteBlock(data)) - } - "minecraft:white_bed" => { - let data = WhiteBedData::from_map(props)?; - Some(Block::WhiteBed(data)) - } - "minecraft:orange_bed" => { - let data = OrangeBedData::from_map(props)?; - Some(Block::OrangeBed(data)) - } - "minecraft:magenta_bed" => { - let data = MagentaBedData::from_map(props)?; - Some(Block::MagentaBed(data)) - } - "minecraft:light_blue_bed" => { - let data = LightBlueBedData::from_map(props)?; - Some(Block::LightBlueBed(data)) - } - "minecraft:yellow_bed" => { - let data = YellowBedData::from_map(props)?; - Some(Block::YellowBed(data)) - } - "minecraft:lime_bed" => { - let data = LimeBedData::from_map(props)?; - Some(Block::LimeBed(data)) - } - "minecraft:pink_bed" => { - let data = PinkBedData::from_map(props)?; - Some(Block::PinkBed(data)) - } - "minecraft:gray_bed" => { - let data = GrayBedData::from_map(props)?; - Some(Block::GrayBed(data)) - } - "minecraft:light_gray_bed" => { - let data = LightGrayBedData::from_map(props)?; - Some(Block::LightGrayBed(data)) - } - "minecraft:cyan_bed" => { - let data = CyanBedData::from_map(props)?; - Some(Block::CyanBed(data)) - } - "minecraft:purple_bed" => { - let data = PurpleBedData::from_map(props)?; - Some(Block::PurpleBed(data)) - } - "minecraft:blue_bed" => { - let data = BlueBedData::from_map(props)?; - Some(Block::BlueBed(data)) - } - "minecraft:brown_bed" => { - let data = BrownBedData::from_map(props)?; - Some(Block::BrownBed(data)) - } - "minecraft:green_bed" => { - let data = GreenBedData::from_map(props)?; - Some(Block::GreenBed(data)) - } - "minecraft:red_bed" => { - let data = RedBedData::from_map(props)?; - Some(Block::RedBed(data)) - } - "minecraft:black_bed" => { - let data = BlackBedData::from_map(props)?; - Some(Block::BlackBed(data)) - } - "minecraft:powered_rail" => { - let data = PoweredRailData::from_map(props)?; - Some(Block::PoweredRail(data)) - } - "minecraft:detector_rail" => { - let data = DetectorRailData::from_map(props)?; - Some(Block::DetectorRail(data)) - } - "minecraft:sticky_piston" => { - let data = StickyPistonData::from_map(props)?; - Some(Block::StickyPiston(data)) - } - "minecraft:cobweb" => Some(Block::Cobweb), - "minecraft:grass" => Some(Block::Grass), - "minecraft:fern" => Some(Block::Fern), - "minecraft:dead_bush" => Some(Block::DeadBush), - "minecraft:seagrass" => Some(Block::Seagrass), - "minecraft:tall_seagrass" => { - let data = TallSeagrassData::from_map(props)?; - Some(Block::TallSeagrass(data)) - } - "minecraft:piston" => { - let data = PistonData::from_map(props)?; - Some(Block::Piston(data)) - } - "minecraft:piston_head" => { - let data = PistonHeadData::from_map(props)?; - Some(Block::PistonHead(data)) - } - "minecraft:white_wool" => Some(Block::WhiteWool), - "minecraft:orange_wool" => Some(Block::OrangeWool), - "minecraft:magenta_wool" => Some(Block::MagentaWool), - "minecraft:light_blue_wool" => Some(Block::LightBlueWool), - "minecraft:yellow_wool" => Some(Block::YellowWool), - "minecraft:lime_wool" => Some(Block::LimeWool), - "minecraft:pink_wool" => Some(Block::PinkWool), - "minecraft:gray_wool" => Some(Block::GrayWool), - "minecraft:light_gray_wool" => Some(Block::LightGrayWool), - "minecraft:cyan_wool" => Some(Block::CyanWool), - "minecraft:purple_wool" => Some(Block::PurpleWool), - "minecraft:blue_wool" => Some(Block::BlueWool), - "minecraft:brown_wool" => Some(Block::BrownWool), - "minecraft:green_wool" => Some(Block::GreenWool), - "minecraft:red_wool" => Some(Block::RedWool), - "minecraft:black_wool" => Some(Block::BlackWool), - "minecraft:moving_piston" => { - let data = MovingPistonData::from_map(props)?; - Some(Block::MovingPiston(data)) - } - "minecraft:dandelion" => Some(Block::Dandelion), - "minecraft:poppy" => Some(Block::Poppy), - "minecraft:blue_orchid" => Some(Block::BlueOrchid), - "minecraft:allium" => Some(Block::Allium), - "minecraft:azure_bluet" => Some(Block::AzureBluet), - "minecraft:red_tulip" => Some(Block::RedTulip), - "minecraft:orange_tulip" => Some(Block::OrangeTulip), - "minecraft:white_tulip" => Some(Block::WhiteTulip), - "minecraft:pink_tulip" => Some(Block::PinkTulip), - "minecraft:oxeye_daisy" => Some(Block::OxeyeDaisy), - "minecraft:brown_mushroom" => Some(Block::BrownMushroom), - "minecraft:red_mushroom" => Some(Block::RedMushroom), - "minecraft:gold_block" => Some(Block::GoldBlock), - "minecraft:iron_block" => Some(Block::IronBlock), - "minecraft:bricks" => Some(Block::Bricks), - "minecraft:tnt" => { - let data = TntData::from_map(props)?; - Some(Block::Tnt(data)) - } - "minecraft:bookshelf" => Some(Block::Bookshelf), - "minecraft:mossy_cobblestone" => Some(Block::MossyCobblestone), - "minecraft:obsidian" => Some(Block::Obsidian), - "minecraft:torch" => Some(Block::Torch), - "minecraft:wall_torch" => { - let data = WallTorchData::from_map(props)?; - Some(Block::WallTorch(data)) - } - "minecraft:fire" => { - let data = FireData::from_map(props)?; - Some(Block::Fire(data)) - } - "minecraft:spawner" => Some(Block::Spawner), - "minecraft:oak_stairs" => { - let data = OakStairsData::from_map(props)?; - Some(Block::OakStairs(data)) - } - "minecraft:chest" => { - let data = ChestData::from_map(props)?; - Some(Block::Chest(data)) - } - "minecraft:redstone_wire" => { - let data = RedstoneWireData::from_map(props)?; - Some(Block::RedstoneWire(data)) - } - "minecraft:diamond_ore" => Some(Block::DiamondOre), - "minecraft:diamond_block" => Some(Block::DiamondBlock), - "minecraft:crafting_table" => Some(Block::CraftingTable), - "minecraft:wheat" => { - let data = WheatData::from_map(props)?; - Some(Block::Wheat(data)) - } - "minecraft:farmland" => { - let data = FarmlandData::from_map(props)?; - Some(Block::Farmland(data)) - } - "minecraft:furnace" => { - let data = FurnaceData::from_map(props)?; - Some(Block::Furnace(data)) - } - "minecraft:sign" => { - let data = SignData::from_map(props)?; - Some(Block::Sign(data)) - } - "minecraft:oak_door" => { - let data = OakDoorData::from_map(props)?; - Some(Block::OakDoor(data)) - } - "minecraft:ladder" => { - let data = LadderData::from_map(props)?; - Some(Block::Ladder(data)) - } - "minecraft:rail" => { - let data = RailData::from_map(props)?; - Some(Block::Rail(data)) - } - "minecraft:cobblestone_stairs" => { - let data = CobblestoneStairsData::from_map(props)?; - Some(Block::CobblestoneStairs(data)) - } - "minecraft:wall_sign" => { - let data = WallSignData::from_map(props)?; - Some(Block::WallSign(data)) - } - "minecraft:lever" => { - let data = LeverData::from_map(props)?; - Some(Block::Lever(data)) - } - "minecraft:stone_pressure_plate" => { - let data = StonePressurePlateData::from_map(props)?; - Some(Block::StonePressurePlate(data)) - } - "minecraft:iron_door" => { - let data = IronDoorData::from_map(props)?; - Some(Block::IronDoor(data)) - } - "minecraft:oak_pressure_plate" => { - let data = OakPressurePlateData::from_map(props)?; - Some(Block::OakPressurePlate(data)) - } - "minecraft:spruce_pressure_plate" => { - let data = SprucePressurePlateData::from_map(props)?; - Some(Block::SprucePressurePlate(data)) - } - "minecraft:birch_pressure_plate" => { - let data = BirchPressurePlateData::from_map(props)?; - Some(Block::BirchPressurePlate(data)) - } - "minecraft:jungle_pressure_plate" => { - let data = JunglePressurePlateData::from_map(props)?; - Some(Block::JunglePressurePlate(data)) - } - "minecraft:acacia_pressure_plate" => { - let data = AcaciaPressurePlateData::from_map(props)?; - Some(Block::AcaciaPressurePlate(data)) - } - "minecraft:dark_oak_pressure_plate" => { - let data = DarkOakPressurePlateData::from_map(props)?; - Some(Block::DarkOakPressurePlate(data)) - } - "minecraft:redstone_ore" => { - let data = RedstoneOreData::from_map(props)?; - Some(Block::RedstoneOre(data)) - } - "minecraft:redstone_torch" => { - let data = RedstoneTorchData::from_map(props)?; - Some(Block::RedstoneTorch(data)) - } - "minecraft:redstone_wall_torch" => { - let data = RedstoneWallTorchData::from_map(props)?; - Some(Block::RedstoneWallTorch(data)) - } - "minecraft:stone_button" => { - let data = StoneButtonData::from_map(props)?; - Some(Block::StoneButton(data)) - } - "minecraft:snow" => { - let data = SnowData::from_map(props)?; - Some(Block::Snow(data)) - } - "minecraft:ice" => Some(Block::Ice), - "minecraft:snow_block" => Some(Block::SnowBlock), - "minecraft:cactus" => { - let data = CactusData::from_map(props)?; - Some(Block::Cactus(data)) - } - "minecraft:clay" => Some(Block::Clay), - "minecraft:sugar_cane" => { - let data = SugarCaneData::from_map(props)?; - Some(Block::SugarCane(data)) - } - "minecraft:jukebox" => { - let data = JukeboxData::from_map(props)?; - Some(Block::Jukebox(data)) - } - "minecraft:oak_fence" => { - let data = OakFenceData::from_map(props)?; - Some(Block::OakFence(data)) - } - "minecraft:pumpkin" => Some(Block::Pumpkin), - "minecraft:netherrack" => Some(Block::Netherrack), - "minecraft:soul_sand" => Some(Block::SoulSand), - "minecraft:glowstone" => Some(Block::Glowstone), - "minecraft:nether_portal" => { - let data = NetherPortalData::from_map(props)?; - Some(Block::NetherPortal(data)) - } - "minecraft:carved_pumpkin" => { - let data = CarvedPumpkinData::from_map(props)?; - Some(Block::CarvedPumpkin(data)) - } - "minecraft:jack_o_lantern" => { - let data = JackOLanternData::from_map(props)?; - Some(Block::JackOLantern(data)) - } - "minecraft:cake" => { - let data = CakeData::from_map(props)?; - Some(Block::Cake(data)) - } - "minecraft:repeater" => { - let data = RepeaterData::from_map(props)?; - Some(Block::Repeater(data)) - } - "minecraft:white_stained_glass" => Some(Block::WhiteStainedGlass), - "minecraft:orange_stained_glass" => Some(Block::OrangeStainedGlass), - "minecraft:magenta_stained_glass" => Some(Block::MagentaStainedGlass), - "minecraft:light_blue_stained_glass" => Some(Block::LightBlueStainedGlass), - "minecraft:yellow_stained_glass" => Some(Block::YellowStainedGlass), - "minecraft:lime_stained_glass" => Some(Block::LimeStainedGlass), - "minecraft:pink_stained_glass" => Some(Block::PinkStainedGlass), - "minecraft:gray_stained_glass" => Some(Block::GrayStainedGlass), - "minecraft:light_gray_stained_glass" => Some(Block::LightGrayStainedGlass), - "minecraft:cyan_stained_glass" => Some(Block::CyanStainedGlass), - "minecraft:purple_stained_glass" => Some(Block::PurpleStainedGlass), - "minecraft:blue_stained_glass" => Some(Block::BlueStainedGlass), - "minecraft:brown_stained_glass" => Some(Block::BrownStainedGlass), - "minecraft:green_stained_glass" => Some(Block::GreenStainedGlass), - "minecraft:red_stained_glass" => Some(Block::RedStainedGlass), - "minecraft:black_stained_glass" => Some(Block::BlackStainedGlass), - "minecraft:oak_trapdoor" => { - let data = OakTrapdoorData::from_map(props)?; - Some(Block::OakTrapdoor(data)) - } - "minecraft:spruce_trapdoor" => { - let data = SpruceTrapdoorData::from_map(props)?; - Some(Block::SpruceTrapdoor(data)) - } - "minecraft:birch_trapdoor" => { - let data = BirchTrapdoorData::from_map(props)?; - Some(Block::BirchTrapdoor(data)) - } - "minecraft:jungle_trapdoor" => { - let data = JungleTrapdoorData::from_map(props)?; - Some(Block::JungleTrapdoor(data)) - } - "minecraft:acacia_trapdoor" => { - let data = AcaciaTrapdoorData::from_map(props)?; - Some(Block::AcaciaTrapdoor(data)) - } - "minecraft:dark_oak_trapdoor" => { - let data = DarkOakTrapdoorData::from_map(props)?; - Some(Block::DarkOakTrapdoor(data)) - } - "minecraft:infested_stone" => Some(Block::InfestedStone), - "minecraft:infested_cobblestone" => Some(Block::InfestedCobblestone), - "minecraft:infested_stone_bricks" => Some(Block::InfestedStoneBricks), - "minecraft:infested_mossy_stone_bricks" => Some(Block::InfestedMossyStoneBricks), - "minecraft:infested_cracked_stone_bricks" => Some(Block::InfestedCrackedStoneBricks), - "minecraft:infested_chiseled_stone_bricks" => Some(Block::InfestedChiseledStoneBricks), - "minecraft:stone_bricks" => Some(Block::StoneBricks), - "minecraft:mossy_stone_bricks" => Some(Block::MossyStoneBricks), - "minecraft:cracked_stone_bricks" => Some(Block::CrackedStoneBricks), - "minecraft:chiseled_stone_bricks" => Some(Block::ChiseledStoneBricks), - "minecraft:brown_mushroom_block" => { - let data = BrownMushroomBlockData::from_map(props)?; - Some(Block::BrownMushroomBlock(data)) - } - "minecraft:red_mushroom_block" => { - let data = RedMushroomBlockData::from_map(props)?; - Some(Block::RedMushroomBlock(data)) - } - "minecraft:mushroom_stem" => { - let data = MushroomStemData::from_map(props)?; - Some(Block::MushroomStem(data)) - } - "minecraft:iron_bars" => { - let data = IronBarsData::from_map(props)?; - Some(Block::IronBars(data)) - } - "minecraft:glass_pane" => { - let data = GlassPaneData::from_map(props)?; - Some(Block::GlassPane(data)) - } - "minecraft:melon" => Some(Block::Melon), - "minecraft:attached_pumpkin_stem" => { - let data = AttachedPumpkinStemData::from_map(props)?; - Some(Block::AttachedPumpkinStem(data)) - } - "minecraft:attached_melon_stem" => { - let data = AttachedMelonStemData::from_map(props)?; - Some(Block::AttachedMelonStem(data)) - } - "minecraft:pumpkin_stem" => { - let data = PumpkinStemData::from_map(props)?; - Some(Block::PumpkinStem(data)) - } - "minecraft:melon_stem" => { - let data = MelonStemData::from_map(props)?; - Some(Block::MelonStem(data)) - } - "minecraft:vine" => { - let data = VineData::from_map(props)?; - Some(Block::Vine(data)) - } - "minecraft:oak_fence_gate" => { - let data = OakFenceGateData::from_map(props)?; - Some(Block::OakFenceGate(data)) - } - "minecraft:brick_stairs" => { - let data = BrickStairsData::from_map(props)?; - Some(Block::BrickStairs(data)) - } - "minecraft:stone_brick_stairs" => { - let data = StoneBrickStairsData::from_map(props)?; - Some(Block::StoneBrickStairs(data)) - } - "minecraft:mycelium" => { - let data = MyceliumData::from_map(props)?; - Some(Block::Mycelium(data)) - } - "minecraft:lily_pad" => Some(Block::LilyPad), - "minecraft:nether_bricks" => Some(Block::NetherBricks), - "minecraft:nether_brick_fence" => { - let data = NetherBrickFenceData::from_map(props)?; - Some(Block::NetherBrickFence(data)) - } - "minecraft:nether_brick_stairs" => { - let data = NetherBrickStairsData::from_map(props)?; - Some(Block::NetherBrickStairs(data)) - } - "minecraft:nether_wart" => { - let data = NetherWartData::from_map(props)?; - Some(Block::NetherWart(data)) - } - "minecraft:enchanting_table" => Some(Block::EnchantingTable), - "minecraft:brewing_stand" => { - let data = BrewingStandData::from_map(props)?; - Some(Block::BrewingStand(data)) - } - "minecraft:cauldron" => { - let data = CauldronData::from_map(props)?; - Some(Block::Cauldron(data)) - } - "minecraft:end_portal" => Some(Block::EndPortal), - "minecraft:end_portal_frame" => { - let data = EndPortalFrameData::from_map(props)?; - Some(Block::EndPortalFrame(data)) - } - "minecraft:end_stone" => Some(Block::EndStone), - "minecraft:dragon_egg" => Some(Block::DragonEgg), - "minecraft:redstone_lamp" => { - let data = RedstoneLampData::from_map(props)?; - Some(Block::RedstoneLamp(data)) - } - "minecraft:cocoa" => { - let data = CocoaData::from_map(props)?; - Some(Block::Cocoa(data)) - } - "minecraft:sandstone_stairs" => { - let data = SandstoneStairsData::from_map(props)?; - Some(Block::SandstoneStairs(data)) - } - "minecraft:emerald_ore" => Some(Block::EmeraldOre), - "minecraft:ender_chest" => { - let data = EnderChestData::from_map(props)?; - Some(Block::EnderChest(data)) - } - "minecraft:tripwire_hook" => { - let data = TripwireHookData::from_map(props)?; - Some(Block::TripwireHook(data)) - } - "minecraft:tripwire" => { - let data = TripwireData::from_map(props)?; - Some(Block::Tripwire(data)) - } - "minecraft:emerald_block" => Some(Block::EmeraldBlock), - "minecraft:spruce_stairs" => { - let data = SpruceStairsData::from_map(props)?; - Some(Block::SpruceStairs(data)) - } - "minecraft:birch_stairs" => { - let data = BirchStairsData::from_map(props)?; - Some(Block::BirchStairs(data)) - } - "minecraft:jungle_stairs" => { - let data = JungleStairsData::from_map(props)?; - Some(Block::JungleStairs(data)) - } - "minecraft:command_block" => { - let data = CommandBlockData::from_map(props)?; - Some(Block::CommandBlock(data)) - } - "minecraft:beacon" => Some(Block::Beacon), - "minecraft:cobblestone_wall" => { - let data = CobblestoneWallData::from_map(props)?; - Some(Block::CobblestoneWall(data)) - } - "minecraft:mossy_cobblestone_wall" => { - let data = MossyCobblestoneWallData::from_map(props)?; - Some(Block::MossyCobblestoneWall(data)) - } - "minecraft:flower_pot" => Some(Block::FlowerPot), - "minecraft:potted_oak_sapling" => Some(Block::PottedOakSapling), - "minecraft:potted_spruce_sapling" => Some(Block::PottedSpruceSapling), - "minecraft:potted_birch_sapling" => Some(Block::PottedBirchSapling), - "minecraft:potted_jungle_sapling" => Some(Block::PottedJungleSapling), - "minecraft:potted_acacia_sapling" => Some(Block::PottedAcaciaSapling), - "minecraft:potted_dark_oak_sapling" => Some(Block::PottedDarkOakSapling), - "minecraft:potted_fern" => Some(Block::PottedFern), - "minecraft:potted_dandelion" => Some(Block::PottedDandelion), - "minecraft:potted_poppy" => Some(Block::PottedPoppy), - "minecraft:potted_blue_orchid" => Some(Block::PottedBlueOrchid), - "minecraft:potted_allium" => Some(Block::PottedAllium), - "minecraft:potted_azure_bluet" => Some(Block::PottedAzureBluet), - "minecraft:potted_red_tulip" => Some(Block::PottedRedTulip), - "minecraft:potted_orange_tulip" => Some(Block::PottedOrangeTulip), - "minecraft:potted_white_tulip" => Some(Block::PottedWhiteTulip), - "minecraft:potted_pink_tulip" => Some(Block::PottedPinkTulip), - "minecraft:potted_oxeye_daisy" => Some(Block::PottedOxeyeDaisy), - "minecraft:potted_red_mushroom" => Some(Block::PottedRedMushroom), - "minecraft:potted_brown_mushroom" => Some(Block::PottedBrownMushroom), - "minecraft:potted_dead_bush" => Some(Block::PottedDeadBush), - "minecraft:potted_cactus" => Some(Block::PottedCactus), - "minecraft:carrots" => { - let data = CarrotsData::from_map(props)?; - Some(Block::Carrots(data)) - } - "minecraft:potatoes" => { - let data = PotatoesData::from_map(props)?; - Some(Block::Potatoes(data)) - } - "minecraft:oak_button" => { - let data = OakButtonData::from_map(props)?; - Some(Block::OakButton(data)) - } - "minecraft:spruce_button" => { - let data = SpruceButtonData::from_map(props)?; - Some(Block::SpruceButton(data)) - } - "minecraft:birch_button" => { - let data = BirchButtonData::from_map(props)?; - Some(Block::BirchButton(data)) - } - "minecraft:jungle_button" => { - let data = JungleButtonData::from_map(props)?; - Some(Block::JungleButton(data)) - } - "minecraft:acacia_button" => { - let data = AcaciaButtonData::from_map(props)?; - Some(Block::AcaciaButton(data)) - } - "minecraft:dark_oak_button" => { - let data = DarkOakButtonData::from_map(props)?; - Some(Block::DarkOakButton(data)) - } - "minecraft:skeleton_wall_skull" => { - let data = SkeletonWallSkullData::from_map(props)?; - Some(Block::SkeletonWallSkull(data)) - } - "minecraft:skeleton_skull" => { - let data = SkeletonSkullData::from_map(props)?; - Some(Block::SkeletonSkull(data)) - } - "minecraft:wither_skeleton_wall_skull" => { - let data = WitherSkeletonWallSkullData::from_map(props)?; - Some(Block::WitherSkeletonWallSkull(data)) - } - "minecraft:wither_skeleton_skull" => { - let data = WitherSkeletonSkullData::from_map(props)?; - Some(Block::WitherSkeletonSkull(data)) - } - "minecraft:zombie_wall_head" => { - let data = ZombieWallHeadData::from_map(props)?; - Some(Block::ZombieWallHead(data)) - } - "minecraft:zombie_head" => { - let data = ZombieHeadData::from_map(props)?; - Some(Block::ZombieHead(data)) - } - "minecraft:player_wall_head" => { - let data = PlayerWallHeadData::from_map(props)?; - Some(Block::PlayerWallHead(data)) - } - "minecraft:player_head" => { - let data = PlayerHeadData::from_map(props)?; - Some(Block::PlayerHead(data)) - } - "minecraft:creeper_wall_head" => { - let data = CreeperWallHeadData::from_map(props)?; - Some(Block::CreeperWallHead(data)) - } - "minecraft:creeper_head" => { - let data = CreeperHeadData::from_map(props)?; - Some(Block::CreeperHead(data)) - } - "minecraft:dragon_wall_head" => { - let data = DragonWallHeadData::from_map(props)?; - Some(Block::DragonWallHead(data)) - } - "minecraft:dragon_head" => { - let data = DragonHeadData::from_map(props)?; - Some(Block::DragonHead(data)) - } - "minecraft:anvil" => { - let data = AnvilData::from_map(props)?; - Some(Block::Anvil(data)) - } - "minecraft:chipped_anvil" => { - let data = ChippedAnvilData::from_map(props)?; - Some(Block::ChippedAnvil(data)) - } - "minecraft:damaged_anvil" => { - let data = DamagedAnvilData::from_map(props)?; - Some(Block::DamagedAnvil(data)) - } - "minecraft:trapped_chest" => { - let data = TrappedChestData::from_map(props)?; - Some(Block::TrappedChest(data)) - } - "minecraft:light_weighted_pressure_plate" => { - let data = LightWeightedPressurePlateData::from_map(props)?; - Some(Block::LightWeightedPressurePlate(data)) - } - "minecraft:heavy_weighted_pressure_plate" => { - let data = HeavyWeightedPressurePlateData::from_map(props)?; - Some(Block::HeavyWeightedPressurePlate(data)) - } - "minecraft:comparator" => { - let data = ComparatorData::from_map(props)?; - Some(Block::Comparator(data)) - } - "minecraft:daylight_detector" => { - let data = DaylightDetectorData::from_map(props)?; - Some(Block::DaylightDetector(data)) - } - "minecraft:redstone_block" => Some(Block::RedstoneBlock), - "minecraft:nether_quartz_ore" => Some(Block::NetherQuartzOre), - "minecraft:hopper" => { - let data = HopperData::from_map(props)?; - Some(Block::Hopper(data)) - } - "minecraft:quartz_block" => Some(Block::QuartzBlock), - "minecraft:chiseled_quartz_block" => Some(Block::ChiseledQuartzBlock), - "minecraft:quartz_pillar" => { - let data = QuartzPillarData::from_map(props)?; - Some(Block::QuartzPillar(data)) - } - "minecraft:quartz_stairs" => { - let data = QuartzStairsData::from_map(props)?; - Some(Block::QuartzStairs(data)) - } - "minecraft:activator_rail" => { - let data = ActivatorRailData::from_map(props)?; - Some(Block::ActivatorRail(data)) - } - "minecraft:dropper" => { - let data = DropperData::from_map(props)?; - Some(Block::Dropper(data)) - } - "minecraft:white_terracotta" => Some(Block::WhiteTerracotta), - "minecraft:orange_terracotta" => Some(Block::OrangeTerracotta), - "minecraft:magenta_terracotta" => Some(Block::MagentaTerracotta), - "minecraft:light_blue_terracotta" => Some(Block::LightBlueTerracotta), - "minecraft:yellow_terracotta" => Some(Block::YellowTerracotta), - "minecraft:lime_terracotta" => Some(Block::LimeTerracotta), - "minecraft:pink_terracotta" => Some(Block::PinkTerracotta), - "minecraft:gray_terracotta" => Some(Block::GrayTerracotta), - "minecraft:light_gray_terracotta" => Some(Block::LightGrayTerracotta), - "minecraft:cyan_terracotta" => Some(Block::CyanTerracotta), - "minecraft:purple_terracotta" => Some(Block::PurpleTerracotta), - "minecraft:blue_terracotta" => Some(Block::BlueTerracotta), - "minecraft:brown_terracotta" => Some(Block::BrownTerracotta), - "minecraft:green_terracotta" => Some(Block::GreenTerracotta), - "minecraft:red_terracotta" => Some(Block::RedTerracotta), - "minecraft:black_terracotta" => Some(Block::BlackTerracotta), - "minecraft:white_stained_glass_pane" => { - let data = WhiteStainedGlassPaneData::from_map(props)?; - Some(Block::WhiteStainedGlassPane(data)) - } - "minecraft:orange_stained_glass_pane" => { - let data = OrangeStainedGlassPaneData::from_map(props)?; - Some(Block::OrangeStainedGlassPane(data)) - } - "minecraft:magenta_stained_glass_pane" => { - let data = MagentaStainedGlassPaneData::from_map(props)?; - Some(Block::MagentaStainedGlassPane(data)) - } - "minecraft:light_blue_stained_glass_pane" => { - let data = LightBlueStainedGlassPaneData::from_map(props)?; - Some(Block::LightBlueStainedGlassPane(data)) - } - "minecraft:yellow_stained_glass_pane" => { - let data = YellowStainedGlassPaneData::from_map(props)?; - Some(Block::YellowStainedGlassPane(data)) - } - "minecraft:lime_stained_glass_pane" => { - let data = LimeStainedGlassPaneData::from_map(props)?; - Some(Block::LimeStainedGlassPane(data)) - } - "minecraft:pink_stained_glass_pane" => { - let data = PinkStainedGlassPaneData::from_map(props)?; - Some(Block::PinkStainedGlassPane(data)) - } - "minecraft:gray_stained_glass_pane" => { - let data = GrayStainedGlassPaneData::from_map(props)?; - Some(Block::GrayStainedGlassPane(data)) - } - "minecraft:light_gray_stained_glass_pane" => { - let data = LightGrayStainedGlassPaneData::from_map(props)?; - Some(Block::LightGrayStainedGlassPane(data)) - } - "minecraft:cyan_stained_glass_pane" => { - let data = CyanStainedGlassPaneData::from_map(props)?; - Some(Block::CyanStainedGlassPane(data)) - } - "minecraft:purple_stained_glass_pane" => { - let data = PurpleStainedGlassPaneData::from_map(props)?; - Some(Block::PurpleStainedGlassPane(data)) - } - "minecraft:blue_stained_glass_pane" => { - let data = BlueStainedGlassPaneData::from_map(props)?; - Some(Block::BlueStainedGlassPane(data)) - } - "minecraft:brown_stained_glass_pane" => { - let data = BrownStainedGlassPaneData::from_map(props)?; - Some(Block::BrownStainedGlassPane(data)) - } - "minecraft:green_stained_glass_pane" => { - let data = GreenStainedGlassPaneData::from_map(props)?; - Some(Block::GreenStainedGlassPane(data)) - } - "minecraft:red_stained_glass_pane" => { - let data = RedStainedGlassPaneData::from_map(props)?; - Some(Block::RedStainedGlassPane(data)) - } - "minecraft:black_stained_glass_pane" => { - let data = BlackStainedGlassPaneData::from_map(props)?; - Some(Block::BlackStainedGlassPane(data)) - } - "minecraft:acacia_stairs" => { - let data = AcaciaStairsData::from_map(props)?; - Some(Block::AcaciaStairs(data)) - } - "minecraft:dark_oak_stairs" => { - let data = DarkOakStairsData::from_map(props)?; - Some(Block::DarkOakStairs(data)) - } - "minecraft:slime_block" => Some(Block::SlimeBlock), - "minecraft:barrier" => Some(Block::Barrier), - "minecraft:iron_trapdoor" => { - let data = IronTrapdoorData::from_map(props)?; - Some(Block::IronTrapdoor(data)) - } - "minecraft:prismarine" => Some(Block::Prismarine), - "minecraft:prismarine_bricks" => Some(Block::PrismarineBricks), - "minecraft:dark_prismarine" => Some(Block::DarkPrismarine), - "minecraft:prismarine_stairs" => { - let data = PrismarineStairsData::from_map(props)?; - Some(Block::PrismarineStairs(data)) - } - "minecraft:prismarine_brick_stairs" => { - let data = PrismarineBrickStairsData::from_map(props)?; - Some(Block::PrismarineBrickStairs(data)) - } - "minecraft:dark_prismarine_stairs" => { - let data = DarkPrismarineStairsData::from_map(props)?; - Some(Block::DarkPrismarineStairs(data)) - } - "minecraft:prismarine_slab" => { - let data = PrismarineSlabData::from_map(props)?; - Some(Block::PrismarineSlab(data)) - } - "minecraft:prismarine_brick_slab" => { - let data = PrismarineBrickSlabData::from_map(props)?; - Some(Block::PrismarineBrickSlab(data)) - } - "minecraft:dark_prismarine_slab" => { - let data = DarkPrismarineSlabData::from_map(props)?; - Some(Block::DarkPrismarineSlab(data)) - } - "minecraft:sea_lantern" => Some(Block::SeaLantern), - "minecraft:hay_block" => { - let data = HayBlockData::from_map(props)?; - Some(Block::HayBlock(data)) - } - "minecraft:white_carpet" => Some(Block::WhiteCarpet), - "minecraft:orange_carpet" => Some(Block::OrangeCarpet), - "minecraft:magenta_carpet" => Some(Block::MagentaCarpet), - "minecraft:light_blue_carpet" => Some(Block::LightBlueCarpet), - "minecraft:yellow_carpet" => Some(Block::YellowCarpet), - "minecraft:lime_carpet" => Some(Block::LimeCarpet), - "minecraft:pink_carpet" => Some(Block::PinkCarpet), - "minecraft:gray_carpet" => Some(Block::GrayCarpet), - "minecraft:light_gray_carpet" => Some(Block::LightGrayCarpet), - "minecraft:cyan_carpet" => Some(Block::CyanCarpet), - "minecraft:purple_carpet" => Some(Block::PurpleCarpet), - "minecraft:blue_carpet" => Some(Block::BlueCarpet), - "minecraft:brown_carpet" => Some(Block::BrownCarpet), - "minecraft:green_carpet" => Some(Block::GreenCarpet), - "minecraft:red_carpet" => Some(Block::RedCarpet), - "minecraft:black_carpet" => Some(Block::BlackCarpet), - "minecraft:terracotta" => Some(Block::Terracotta), - "minecraft:coal_block" => Some(Block::CoalBlock), - "minecraft:packed_ice" => Some(Block::PackedIce), - "minecraft:sunflower" => { - let data = SunflowerData::from_map(props)?; - Some(Block::Sunflower(data)) - } - "minecraft:lilac" => { - let data = LilacData::from_map(props)?; - Some(Block::Lilac(data)) - } - "minecraft:rose_bush" => { - let data = RoseBushData::from_map(props)?; - Some(Block::RoseBush(data)) - } - "minecraft:peony" => { - let data = PeonyData::from_map(props)?; - Some(Block::Peony(data)) - } - "minecraft:tall_grass" => { - let data = TallGrassData::from_map(props)?; - Some(Block::TallGrass(data)) - } - "minecraft:large_fern" => { - let data = LargeFernData::from_map(props)?; - Some(Block::LargeFern(data)) - } - "minecraft:white_banner" => { - let data = WhiteBannerData::from_map(props)?; - Some(Block::WhiteBanner(data)) - } - "minecraft:orange_banner" => { - let data = OrangeBannerData::from_map(props)?; - Some(Block::OrangeBanner(data)) - } - "minecraft:magenta_banner" => { - let data = MagentaBannerData::from_map(props)?; - Some(Block::MagentaBanner(data)) - } - "minecraft:light_blue_banner" => { - let data = LightBlueBannerData::from_map(props)?; - Some(Block::LightBlueBanner(data)) - } - "minecraft:yellow_banner" => { - let data = YellowBannerData::from_map(props)?; - Some(Block::YellowBanner(data)) - } - "minecraft:lime_banner" => { - let data = LimeBannerData::from_map(props)?; - Some(Block::LimeBanner(data)) - } - "minecraft:pink_banner" => { - let data = PinkBannerData::from_map(props)?; - Some(Block::PinkBanner(data)) - } - "minecraft:gray_banner" => { - let data = GrayBannerData::from_map(props)?; - Some(Block::GrayBanner(data)) - } - "minecraft:light_gray_banner" => { - let data = LightGrayBannerData::from_map(props)?; - Some(Block::LightGrayBanner(data)) - } - "minecraft:cyan_banner" => { - let data = CyanBannerData::from_map(props)?; - Some(Block::CyanBanner(data)) - } - "minecraft:purple_banner" => { - let data = PurpleBannerData::from_map(props)?; - Some(Block::PurpleBanner(data)) - } - "minecraft:blue_banner" => { - let data = BlueBannerData::from_map(props)?; - Some(Block::BlueBanner(data)) - } - "minecraft:brown_banner" => { - let data = BrownBannerData::from_map(props)?; - Some(Block::BrownBanner(data)) - } - "minecraft:green_banner" => { - let data = GreenBannerData::from_map(props)?; - Some(Block::GreenBanner(data)) - } - "minecraft:red_banner" => { - let data = RedBannerData::from_map(props)?; - Some(Block::RedBanner(data)) - } - "minecraft:black_banner" => { - let data = BlackBannerData::from_map(props)?; - Some(Block::BlackBanner(data)) - } - "minecraft:white_wall_banner" => { - let data = WhiteWallBannerData::from_map(props)?; - Some(Block::WhiteWallBanner(data)) - } - "minecraft:orange_wall_banner" => { - let data = OrangeWallBannerData::from_map(props)?; - Some(Block::OrangeWallBanner(data)) - } - "minecraft:magenta_wall_banner" => { - let data = MagentaWallBannerData::from_map(props)?; - Some(Block::MagentaWallBanner(data)) - } - "minecraft:light_blue_wall_banner" => { - let data = LightBlueWallBannerData::from_map(props)?; - Some(Block::LightBlueWallBanner(data)) - } - "minecraft:yellow_wall_banner" => { - let data = YellowWallBannerData::from_map(props)?; - Some(Block::YellowWallBanner(data)) - } - "minecraft:lime_wall_banner" => { - let data = LimeWallBannerData::from_map(props)?; - Some(Block::LimeWallBanner(data)) - } - "minecraft:pink_wall_banner" => { - let data = PinkWallBannerData::from_map(props)?; - Some(Block::PinkWallBanner(data)) - } - "minecraft:gray_wall_banner" => { - let data = GrayWallBannerData::from_map(props)?; - Some(Block::GrayWallBanner(data)) - } - "minecraft:light_gray_wall_banner" => { - let data = LightGrayWallBannerData::from_map(props)?; - Some(Block::LightGrayWallBanner(data)) - } - "minecraft:cyan_wall_banner" => { - let data = CyanWallBannerData::from_map(props)?; - Some(Block::CyanWallBanner(data)) - } - "minecraft:purple_wall_banner" => { - let data = PurpleWallBannerData::from_map(props)?; - Some(Block::PurpleWallBanner(data)) - } - "minecraft:blue_wall_banner" => { - let data = BlueWallBannerData::from_map(props)?; - Some(Block::BlueWallBanner(data)) - } - "minecraft:brown_wall_banner" => { - let data = BrownWallBannerData::from_map(props)?; - Some(Block::BrownWallBanner(data)) - } - "minecraft:green_wall_banner" => { - let data = GreenWallBannerData::from_map(props)?; - Some(Block::GreenWallBanner(data)) - } - "minecraft:red_wall_banner" => { - let data = RedWallBannerData::from_map(props)?; - Some(Block::RedWallBanner(data)) - } - "minecraft:black_wall_banner" => { - let data = BlackWallBannerData::from_map(props)?; - Some(Block::BlackWallBanner(data)) - } - "minecraft:red_sandstone" => Some(Block::RedSandstone), - "minecraft:chiseled_red_sandstone" => Some(Block::ChiseledRedSandstone), - "minecraft:cut_red_sandstone" => Some(Block::CutRedSandstone), - "minecraft:red_sandstone_stairs" => { - let data = RedSandstoneStairsData::from_map(props)?; - Some(Block::RedSandstoneStairs(data)) - } - "minecraft:oak_slab" => { - let data = OakSlabData::from_map(props)?; - Some(Block::OakSlab(data)) - } - "minecraft:spruce_slab" => { - let data = SpruceSlabData::from_map(props)?; - Some(Block::SpruceSlab(data)) - } - "minecraft:birch_slab" => { - let data = BirchSlabData::from_map(props)?; - Some(Block::BirchSlab(data)) - } - "minecraft:jungle_slab" => { - let data = JungleSlabData::from_map(props)?; - Some(Block::JungleSlab(data)) - } - "minecraft:acacia_slab" => { - let data = AcaciaSlabData::from_map(props)?; - Some(Block::AcaciaSlab(data)) - } - "minecraft:dark_oak_slab" => { - let data = DarkOakSlabData::from_map(props)?; - Some(Block::DarkOakSlab(data)) - } - "minecraft:stone_slab" => { - let data = StoneSlabData::from_map(props)?; - Some(Block::StoneSlab(data)) - } - "minecraft:sandstone_slab" => { - let data = SandstoneSlabData::from_map(props)?; - Some(Block::SandstoneSlab(data)) - } - "minecraft:petrified_oak_slab" => { - let data = PetrifiedOakSlabData::from_map(props)?; - Some(Block::PetrifiedOakSlab(data)) - } - "minecraft:cobblestone_slab" => { - let data = CobblestoneSlabData::from_map(props)?; - Some(Block::CobblestoneSlab(data)) - } - "minecraft:brick_slab" => { - let data = BrickSlabData::from_map(props)?; - Some(Block::BrickSlab(data)) - } - "minecraft:stone_brick_slab" => { - let data = StoneBrickSlabData::from_map(props)?; - Some(Block::StoneBrickSlab(data)) - } - "minecraft:nether_brick_slab" => { - let data = NetherBrickSlabData::from_map(props)?; - Some(Block::NetherBrickSlab(data)) - } - "minecraft:quartz_slab" => { - let data = QuartzSlabData::from_map(props)?; - Some(Block::QuartzSlab(data)) - } - "minecraft:red_sandstone_slab" => { - let data = RedSandstoneSlabData::from_map(props)?; - Some(Block::RedSandstoneSlab(data)) - } - "minecraft:purpur_slab" => { - let data = PurpurSlabData::from_map(props)?; - Some(Block::PurpurSlab(data)) - } - "minecraft:smooth_stone" => Some(Block::SmoothStone), - "minecraft:smooth_sandstone" => Some(Block::SmoothSandstone), - "minecraft:smooth_quartz" => Some(Block::SmoothQuartz), - "minecraft:smooth_red_sandstone" => Some(Block::SmoothRedSandstone), - "minecraft:spruce_fence_gate" => { - let data = SpruceFenceGateData::from_map(props)?; - Some(Block::SpruceFenceGate(data)) - } - "minecraft:birch_fence_gate" => { - let data = BirchFenceGateData::from_map(props)?; - Some(Block::BirchFenceGate(data)) - } - "minecraft:jungle_fence_gate" => { - let data = JungleFenceGateData::from_map(props)?; - Some(Block::JungleFenceGate(data)) - } - "minecraft:acacia_fence_gate" => { - let data = AcaciaFenceGateData::from_map(props)?; - Some(Block::AcaciaFenceGate(data)) - } - "minecraft:dark_oak_fence_gate" => { - let data = DarkOakFenceGateData::from_map(props)?; - Some(Block::DarkOakFenceGate(data)) - } - "minecraft:spruce_fence" => { - let data = SpruceFenceData::from_map(props)?; - Some(Block::SpruceFence(data)) - } - "minecraft:birch_fence" => { - let data = BirchFenceData::from_map(props)?; - Some(Block::BirchFence(data)) - } - "minecraft:jungle_fence" => { - let data = JungleFenceData::from_map(props)?; - Some(Block::JungleFence(data)) - } - "minecraft:acacia_fence" => { - let data = AcaciaFenceData::from_map(props)?; - Some(Block::AcaciaFence(data)) - } - "minecraft:dark_oak_fence" => { - let data = DarkOakFenceData::from_map(props)?; - Some(Block::DarkOakFence(data)) - } - "minecraft:spruce_door" => { - let data = SpruceDoorData::from_map(props)?; - Some(Block::SpruceDoor(data)) - } - "minecraft:birch_door" => { - let data = BirchDoorData::from_map(props)?; - Some(Block::BirchDoor(data)) - } - "minecraft:jungle_door" => { - let data = JungleDoorData::from_map(props)?; - Some(Block::JungleDoor(data)) - } - "minecraft:acacia_door" => { - let data = AcaciaDoorData::from_map(props)?; - Some(Block::AcaciaDoor(data)) - } - "minecraft:dark_oak_door" => { - let data = DarkOakDoorData::from_map(props)?; - Some(Block::DarkOakDoor(data)) - } - "minecraft:end_rod" => { - let data = EndRodData::from_map(props)?; - Some(Block::EndRod(data)) - } - "minecraft:chorus_plant" => { - let data = ChorusPlantData::from_map(props)?; - Some(Block::ChorusPlant(data)) - } - "minecraft:chorus_flower" => { - let data = ChorusFlowerData::from_map(props)?; - Some(Block::ChorusFlower(data)) - } - "minecraft:purpur_block" => Some(Block::PurpurBlock), - "minecraft:purpur_pillar" => { - let data = PurpurPillarData::from_map(props)?; - Some(Block::PurpurPillar(data)) - } - "minecraft:purpur_stairs" => { - let data = PurpurStairsData::from_map(props)?; - Some(Block::PurpurStairs(data)) - } - "minecraft:end_stone_bricks" => Some(Block::EndStoneBricks), - "minecraft:beetroots" => { - let data = BeetrootsData::from_map(props)?; - Some(Block::Beetroots(data)) - } - "minecraft:grass_path" => Some(Block::GrassPath), - "minecraft:end_gateway" => Some(Block::EndGateway), - "minecraft:repeating_command_block" => { - let data = RepeatingCommandBlockData::from_map(props)?; - Some(Block::RepeatingCommandBlock(data)) - } - "minecraft:chain_command_block" => { - let data = ChainCommandBlockData::from_map(props)?; - Some(Block::ChainCommandBlock(data)) - } - "minecraft:frosted_ice" => { - let data = FrostedIceData::from_map(props)?; - Some(Block::FrostedIce(data)) - } - "minecraft:magma_block" => Some(Block::MagmaBlock), - "minecraft:nether_wart_block" => Some(Block::NetherWartBlock), - "minecraft:red_nether_bricks" => Some(Block::RedNetherBricks), - "minecraft:bone_block" => { - let data = BoneBlockData::from_map(props)?; - Some(Block::BoneBlock(data)) - } - "minecraft:structure_void" => Some(Block::StructureVoid), - "minecraft:observer" => { - let data = ObserverData::from_map(props)?; - Some(Block::Observer(data)) - } - "minecraft:shulker_box" => { - let data = ShulkerBoxData::from_map(props)?; - Some(Block::ShulkerBox(data)) - } - "minecraft:white_shulker_box" => { - let data = WhiteShulkerBoxData::from_map(props)?; - Some(Block::WhiteShulkerBox(data)) - } - "minecraft:orange_shulker_box" => { - let data = OrangeShulkerBoxData::from_map(props)?; - Some(Block::OrangeShulkerBox(data)) - } - "minecraft:magenta_shulker_box" => { - let data = MagentaShulkerBoxData::from_map(props)?; - Some(Block::MagentaShulkerBox(data)) - } - "minecraft:light_blue_shulker_box" => { - let data = LightBlueShulkerBoxData::from_map(props)?; - Some(Block::LightBlueShulkerBox(data)) - } - "minecraft:yellow_shulker_box" => { - let data = YellowShulkerBoxData::from_map(props)?; - Some(Block::YellowShulkerBox(data)) - } - "minecraft:lime_shulker_box" => { - let data = LimeShulkerBoxData::from_map(props)?; - Some(Block::LimeShulkerBox(data)) - } - "minecraft:pink_shulker_box" => { - let data = PinkShulkerBoxData::from_map(props)?; - Some(Block::PinkShulkerBox(data)) - } - "minecraft:gray_shulker_box" => { - let data = GrayShulkerBoxData::from_map(props)?; - Some(Block::GrayShulkerBox(data)) - } - "minecraft:light_gray_shulker_box" => { - let data = LightGrayShulkerBoxData::from_map(props)?; - Some(Block::LightGrayShulkerBox(data)) - } - "minecraft:cyan_shulker_box" => { - let data = CyanShulkerBoxData::from_map(props)?; - Some(Block::CyanShulkerBox(data)) - } - "minecraft:purple_shulker_box" => { - let data = PurpleShulkerBoxData::from_map(props)?; - Some(Block::PurpleShulkerBox(data)) - } - "minecraft:blue_shulker_box" => { - let data = BlueShulkerBoxData::from_map(props)?; - Some(Block::BlueShulkerBox(data)) - } - "minecraft:brown_shulker_box" => { - let data = BrownShulkerBoxData::from_map(props)?; - Some(Block::BrownShulkerBox(data)) - } - "minecraft:green_shulker_box" => { - let data = GreenShulkerBoxData::from_map(props)?; - Some(Block::GreenShulkerBox(data)) - } - "minecraft:red_shulker_box" => { - let data = RedShulkerBoxData::from_map(props)?; - Some(Block::RedShulkerBox(data)) - } - "minecraft:black_shulker_box" => { - let data = BlackShulkerBoxData::from_map(props)?; - Some(Block::BlackShulkerBox(data)) - } - "minecraft:white_glazed_terracotta" => { - let data = WhiteGlazedTerracottaData::from_map(props)?; - Some(Block::WhiteGlazedTerracotta(data)) - } - "minecraft:orange_glazed_terracotta" => { - let data = OrangeGlazedTerracottaData::from_map(props)?; - Some(Block::OrangeGlazedTerracotta(data)) - } - "minecraft:magenta_glazed_terracotta" => { - let data = MagentaGlazedTerracottaData::from_map(props)?; - Some(Block::MagentaGlazedTerracotta(data)) - } - "minecraft:light_blue_glazed_terracotta" => { - let data = LightBlueGlazedTerracottaData::from_map(props)?; - Some(Block::LightBlueGlazedTerracotta(data)) - } - "minecraft:yellow_glazed_terracotta" => { - let data = YellowGlazedTerracottaData::from_map(props)?; - Some(Block::YellowGlazedTerracotta(data)) - } - "minecraft:lime_glazed_terracotta" => { - let data = LimeGlazedTerracottaData::from_map(props)?; - Some(Block::LimeGlazedTerracotta(data)) - } - "minecraft:pink_glazed_terracotta" => { - let data = PinkGlazedTerracottaData::from_map(props)?; - Some(Block::PinkGlazedTerracotta(data)) - } - "minecraft:gray_glazed_terracotta" => { - let data = GrayGlazedTerracottaData::from_map(props)?; - Some(Block::GrayGlazedTerracotta(data)) - } - "minecraft:light_gray_glazed_terracotta" => { - let data = LightGrayGlazedTerracottaData::from_map(props)?; - Some(Block::LightGrayGlazedTerracotta(data)) - } - "minecraft:cyan_glazed_terracotta" => { - let data = CyanGlazedTerracottaData::from_map(props)?; - Some(Block::CyanGlazedTerracotta(data)) - } - "minecraft:purple_glazed_terracotta" => { - let data = PurpleGlazedTerracottaData::from_map(props)?; - Some(Block::PurpleGlazedTerracotta(data)) - } - "minecraft:blue_glazed_terracotta" => { - let data = BlueGlazedTerracottaData::from_map(props)?; - Some(Block::BlueGlazedTerracotta(data)) - } - "minecraft:brown_glazed_terracotta" => { - let data = BrownGlazedTerracottaData::from_map(props)?; - Some(Block::BrownGlazedTerracotta(data)) - } - "minecraft:green_glazed_terracotta" => { - let data = GreenGlazedTerracottaData::from_map(props)?; - Some(Block::GreenGlazedTerracotta(data)) - } - "minecraft:red_glazed_terracotta" => { - let data = RedGlazedTerracottaData::from_map(props)?; - Some(Block::RedGlazedTerracotta(data)) - } - "minecraft:black_glazed_terracotta" => { - let data = BlackGlazedTerracottaData::from_map(props)?; - Some(Block::BlackGlazedTerracotta(data)) - } - "minecraft:white_concrete" => Some(Block::WhiteConcrete), - "minecraft:orange_concrete" => Some(Block::OrangeConcrete), - "minecraft:magenta_concrete" => Some(Block::MagentaConcrete), - "minecraft:light_blue_concrete" => Some(Block::LightBlueConcrete), - "minecraft:yellow_concrete" => Some(Block::YellowConcrete), - "minecraft:lime_concrete" => Some(Block::LimeConcrete), - "minecraft:pink_concrete" => Some(Block::PinkConcrete), - "minecraft:gray_concrete" => Some(Block::GrayConcrete), - "minecraft:light_gray_concrete" => Some(Block::LightGrayConcrete), - "minecraft:cyan_concrete" => Some(Block::CyanConcrete), - "minecraft:purple_concrete" => Some(Block::PurpleConcrete), - "minecraft:blue_concrete" => Some(Block::BlueConcrete), - "minecraft:brown_concrete" => Some(Block::BrownConcrete), - "minecraft:green_concrete" => Some(Block::GreenConcrete), - "minecraft:red_concrete" => Some(Block::RedConcrete), - "minecraft:black_concrete" => Some(Block::BlackConcrete), - "minecraft:white_concrete_powder" => Some(Block::WhiteConcretePowder), - "minecraft:orange_concrete_powder" => Some(Block::OrangeConcretePowder), - "minecraft:magenta_concrete_powder" => Some(Block::MagentaConcretePowder), - "minecraft:light_blue_concrete_powder" => Some(Block::LightBlueConcretePowder), - "minecraft:yellow_concrete_powder" => Some(Block::YellowConcretePowder), - "minecraft:lime_concrete_powder" => Some(Block::LimeConcretePowder), - "minecraft:pink_concrete_powder" => Some(Block::PinkConcretePowder), - "minecraft:gray_concrete_powder" => Some(Block::GrayConcretePowder), - "minecraft:light_gray_concrete_powder" => Some(Block::LightGrayConcretePowder), - "minecraft:cyan_concrete_powder" => Some(Block::CyanConcretePowder), - "minecraft:purple_concrete_powder" => Some(Block::PurpleConcretePowder), - "minecraft:blue_concrete_powder" => Some(Block::BlueConcretePowder), - "minecraft:brown_concrete_powder" => Some(Block::BrownConcretePowder), - "minecraft:green_concrete_powder" => Some(Block::GreenConcretePowder), - "minecraft:red_concrete_powder" => Some(Block::RedConcretePowder), - "minecraft:black_concrete_powder" => Some(Block::BlackConcretePowder), - "minecraft:kelp" => { - let data = KelpData::from_map(props)?; - Some(Block::Kelp(data)) - } - "minecraft:kelp_plant" => Some(Block::KelpPlant), - "minecraft:dried_kelp_block" => Some(Block::DriedKelpBlock), - "minecraft:turtle_egg" => { - let data = TurtleEggData::from_map(props)?; - Some(Block::TurtleEgg(data)) - } - "minecraft:dead_tube_coral_block" => Some(Block::DeadTubeCoralBlock), - "minecraft:dead_brain_coral_block" => Some(Block::DeadBrainCoralBlock), - "minecraft:dead_bubble_coral_block" => Some(Block::DeadBubbleCoralBlock), - "minecraft:dead_fire_coral_block" => Some(Block::DeadFireCoralBlock), - "minecraft:dead_horn_coral_block" => Some(Block::DeadHornCoralBlock), - "minecraft:tube_coral_block" => Some(Block::TubeCoralBlock), - "minecraft:brain_coral_block" => Some(Block::BrainCoralBlock), - "minecraft:bubble_coral_block" => Some(Block::BubbleCoralBlock), - "minecraft:fire_coral_block" => Some(Block::FireCoralBlock), - "minecraft:horn_coral_block" => Some(Block::HornCoralBlock), - "minecraft:dead_tube_coral" => { - let data = DeadTubeCoralData::from_map(props)?; - Some(Block::DeadTubeCoral(data)) - } - "minecraft:dead_brain_coral" => { - let data = DeadBrainCoralData::from_map(props)?; - Some(Block::DeadBrainCoral(data)) - } - "minecraft:dead_bubble_coral" => { - let data = DeadBubbleCoralData::from_map(props)?; - Some(Block::DeadBubbleCoral(data)) - } - "minecraft:dead_fire_coral" => { - let data = DeadFireCoralData::from_map(props)?; - Some(Block::DeadFireCoral(data)) - } - "minecraft:dead_horn_coral" => { - let data = DeadHornCoralData::from_map(props)?; - Some(Block::DeadHornCoral(data)) - } - "minecraft:tube_coral" => { - let data = TubeCoralData::from_map(props)?; - Some(Block::TubeCoral(data)) - } - "minecraft:brain_coral" => { - let data = BrainCoralData::from_map(props)?; - Some(Block::BrainCoral(data)) - } - "minecraft:bubble_coral" => { - let data = BubbleCoralData::from_map(props)?; - Some(Block::BubbleCoral(data)) - } - "minecraft:fire_coral" => { - let data = FireCoralData::from_map(props)?; - Some(Block::FireCoral(data)) - } - "minecraft:horn_coral" => { - let data = HornCoralData::from_map(props)?; - Some(Block::HornCoral(data)) - } - "minecraft:dead_tube_coral_wall_fan" => { - let data = DeadTubeCoralWallFanData::from_map(props)?; - Some(Block::DeadTubeCoralWallFan(data)) - } - "minecraft:dead_brain_coral_wall_fan" => { - let data = DeadBrainCoralWallFanData::from_map(props)?; - Some(Block::DeadBrainCoralWallFan(data)) - } - "minecraft:dead_bubble_coral_wall_fan" => { - let data = DeadBubbleCoralWallFanData::from_map(props)?; - Some(Block::DeadBubbleCoralWallFan(data)) - } - "minecraft:dead_fire_coral_wall_fan" => { - let data = DeadFireCoralWallFanData::from_map(props)?; - Some(Block::DeadFireCoralWallFan(data)) - } - "minecraft:dead_horn_coral_wall_fan" => { - let data = DeadHornCoralWallFanData::from_map(props)?; - Some(Block::DeadHornCoralWallFan(data)) - } - "minecraft:tube_coral_wall_fan" => { - let data = TubeCoralWallFanData::from_map(props)?; - Some(Block::TubeCoralWallFan(data)) - } - "minecraft:brain_coral_wall_fan" => { - let data = BrainCoralWallFanData::from_map(props)?; - Some(Block::BrainCoralWallFan(data)) - } - "minecraft:bubble_coral_wall_fan" => { - let data = BubbleCoralWallFanData::from_map(props)?; - Some(Block::BubbleCoralWallFan(data)) - } - "minecraft:fire_coral_wall_fan" => { - let data = FireCoralWallFanData::from_map(props)?; - Some(Block::FireCoralWallFan(data)) - } - "minecraft:horn_coral_wall_fan" => { - let data = HornCoralWallFanData::from_map(props)?; - Some(Block::HornCoralWallFan(data)) - } - "minecraft:dead_tube_coral_fan" => { - let data = DeadTubeCoralFanData::from_map(props)?; - Some(Block::DeadTubeCoralFan(data)) - } - "minecraft:dead_brain_coral_fan" => { - let data = DeadBrainCoralFanData::from_map(props)?; - Some(Block::DeadBrainCoralFan(data)) - } - "minecraft:dead_bubble_coral_fan" => { - let data = DeadBubbleCoralFanData::from_map(props)?; - Some(Block::DeadBubbleCoralFan(data)) - } - "minecraft:dead_fire_coral_fan" => { - let data = DeadFireCoralFanData::from_map(props)?; - Some(Block::DeadFireCoralFan(data)) - } - "minecraft:dead_horn_coral_fan" => { - let data = DeadHornCoralFanData::from_map(props)?; - Some(Block::DeadHornCoralFan(data)) - } - "minecraft:tube_coral_fan" => { - let data = TubeCoralFanData::from_map(props)?; - Some(Block::TubeCoralFan(data)) - } - "minecraft:brain_coral_fan" => { - let data = BrainCoralFanData::from_map(props)?; - Some(Block::BrainCoralFan(data)) - } - "minecraft:bubble_coral_fan" => { - let data = BubbleCoralFanData::from_map(props)?; - Some(Block::BubbleCoralFan(data)) - } - "minecraft:fire_coral_fan" => { - let data = FireCoralFanData::from_map(props)?; - Some(Block::FireCoralFan(data)) - } - "minecraft:horn_coral_fan" => { - let data = HornCoralFanData::from_map(props)?; - Some(Block::HornCoralFan(data)) - } - "minecraft:sea_pickle" => { - let data = SeaPickleData::from_map(props)?; - Some(Block::SeaPickle(data)) - } - "minecraft:blue_ice" => Some(Block::BlueIce), - "minecraft:conduit" => { - let data = ConduitData::from_map(props)?; - Some(Block::Conduit(data)) - } - "minecraft:void_air" => Some(Block::VoidAir), - "minecraft:cave_air" => Some(Block::CaveAir), - "minecraft:bubble_column" => { - let data = BubbleColumnData::from_map(props)?; - Some(Block::BubbleColumn(data)) - } - "minecraft:structure_block" => { - let data = StructureBlockData::from_map(props)?; - Some(Block::StructureBlock(data)) - } - _ => None, - } - } - pub fn to_name_and_props(&self) -> (&'static str, Vec<(&'static str, String)>) { - let mut props = vec![]; - let name = match self { - Block::Air => "minecraft:air", - Block::Stone => "minecraft:stone", - Block::Granite => "minecraft:granite", - Block::PolishedGranite => "minecraft:polished_granite", - Block::Diorite => "minecraft:diorite", - Block::PolishedDiorite => "minecraft:polished_diorite", - Block::Andesite => "minecraft:andesite", - Block::PolishedAndesite => "minecraft:polished_andesite", - Block::GrassBlock(data) => { - props.push(("snowy", data.snowy.to_snake_case())); - "minecraft:grass_block" - } - Block::Dirt => "minecraft:dirt", - Block::CoarseDirt => "minecraft:coarse_dirt", - Block::Podzol(data) => { - props.push(("snowy", data.snowy.to_snake_case())); - "minecraft:podzol" - } - Block::Cobblestone => "minecraft:cobblestone", - Block::OakPlanks => "minecraft:oak_planks", - Block::SprucePlanks => "minecraft:spruce_planks", - Block::BirchPlanks => "minecraft:birch_planks", - Block::JunglePlanks => "minecraft:jungle_planks", - Block::AcaciaPlanks => "minecraft:acacia_planks", - Block::DarkOakPlanks => "minecraft:dark_oak_planks", - Block::OakSapling(data) => { - props.push(("stage", data.stage.to_snake_case())); - "minecraft:oak_sapling" - } - Block::SpruceSapling(data) => { - props.push(("stage", data.stage.to_snake_case())); - "minecraft:spruce_sapling" - } - Block::BirchSapling(data) => { - props.push(("stage", data.stage.to_snake_case())); - "minecraft:birch_sapling" - } - Block::JungleSapling(data) => { - props.push(("stage", data.stage.to_snake_case())); - "minecraft:jungle_sapling" - } - Block::AcaciaSapling(data) => { - props.push(("stage", data.stage.to_snake_case())); - "minecraft:acacia_sapling" - } - Block::DarkOakSapling(data) => { - props.push(("stage", data.stage.to_snake_case())); - "minecraft:dark_oak_sapling" - } - Block::Bedrock => "minecraft:bedrock", - Block::Water(data) => { - props.push(("level", data.level.to_snake_case())); - "minecraft:water" - } - Block::Lava(data) => { - props.push(("level", data.level.to_snake_case())); - "minecraft:lava" - } - Block::Sand => "minecraft:sand", - Block::RedSand => "minecraft:red_sand", - Block::Gravel => "minecraft:gravel", - Block::GoldOre => "minecraft:gold_ore", - Block::IronOre => "minecraft:iron_ore", - Block::CoalOre => "minecraft:coal_ore", - Block::OakLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:oak_log" - } - Block::SpruceLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:spruce_log" - } - Block::BirchLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:birch_log" - } - Block::JungleLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:jungle_log" - } - Block::AcaciaLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:acacia_log" - } - Block::DarkOakLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:dark_oak_log" - } - Block::StrippedSpruceLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_spruce_log" - } - Block::StrippedBirchLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_birch_log" - } - Block::StrippedJungleLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_jungle_log" - } - Block::StrippedAcaciaLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_acacia_log" - } - Block::StrippedDarkOakLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_dark_oak_log" - } - Block::StrippedOakLog(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_oak_log" - } - Block::OakWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:oak_wood" - } - Block::SpruceWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:spruce_wood" - } - Block::BirchWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:birch_wood" - } - Block::JungleWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:jungle_wood" - } - Block::AcaciaWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:acacia_wood" - } - Block::DarkOakWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:dark_oak_wood" - } - Block::StrippedOakWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_oak_wood" - } - Block::StrippedSpruceWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_spruce_wood" - } - Block::StrippedBirchWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_birch_wood" - } - Block::StrippedJungleWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_jungle_wood" - } - Block::StrippedAcaciaWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_acacia_wood" - } - Block::StrippedDarkOakWood(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:stripped_dark_oak_wood" - } - Block::OakLeaves(data) => { - props.push(("distance", data.distance.to_snake_case())); - props.push(("persistent", data.persistent.to_snake_case())); - "minecraft:oak_leaves" - } - Block::SpruceLeaves(data) => { - props.push(("persistent", data.persistent.to_snake_case())); - props.push(("distance", data.distance.to_snake_case())); - "minecraft:spruce_leaves" - } - Block::BirchLeaves(data) => { - props.push(("persistent", data.persistent.to_snake_case())); - props.push(("distance", data.distance.to_snake_case())); - "minecraft:birch_leaves" - } - Block::JungleLeaves(data) => { - props.push(("persistent", data.persistent.to_snake_case())); - props.push(("distance", data.distance.to_snake_case())); - "minecraft:jungle_leaves" - } - Block::AcaciaLeaves(data) => { - props.push(("distance", data.distance.to_snake_case())); - props.push(("persistent", data.persistent.to_snake_case())); - "minecraft:acacia_leaves" - } - Block::DarkOakLeaves(data) => { - props.push(("distance", data.distance.to_snake_case())); - props.push(("persistent", data.persistent.to_snake_case())); - "minecraft:dark_oak_leaves" - } - Block::Sponge => "minecraft:sponge", - Block::WetSponge => "minecraft:wet_sponge", - Block::Glass => "minecraft:glass", - Block::LapisOre => "minecraft:lapis_ore", - Block::LapisBlock => "minecraft:lapis_block", - Block::Dispenser(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("triggered", data.triggered.to_snake_case())); - "minecraft:dispenser" - } - Block::Sandstone => "minecraft:sandstone", - Block::ChiseledSandstone => "minecraft:chiseled_sandstone", - Block::CutSandstone => "minecraft:cut_sandstone", - Block::NoteBlock(data) => { - props.push(("note", data.note.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("instrument", data.instrument.to_snake_case())); - "minecraft:note_block" - } - Block::WhiteBed(data) => { - props.push(("part", data.part.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - "minecraft:white_bed" - } - Block::OrangeBed(data) => { - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - "minecraft:orange_bed" - } - Block::MagentaBed(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - "minecraft:magenta_bed" - } - Block::LightBlueBed(data) => { - props.push(("part", data.part.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:light_blue_bed" - } - Block::YellowBed(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - "minecraft:yellow_bed" - } - Block::LimeBed(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - "minecraft:lime_bed" - } - Block::PinkBed(data) => { - props.push(("part", data.part.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - "minecraft:pink_bed" - } - Block::GrayBed(data) => { - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - "minecraft:gray_bed" - } - Block::LightGrayBed(data) => { - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:light_gray_bed" - } - Block::CyanBed(data) => { - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - "minecraft:cyan_bed" - } - Block::PurpleBed(data) => { - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:purple_bed" - } - Block::BlueBed(data) => { - props.push(("part", data.part.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - "minecraft:blue_bed" - } - Block::BrownBed(data) => { - props.push(("part", data.part.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:brown_bed" - } - Block::GreenBed(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - props.push(("occupied", data.occupied.to_snake_case())); - "minecraft:green_bed" - } - Block::RedBed(data) => { - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:red_bed" - } - Block::BlackBed(data) => { - props.push(("occupied", data.occupied.to_snake_case())); - props.push(("part", data.part.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:black_bed" - } - Block::PoweredRail(data) => { - props.push(("shape", data.shape.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:powered_rail" - } - Block::DetectorRail(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - "minecraft:detector_rail" - } - Block::StickyPiston(data) => { - props.push(("extended", data.extended.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:sticky_piston" - } - Block::Cobweb => "minecraft:cobweb", - Block::Grass => "minecraft:grass", - Block::Fern => "minecraft:fern", - Block::DeadBush => "minecraft:dead_bush", - Block::Seagrass => "minecraft:seagrass", - Block::TallSeagrass(data) => { - props.push(("half", data.half.to_snake_case())); - "minecraft:tall_seagrass" - } - Block::Piston(data) => { - props.push(("extended", data.extended.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:piston" - } - Block::PistonHead(data) => { - props.push(("short", data.short.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:piston_head" - } - Block::WhiteWool => "minecraft:white_wool", - Block::OrangeWool => "minecraft:orange_wool", - Block::MagentaWool => "minecraft:magenta_wool", - Block::LightBlueWool => "minecraft:light_blue_wool", - Block::YellowWool => "minecraft:yellow_wool", - Block::LimeWool => "minecraft:lime_wool", - Block::PinkWool => "minecraft:pink_wool", - Block::GrayWool => "minecraft:gray_wool", - Block::LightGrayWool => "minecraft:light_gray_wool", - Block::CyanWool => "minecraft:cyan_wool", - Block::PurpleWool => "minecraft:purple_wool", - Block::BlueWool => "minecraft:blue_wool", - Block::BrownWool => "minecraft:brown_wool", - Block::GreenWool => "minecraft:green_wool", - Block::RedWool => "minecraft:red_wool", - Block::BlackWool => "minecraft:black_wool", - Block::MovingPiston(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:moving_piston" - } - Block::Dandelion => "minecraft:dandelion", - Block::Poppy => "minecraft:poppy", - Block::BlueOrchid => "minecraft:blue_orchid", - Block::Allium => "minecraft:allium", - Block::AzureBluet => "minecraft:azure_bluet", - Block::RedTulip => "minecraft:red_tulip", - Block::OrangeTulip => "minecraft:orange_tulip", - Block::WhiteTulip => "minecraft:white_tulip", - Block::PinkTulip => "minecraft:pink_tulip", - Block::OxeyeDaisy => "minecraft:oxeye_daisy", - Block::BrownMushroom => "minecraft:brown_mushroom", - Block::RedMushroom => "minecraft:red_mushroom", - Block::GoldBlock => "minecraft:gold_block", - Block::IronBlock => "minecraft:iron_block", - Block::Bricks => "minecraft:bricks", - Block::Tnt(data) => { - props.push(("unstable", data.unstable.to_snake_case())); - "minecraft:tnt" - } - Block::Bookshelf => "minecraft:bookshelf", - Block::MossyCobblestone => "minecraft:mossy_cobblestone", - Block::Obsidian => "minecraft:obsidian", - Block::Torch => "minecraft:torch", - Block::WallTorch(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:wall_torch" - } - Block::Fire(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("up", data.up.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("age", data.age.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - "minecraft:fire" - } - Block::Spawner => "minecraft:spawner", - Block::OakStairs(data) => { - props.push(("shape", data.shape.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:oak_stairs" - } - Block::Chest(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:chest" - } - Block::RedstoneWire(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("power", data.power.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:redstone_wire" - } - Block::DiamondOre => "minecraft:diamond_ore", - Block::DiamondBlock => "minecraft:diamond_block", - Block::CraftingTable => "minecraft:crafting_table", - Block::Wheat(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:wheat" - } - Block::Farmland(data) => { - props.push(("moisture", data.moisture.to_snake_case())); - "minecraft:farmland" - } - Block::Furnace(data) => { - props.push(("lit", data.lit.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:furnace" - } - Block::Sign(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:sign" - } - Block::OakDoor(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("hinge", data.hinge.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - "minecraft:oak_door" - } - Block::Ladder(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:ladder" - } - Block::Rail(data) => { - props.push(("shape", data.shape.to_snake_case())); - "minecraft:rail" - } - Block::CobblestoneStairs(data) => { - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:cobblestone_stairs" - } - Block::WallSign(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:wall_sign" - } - Block::Lever(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("face", data.face.to_snake_case())); - "minecraft:lever" - } - Block::StonePressurePlate(data) => { - props.push(("powered", data.powered.to_snake_case())); - "minecraft:stone_pressure_plate" - } - Block::IronDoor(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("hinge", data.hinge.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - "minecraft:iron_door" - } - Block::OakPressurePlate(data) => { - props.push(("powered", data.powered.to_snake_case())); - "minecraft:oak_pressure_plate" - } - Block::SprucePressurePlate(data) => { - props.push(("powered", data.powered.to_snake_case())); - "minecraft:spruce_pressure_plate" - } - Block::BirchPressurePlate(data) => { - props.push(("powered", data.powered.to_snake_case())); - "minecraft:birch_pressure_plate" - } - Block::JunglePressurePlate(data) => { - props.push(("powered", data.powered.to_snake_case())); - "minecraft:jungle_pressure_plate" - } - Block::AcaciaPressurePlate(data) => { - props.push(("powered", data.powered.to_snake_case())); - "minecraft:acacia_pressure_plate" - } - Block::DarkOakPressurePlate(data) => { - props.push(("powered", data.powered.to_snake_case())); - "minecraft:dark_oak_pressure_plate" - } - Block::RedstoneOre(data) => { - props.push(("lit", data.lit.to_snake_case())); - "minecraft:redstone_ore" - } - Block::RedstoneTorch(data) => { - props.push(("lit", data.lit.to_snake_case())); - "minecraft:redstone_torch" - } - Block::RedstoneWallTorch(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("lit", data.lit.to_snake_case())); - "minecraft:redstone_wall_torch" - } - Block::StoneButton(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("face", data.face.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:stone_button" - } - Block::Snow(data) => { - props.push(("layers", data.layers.to_snake_case())); - "minecraft:snow" - } - Block::Ice => "minecraft:ice", - Block::SnowBlock => "minecraft:snow_block", - Block::Cactus(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:cactus" - } - Block::Clay => "minecraft:clay", - Block::SugarCane(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:sugar_cane" - } - Block::Jukebox(data) => { - props.push(("has_record", data.has_record.to_snake_case())); - "minecraft:jukebox" - } - Block::OakFence(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - "minecraft:oak_fence" - } - Block::Pumpkin => "minecraft:pumpkin", - Block::Netherrack => "minecraft:netherrack", - Block::SoulSand => "minecraft:soul_sand", - Block::Glowstone => "minecraft:glowstone", - Block::NetherPortal(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:nether_portal" - } - Block::CarvedPumpkin(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:carved_pumpkin" - } - Block::JackOLantern(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:jack_o_lantern" - } - Block::Cake(data) => { - props.push(("bites", data.bites.to_snake_case())); - "minecraft:cake" - } - Block::Repeater(data) => { - props.push(("delay", data.delay.to_snake_case())); - props.push(("locked", data.locked.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:repeater" - } - Block::WhiteStainedGlass => "minecraft:white_stained_glass", - Block::OrangeStainedGlass => "minecraft:orange_stained_glass", - Block::MagentaStainedGlass => "minecraft:magenta_stained_glass", - Block::LightBlueStainedGlass => "minecraft:light_blue_stained_glass", - Block::YellowStainedGlass => "minecraft:yellow_stained_glass", - Block::LimeStainedGlass => "minecraft:lime_stained_glass", - Block::PinkStainedGlass => "minecraft:pink_stained_glass", - Block::GrayStainedGlass => "minecraft:gray_stained_glass", - Block::LightGrayStainedGlass => "minecraft:light_gray_stained_glass", - Block::CyanStainedGlass => "minecraft:cyan_stained_glass", - Block::PurpleStainedGlass => "minecraft:purple_stained_glass", - Block::BlueStainedGlass => "minecraft:blue_stained_glass", - Block::BrownStainedGlass => "minecraft:brown_stained_glass", - Block::GreenStainedGlass => "minecraft:green_stained_glass", - Block::RedStainedGlass => "minecraft:red_stained_glass", - Block::BlackStainedGlass => "minecraft:black_stained_glass", - Block::OakTrapdoor(data) => { - props.push(("open", data.open.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:oak_trapdoor" - } - Block::SpruceTrapdoor(data) => { - props.push(("open", data.open.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:spruce_trapdoor" - } - Block::BirchTrapdoor(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - "minecraft:birch_trapdoor" - } - Block::JungleTrapdoor(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:jungle_trapdoor" - } - Block::AcaciaTrapdoor(data) => { - props.push(("open", data.open.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:acacia_trapdoor" - } - Block::DarkOakTrapdoor(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - "minecraft:dark_oak_trapdoor" - } - Block::InfestedStone => "minecraft:infested_stone", - Block::InfestedCobblestone => "minecraft:infested_cobblestone", - Block::InfestedStoneBricks => "minecraft:infested_stone_bricks", - Block::InfestedMossyStoneBricks => "minecraft:infested_mossy_stone_bricks", - Block::InfestedCrackedStoneBricks => "minecraft:infested_cracked_stone_bricks", - Block::InfestedChiseledStoneBricks => "minecraft:infested_chiseled_stone_bricks", - Block::StoneBricks => "minecraft:stone_bricks", - Block::MossyStoneBricks => "minecraft:mossy_stone_bricks", - Block::CrackedStoneBricks => "minecraft:cracked_stone_bricks", - Block::ChiseledStoneBricks => "minecraft:chiseled_stone_bricks", - Block::BrownMushroomBlock(data) => { - props.push(("north", data.north.to_snake_case())); - props.push(("down", data.down.to_snake_case())); - props.push(("up", data.up.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - "minecraft:brown_mushroom_block" - } - Block::RedMushroomBlock(data) => { - props.push(("south", data.south.to_snake_case())); - props.push(("down", data.down.to_snake_case())); - props.push(("up", data.up.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - "minecraft:red_mushroom_block" - } - Block::MushroomStem(data) => { - props.push(("up", data.up.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("down", data.down.to_snake_case())); - "minecraft:mushroom_stem" - } - Block::IronBars(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:iron_bars" - } - Block::GlassPane(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - "minecraft:glass_pane" - } - Block::Melon => "minecraft:melon", - Block::AttachedPumpkinStem(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:attached_pumpkin_stem" - } - Block::AttachedMelonStem(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:attached_melon_stem" - } - Block::PumpkinStem(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:pumpkin_stem" - } - Block::MelonStem(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:melon_stem" - } - Block::Vine(data) => { - props.push(("up", data.up.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - "minecraft:vine" - } - Block::OakFenceGate(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("in_wall", data.in_wall.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:oak_fence_gate" - } - Block::BrickStairs(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - "minecraft:brick_stairs" - } - Block::StoneBrickStairs(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - "minecraft:stone_brick_stairs" - } - Block::Mycelium(data) => { - props.push(("snowy", data.snowy.to_snake_case())); - "minecraft:mycelium" - } - Block::LilyPad => "minecraft:lily_pad", - Block::NetherBricks => "minecraft:nether_bricks", - Block::NetherBrickFence(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:nether_brick_fence" - } - Block::NetherBrickStairs(data) => { - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:nether_brick_stairs" - } - Block::NetherWart(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:nether_wart" - } - Block::EnchantingTable => "minecraft:enchanting_table", - Block::BrewingStand(data) => { - props.push(("has_bottle_2", data.has_bottle_2.to_snake_case())); - props.push(("has_bottle_0", data.has_bottle_0.to_snake_case())); - props.push(("has_bottle_1", data.has_bottle_1.to_snake_case())); - "minecraft:brewing_stand" - } - Block::Cauldron(data) => { - props.push(("level", data.level.to_snake_case())); - "minecraft:cauldron" - } - Block::EndPortal => "minecraft:end_portal", - Block::EndPortalFrame(data) => { - props.push(("eye", data.eye.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:end_portal_frame" - } - Block::EndStone => "minecraft:end_stone", - Block::DragonEgg => "minecraft:dragon_egg", - Block::RedstoneLamp(data) => { - props.push(("lit", data.lit.to_snake_case())); - "minecraft:redstone_lamp" - } - Block::Cocoa(data) => { - props.push(("age", data.age.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:cocoa" - } - Block::SandstoneStairs(data) => { - props.push(("half", data.half.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:sandstone_stairs" - } - Block::EmeraldOre => "minecraft:emerald_ore", - Block::EnderChest(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:ender_chest" - } - Block::TripwireHook(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("attached", data.attached.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:tripwire_hook" - } - Block::Tripwire(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("disarmed", data.disarmed.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("attached", data.attached.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - "minecraft:tripwire" - } - Block::EmeraldBlock => "minecraft:emerald_block", - Block::SpruceStairs(data) => { - props.push(("half", data.half.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:spruce_stairs" - } - Block::BirchStairs(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - "minecraft:birch_stairs" - } - Block::JungleStairs(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - "minecraft:jungle_stairs" - } - Block::CommandBlock(data) => { - props.push(("conditional", data.conditional.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:command_block" - } - Block::Beacon => "minecraft:beacon", - Block::CobblestoneWall(data) => { - props.push(("south", data.south.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("up", data.up.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:cobblestone_wall" - } - Block::MossyCobblestoneWall(data) => { - props.push(("up", data.up.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:mossy_cobblestone_wall" - } - Block::FlowerPot => "minecraft:flower_pot", - Block::PottedOakSapling => "minecraft:potted_oak_sapling", - Block::PottedSpruceSapling => "minecraft:potted_spruce_sapling", - Block::PottedBirchSapling => "minecraft:potted_birch_sapling", - Block::PottedJungleSapling => "minecraft:potted_jungle_sapling", - Block::PottedAcaciaSapling => "minecraft:potted_acacia_sapling", - Block::PottedDarkOakSapling => "minecraft:potted_dark_oak_sapling", - Block::PottedFern => "minecraft:potted_fern", - Block::PottedDandelion => "minecraft:potted_dandelion", - Block::PottedPoppy => "minecraft:potted_poppy", - Block::PottedBlueOrchid => "minecraft:potted_blue_orchid", - Block::PottedAllium => "minecraft:potted_allium", - Block::PottedAzureBluet => "minecraft:potted_azure_bluet", - Block::PottedRedTulip => "minecraft:potted_red_tulip", - Block::PottedOrangeTulip => "minecraft:potted_orange_tulip", - Block::PottedWhiteTulip => "minecraft:potted_white_tulip", - Block::PottedPinkTulip => "minecraft:potted_pink_tulip", - Block::PottedOxeyeDaisy => "minecraft:potted_oxeye_daisy", - Block::PottedRedMushroom => "minecraft:potted_red_mushroom", - Block::PottedBrownMushroom => "minecraft:potted_brown_mushroom", - Block::PottedDeadBush => "minecraft:potted_dead_bush", - Block::PottedCactus => "minecraft:potted_cactus", - Block::Carrots(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:carrots" - } - Block::Potatoes(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:potatoes" - } - Block::OakButton(data) => { - props.push(("face", data.face.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:oak_button" - } - Block::SpruceButton(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("face", data.face.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:spruce_button" - } - Block::BirchButton(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("face", data.face.to_snake_case())); - "minecraft:birch_button" - } - Block::JungleButton(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("face", data.face.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:jungle_button" - } - Block::AcaciaButton(data) => { - props.push(("face", data.face.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:acacia_button" - } - Block::DarkOakButton(data) => { - props.push(("face", data.face.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:dark_oak_button" - } - Block::SkeletonWallSkull(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:skeleton_wall_skull" - } - Block::SkeletonSkull(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:skeleton_skull" - } - Block::WitherSkeletonWallSkull(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:wither_skeleton_wall_skull" - } - Block::WitherSkeletonSkull(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:wither_skeleton_skull" - } - Block::ZombieWallHead(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:zombie_wall_head" - } - Block::ZombieHead(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:zombie_head" - } - Block::PlayerWallHead(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:player_wall_head" - } - Block::PlayerHead(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:player_head" - } - Block::CreeperWallHead(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:creeper_wall_head" - } - Block::CreeperHead(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:creeper_head" - } - Block::DragonWallHead(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:dragon_wall_head" - } - Block::DragonHead(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:dragon_head" - } - Block::Anvil(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:anvil" - } - Block::ChippedAnvil(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:chipped_anvil" - } - Block::DamagedAnvil(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:damaged_anvil" - } - Block::TrappedChest(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:trapped_chest" - } - Block::LightWeightedPressurePlate(data) => { - props.push(("power", data.power.to_snake_case())); - "minecraft:light_weighted_pressure_plate" - } - Block::HeavyWeightedPressurePlate(data) => { - props.push(("power", data.power.to_snake_case())); - "minecraft:heavy_weighted_pressure_plate" - } - Block::Comparator(data) => { - props.push(("mode", data.mode.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:comparator" - } - Block::DaylightDetector(data) => { - props.push(("inverted", data.inverted.to_snake_case())); - props.push(("power", data.power.to_snake_case())); - "minecraft:daylight_detector" - } - Block::RedstoneBlock => "minecraft:redstone_block", - Block::NetherQuartzOre => "minecraft:nether_quartz_ore", - Block::Hopper(data) => { - props.push(("enabled", data.enabled.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:hopper" - } - Block::QuartzBlock => "minecraft:quartz_block", - Block::ChiseledQuartzBlock => "minecraft:chiseled_quartz_block", - Block::QuartzPillar(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:quartz_pillar" - } - Block::QuartzStairs(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - "minecraft:quartz_stairs" - } - Block::ActivatorRail(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - "minecraft:activator_rail" - } - Block::Dropper(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("triggered", data.triggered.to_snake_case())); - "minecraft:dropper" - } - Block::WhiteTerracotta => "minecraft:white_terracotta", - Block::OrangeTerracotta => "minecraft:orange_terracotta", - Block::MagentaTerracotta => "minecraft:magenta_terracotta", - Block::LightBlueTerracotta => "minecraft:light_blue_terracotta", - Block::YellowTerracotta => "minecraft:yellow_terracotta", - Block::LimeTerracotta => "minecraft:lime_terracotta", - Block::PinkTerracotta => "minecraft:pink_terracotta", - Block::GrayTerracotta => "minecraft:gray_terracotta", - Block::LightGrayTerracotta => "minecraft:light_gray_terracotta", - Block::CyanTerracotta => "minecraft:cyan_terracotta", - Block::PurpleTerracotta => "minecraft:purple_terracotta", - Block::BlueTerracotta => "minecraft:blue_terracotta", - Block::BrownTerracotta => "minecraft:brown_terracotta", - Block::GreenTerracotta => "minecraft:green_terracotta", - Block::RedTerracotta => "minecraft:red_terracotta", - Block::BlackTerracotta => "minecraft:black_terracotta", - Block::WhiteStainedGlassPane(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - "minecraft:white_stained_glass_pane" - } - Block::OrangeStainedGlassPane(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:orange_stained_glass_pane" - } - Block::MagentaStainedGlassPane(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:magenta_stained_glass_pane" - } - Block::LightBlueStainedGlassPane(data) => { - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:light_blue_stained_glass_pane" - } - Block::YellowStainedGlassPane(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:yellow_stained_glass_pane" - } - Block::LimeStainedGlassPane(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:lime_stained_glass_pane" - } - Block::PinkStainedGlassPane(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - "minecraft:pink_stained_glass_pane" - } - Block::GrayStainedGlassPane(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:gray_stained_glass_pane" - } - Block::LightGrayStainedGlassPane(data) => { - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - "minecraft:light_gray_stained_glass_pane" - } - Block::CyanStainedGlassPane(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:cyan_stained_glass_pane" - } - Block::PurpleStainedGlassPane(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:purple_stained_glass_pane" - } - Block::BlueStainedGlassPane(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - "minecraft:blue_stained_glass_pane" - } - Block::BrownStainedGlassPane(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - "minecraft:brown_stained_glass_pane" - } - Block::GreenStainedGlassPane(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - "minecraft:green_stained_glass_pane" - } - Block::RedStainedGlassPane(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:red_stained_glass_pane" - } - Block::BlackStainedGlassPane(data) => { - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:black_stained_glass_pane" - } - Block::AcaciaStairs(data) => { - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:acacia_stairs" - } - Block::DarkOakStairs(data) => { - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:dark_oak_stairs" - } - Block::SlimeBlock => "minecraft:slime_block", - Block::Barrier => "minecraft:barrier", - Block::IronTrapdoor(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:iron_trapdoor" - } - Block::Prismarine => "minecraft:prismarine", - Block::PrismarineBricks => "minecraft:prismarine_bricks", - Block::DarkPrismarine => "minecraft:dark_prismarine", - Block::PrismarineStairs(data) => { - props.push(("shape", data.shape.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:prismarine_stairs" - } - Block::PrismarineBrickStairs(data) => { - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - "minecraft:prismarine_brick_stairs" - } - Block::DarkPrismarineStairs(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dark_prismarine_stairs" - } - Block::PrismarineSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:prismarine_slab" - } - Block::PrismarineBrickSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:prismarine_brick_slab" - } - Block::DarkPrismarineSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dark_prismarine_slab" - } - Block::SeaLantern => "minecraft:sea_lantern", - Block::HayBlock(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:hay_block" - } - Block::WhiteCarpet => "minecraft:white_carpet", - Block::OrangeCarpet => "minecraft:orange_carpet", - Block::MagentaCarpet => "minecraft:magenta_carpet", - Block::LightBlueCarpet => "minecraft:light_blue_carpet", - Block::YellowCarpet => "minecraft:yellow_carpet", - Block::LimeCarpet => "minecraft:lime_carpet", - Block::PinkCarpet => "minecraft:pink_carpet", - Block::GrayCarpet => "minecraft:gray_carpet", - Block::LightGrayCarpet => "minecraft:light_gray_carpet", - Block::CyanCarpet => "minecraft:cyan_carpet", - Block::PurpleCarpet => "minecraft:purple_carpet", - Block::BlueCarpet => "minecraft:blue_carpet", - Block::BrownCarpet => "minecraft:brown_carpet", - Block::GreenCarpet => "minecraft:green_carpet", - Block::RedCarpet => "minecraft:red_carpet", - Block::BlackCarpet => "minecraft:black_carpet", - Block::Terracotta => "minecraft:terracotta", - Block::CoalBlock => "minecraft:coal_block", - Block::PackedIce => "minecraft:packed_ice", - Block::Sunflower(data) => { - props.push(("half", data.half.to_snake_case())); - "minecraft:sunflower" - } - Block::Lilac(data) => { - props.push(("half", data.half.to_snake_case())); - "minecraft:lilac" - } - Block::RoseBush(data) => { - props.push(("half", data.half.to_snake_case())); - "minecraft:rose_bush" - } - Block::Peony(data) => { - props.push(("half", data.half.to_snake_case())); - "minecraft:peony" - } - Block::TallGrass(data) => { - props.push(("half", data.half.to_snake_case())); - "minecraft:tall_grass" - } - Block::LargeFern(data) => { - props.push(("half", data.half.to_snake_case())); - "minecraft:large_fern" - } - Block::WhiteBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:white_banner" - } - Block::OrangeBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:orange_banner" - } - Block::MagentaBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:magenta_banner" - } - Block::LightBlueBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:light_blue_banner" - } - Block::YellowBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:yellow_banner" - } - Block::LimeBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:lime_banner" - } - Block::PinkBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:pink_banner" - } - Block::GrayBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:gray_banner" - } - Block::LightGrayBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:light_gray_banner" - } - Block::CyanBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:cyan_banner" - } - Block::PurpleBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:purple_banner" - } - Block::BlueBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:blue_banner" - } - Block::BrownBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:brown_banner" - } - Block::GreenBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:green_banner" - } - Block::RedBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:red_banner" - } - Block::BlackBanner(data) => { - props.push(("rotation", data.rotation.to_snake_case())); - "minecraft:black_banner" - } - Block::WhiteWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:white_wall_banner" - } - Block::OrangeWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:orange_wall_banner" - } - Block::MagentaWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:magenta_wall_banner" - } - Block::LightBlueWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:light_blue_wall_banner" - } - Block::YellowWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:yellow_wall_banner" - } - Block::LimeWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:lime_wall_banner" - } - Block::PinkWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:pink_wall_banner" - } - Block::GrayWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:gray_wall_banner" - } - Block::LightGrayWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:light_gray_wall_banner" - } - Block::CyanWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:cyan_wall_banner" - } - Block::PurpleWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:purple_wall_banner" - } - Block::BlueWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:blue_wall_banner" - } - Block::BrownWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:brown_wall_banner" - } - Block::GreenWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:green_wall_banner" - } - Block::RedWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:red_wall_banner" - } - Block::BlackWallBanner(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:black_wall_banner" - } - Block::RedSandstone => "minecraft:red_sandstone", - Block::ChiseledRedSandstone => "minecraft:chiseled_red_sandstone", - Block::CutRedSandstone => "minecraft:cut_red_sandstone", - Block::RedSandstoneStairs(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("shape", data.shape.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:red_sandstone_stairs" - } - Block::OakSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:oak_slab" - } - Block::SpruceSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:spruce_slab" - } - Block::BirchSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:birch_slab" - } - Block::JungleSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:jungle_slab" - } - Block::AcaciaSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:acacia_slab" - } - Block::DarkOakSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dark_oak_slab" - } - Block::StoneSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:stone_slab" - } - Block::SandstoneSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:sandstone_slab" - } - Block::PetrifiedOakSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:petrified_oak_slab" - } - Block::CobblestoneSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:cobblestone_slab" - } - Block::BrickSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:brick_slab" - } - Block::StoneBrickSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:stone_brick_slab" - } - Block::NetherBrickSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:nether_brick_slab" - } - Block::QuartzSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:quartz_slab" - } - Block::RedSandstoneSlab(data) => { - props.push(("type", data.ty.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:red_sandstone_slab" - } - Block::PurpurSlab(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("type", data.ty.to_snake_case())); - "minecraft:purpur_slab" - } - Block::SmoothStone => "minecraft:smooth_stone", - Block::SmoothSandstone => "minecraft:smooth_sandstone", - Block::SmoothQuartz => "minecraft:smooth_quartz", - Block::SmoothRedSandstone => "minecraft:smooth_red_sandstone", - Block::SpruceFenceGate(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("in_wall", data.in_wall.to_snake_case())); - "minecraft:spruce_fence_gate" - } - Block::BirchFenceGate(data) => { - props.push(("in_wall", data.in_wall.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:birch_fence_gate" - } - Block::JungleFenceGate(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("in_wall", data.in_wall.to_snake_case())); - "minecraft:jungle_fence_gate" - } - Block::AcaciaFenceGate(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("in_wall", data.in_wall.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - "minecraft:acacia_fence_gate" - } - Block::DarkOakFenceGate(data) => { - props.push(("in_wall", data.in_wall.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:dark_oak_fence_gate" - } - Block::SpruceFence(data) => { - props.push(("north", data.north.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - "minecraft:spruce_fence" - } - Block::BirchFence(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - "minecraft:birch_fence" - } - Block::JungleFence(data) => { - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:jungle_fence" - } - Block::AcaciaFence(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - "minecraft:acacia_fence" - } - Block::DarkOakFence(data) => { - props.push(("east", data.east.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - "minecraft:dark_oak_fence" - } - Block::SpruceDoor(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("hinge", data.hinge.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - "minecraft:spruce_door" - } - Block::BirchDoor(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("hinge", data.hinge.to_snake_case())); - "minecraft:birch_door" - } - Block::JungleDoor(data) => { - props.push(("half", data.half.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - props.push(("hinge", data.hinge.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:jungle_door" - } - Block::AcaciaDoor(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("hinge", data.hinge.to_snake_case())); - "minecraft:acacia_door" - } - Block::DarkOakDoor(data) => { - props.push(("half", data.half.to_snake_case())); - props.push(("hinge", data.hinge.to_snake_case())); - props.push(("open", data.open.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - props.push(("powered", data.powered.to_snake_case())); - "minecraft:dark_oak_door" - } - Block::EndRod(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:end_rod" - } - Block::ChorusPlant(data) => { - props.push(("down", data.down.to_snake_case())); - props.push(("north", data.north.to_snake_case())); - props.push(("south", data.south.to_snake_case())); - props.push(("west", data.west.to_snake_case())); - props.push(("east", data.east.to_snake_case())); - props.push(("up", data.up.to_snake_case())); - "minecraft:chorus_plant" - } - Block::ChorusFlower(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:chorus_flower" - } - Block::PurpurBlock => "minecraft:purpur_block", - Block::PurpurPillar(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:purpur_pillar" - } - Block::PurpurStairs(data) => { - props.push(("shape", data.shape.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("half", data.half.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:purpur_stairs" - } - Block::EndStoneBricks => "minecraft:end_stone_bricks", - Block::Beetroots(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:beetroots" - } - Block::GrassPath => "minecraft:grass_path", - Block::EndGateway => "minecraft:end_gateway", - Block::RepeatingCommandBlock(data) => { - props.push(("conditional", data.conditional.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:repeating_command_block" - } - Block::ChainCommandBlock(data) => { - props.push(("conditional", data.conditional.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:chain_command_block" - } - Block::FrostedIce(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:frosted_ice" - } - Block::MagmaBlock => "minecraft:magma_block", - Block::NetherWartBlock => "minecraft:nether_wart_block", - Block::RedNetherBricks => "minecraft:red_nether_bricks", - Block::BoneBlock(data) => { - props.push(("axis", data.axis.to_snake_case())); - "minecraft:bone_block" - } - Block::StructureVoid => "minecraft:structure_void", - Block::Observer(data) => { - props.push(("powered", data.powered.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:observer" - } - Block::ShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:shulker_box" - } - Block::WhiteShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:white_shulker_box" - } - Block::OrangeShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:orange_shulker_box" - } - Block::MagentaShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:magenta_shulker_box" - } - Block::LightBlueShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:light_blue_shulker_box" - } - Block::YellowShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:yellow_shulker_box" - } - Block::LimeShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:lime_shulker_box" - } - Block::PinkShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:pink_shulker_box" - } - Block::GrayShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:gray_shulker_box" - } - Block::LightGrayShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:light_gray_shulker_box" - } - Block::CyanShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:cyan_shulker_box" - } - Block::PurpleShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:purple_shulker_box" - } - Block::BlueShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:blue_shulker_box" - } - Block::BrownShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:brown_shulker_box" - } - Block::GreenShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:green_shulker_box" - } - Block::RedShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:red_shulker_box" - } - Block::BlackShulkerBox(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:black_shulker_box" - } - Block::WhiteGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:white_glazed_terracotta" - } - Block::OrangeGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:orange_glazed_terracotta" - } - Block::MagentaGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:magenta_glazed_terracotta" - } - Block::LightBlueGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:light_blue_glazed_terracotta" - } - Block::YellowGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:yellow_glazed_terracotta" - } - Block::LimeGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:lime_glazed_terracotta" - } - Block::PinkGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:pink_glazed_terracotta" - } - Block::GrayGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:gray_glazed_terracotta" - } - Block::LightGrayGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:light_gray_glazed_terracotta" - } - Block::CyanGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:cyan_glazed_terracotta" - } - Block::PurpleGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:purple_glazed_terracotta" - } - Block::BlueGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:blue_glazed_terracotta" - } - Block::BrownGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:brown_glazed_terracotta" - } - Block::GreenGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:green_glazed_terracotta" - } - Block::RedGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:red_glazed_terracotta" - } - Block::BlackGlazedTerracotta(data) => { - props.push(("facing", data.facing.to_snake_case())); - "minecraft:black_glazed_terracotta" - } - Block::WhiteConcrete => "minecraft:white_concrete", - Block::OrangeConcrete => "minecraft:orange_concrete", - Block::MagentaConcrete => "minecraft:magenta_concrete", - Block::LightBlueConcrete => "minecraft:light_blue_concrete", - Block::YellowConcrete => "minecraft:yellow_concrete", - Block::LimeConcrete => "minecraft:lime_concrete", - Block::PinkConcrete => "minecraft:pink_concrete", - Block::GrayConcrete => "minecraft:gray_concrete", - Block::LightGrayConcrete => "minecraft:light_gray_concrete", - Block::CyanConcrete => "minecraft:cyan_concrete", - Block::PurpleConcrete => "minecraft:purple_concrete", - Block::BlueConcrete => "minecraft:blue_concrete", - Block::BrownConcrete => "minecraft:brown_concrete", - Block::GreenConcrete => "minecraft:green_concrete", - Block::RedConcrete => "minecraft:red_concrete", - Block::BlackConcrete => "minecraft:black_concrete", - Block::WhiteConcretePowder => "minecraft:white_concrete_powder", - Block::OrangeConcretePowder => "minecraft:orange_concrete_powder", - Block::MagentaConcretePowder => "minecraft:magenta_concrete_powder", - Block::LightBlueConcretePowder => "minecraft:light_blue_concrete_powder", - Block::YellowConcretePowder => "minecraft:yellow_concrete_powder", - Block::LimeConcretePowder => "minecraft:lime_concrete_powder", - Block::PinkConcretePowder => "minecraft:pink_concrete_powder", - Block::GrayConcretePowder => "minecraft:gray_concrete_powder", - Block::LightGrayConcretePowder => "minecraft:light_gray_concrete_powder", - Block::CyanConcretePowder => "minecraft:cyan_concrete_powder", - Block::PurpleConcretePowder => "minecraft:purple_concrete_powder", - Block::BlueConcretePowder => "minecraft:blue_concrete_powder", - Block::BrownConcretePowder => "minecraft:brown_concrete_powder", - Block::GreenConcretePowder => "minecraft:green_concrete_powder", - Block::RedConcretePowder => "minecraft:red_concrete_powder", - Block::BlackConcretePowder => "minecraft:black_concrete_powder", - Block::Kelp(data) => { - props.push(("age", data.age.to_snake_case())); - "minecraft:kelp" - } - Block::KelpPlant => "minecraft:kelp_plant", - Block::DriedKelpBlock => "minecraft:dried_kelp_block", - Block::TurtleEgg(data) => { - props.push(("eggs", data.eggs.to_snake_case())); - props.push(("hatch", data.hatch.to_snake_case())); - "minecraft:turtle_egg" - } - Block::DeadTubeCoralBlock => "minecraft:dead_tube_coral_block", - Block::DeadBrainCoralBlock => "minecraft:dead_brain_coral_block", - Block::DeadBubbleCoralBlock => "minecraft:dead_bubble_coral_block", - Block::DeadFireCoralBlock => "minecraft:dead_fire_coral_block", - Block::DeadHornCoralBlock => "minecraft:dead_horn_coral_block", - Block::TubeCoralBlock => "minecraft:tube_coral_block", - Block::BrainCoralBlock => "minecraft:brain_coral_block", - Block::BubbleCoralBlock => "minecraft:bubble_coral_block", - Block::FireCoralBlock => "minecraft:fire_coral_block", - Block::HornCoralBlock => "minecraft:horn_coral_block", - Block::DeadTubeCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_tube_coral" - } - Block::DeadBrainCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_brain_coral" - } - Block::DeadBubbleCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_bubble_coral" - } - Block::DeadFireCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_fire_coral" - } - Block::DeadHornCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_horn_coral" - } - Block::TubeCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:tube_coral" - } - Block::BrainCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:brain_coral" - } - Block::BubbleCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:bubble_coral" - } - Block::FireCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:fire_coral" - } - Block::HornCoral(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:horn_coral" - } - Block::DeadTubeCoralWallFan(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_tube_coral_wall_fan" - } - Block::DeadBrainCoralWallFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:dead_brain_coral_wall_fan" - } - Block::DeadBubbleCoralWallFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:dead_bubble_coral_wall_fan" - } - Block::DeadFireCoralWallFan(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_fire_coral_wall_fan" - } - Block::DeadHornCoralWallFan(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_horn_coral_wall_fan" - } - Block::TubeCoralWallFan(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:tube_coral_wall_fan" - } - Block::BrainCoralWallFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:brain_coral_wall_fan" - } - Block::BubbleCoralWallFan(data) => { - props.push(("facing", data.facing.to_snake_case())); - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:bubble_coral_wall_fan" - } - Block::FireCoralWallFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:fire_coral_wall_fan" - } - Block::HornCoralWallFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("facing", data.facing.to_snake_case())); - "minecraft:horn_coral_wall_fan" - } - Block::DeadTubeCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_tube_coral_fan" - } - Block::DeadBrainCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_brain_coral_fan" - } - Block::DeadBubbleCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_bubble_coral_fan" - } - Block::DeadFireCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_fire_coral_fan" - } - Block::DeadHornCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:dead_horn_coral_fan" - } - Block::TubeCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:tube_coral_fan" - } - Block::BrainCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:brain_coral_fan" - } - Block::BubbleCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:bubble_coral_fan" - } - Block::FireCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:fire_coral_fan" - } - Block::HornCoralFan(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:horn_coral_fan" - } - Block::SeaPickle(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - props.push(("pickles", data.pickles.to_snake_case())); - "minecraft:sea_pickle" - } - Block::BlueIce => "minecraft:blue_ice", - Block::Conduit(data) => { - props.push(("waterlogged", data.waterlogged.to_snake_case())); - "minecraft:conduit" - } - Block::VoidAir => "minecraft:void_air", - Block::CaveAir => "minecraft:cave_air", - Block::BubbleColumn(data) => { - props.push(("drag", data.drag.to_snake_case())); - "minecraft:bubble_column" - } - Block::StructureBlock(data) => { - props.push(("mode", data.mode.to_snake_case())); - "minecraft:structure_block" - } - }; - (name, props) - } - pub fn from_name_and_default_props(name: &str) -> Option { - match name { - "minecraft:air" => Some(Block::Air), - "minecraft:stone" => Some(Block::Stone), - "minecraft:granite" => Some(Block::Granite), - "minecraft:polished_granite" => Some(Block::PolishedGranite), - "minecraft:diorite" => Some(Block::Diorite), - "minecraft:polished_diorite" => Some(Block::PolishedDiorite), - "minecraft:andesite" => Some(Block::Andesite), - "minecraft:polished_andesite" => Some(Block::PolishedAndesite), - "minecraft:grass_block" => { - let data = GrassBlockData::default(); - Some(Block::GrassBlock(data)) - } - "minecraft:dirt" => Some(Block::Dirt), - "minecraft:coarse_dirt" => Some(Block::CoarseDirt), - "minecraft:podzol" => { - let data = PodzolData::default(); - Some(Block::Podzol(data)) - } - "minecraft:cobblestone" => Some(Block::Cobblestone), - "minecraft:oak_planks" => Some(Block::OakPlanks), - "minecraft:spruce_planks" => Some(Block::SprucePlanks), - "minecraft:birch_planks" => Some(Block::BirchPlanks), - "minecraft:jungle_planks" => Some(Block::JunglePlanks), - "minecraft:acacia_planks" => Some(Block::AcaciaPlanks), - "minecraft:dark_oak_planks" => Some(Block::DarkOakPlanks), - "minecraft:oak_sapling" => { - let data = OakSaplingData::default(); - Some(Block::OakSapling(data)) - } - "minecraft:spruce_sapling" => { - let data = SpruceSaplingData::default(); - Some(Block::SpruceSapling(data)) - } - "minecraft:birch_sapling" => { - let data = BirchSaplingData::default(); - Some(Block::BirchSapling(data)) - } - "minecraft:jungle_sapling" => { - let data = JungleSaplingData::default(); - Some(Block::JungleSapling(data)) - } - "minecraft:acacia_sapling" => { - let data = AcaciaSaplingData::default(); - Some(Block::AcaciaSapling(data)) - } - "minecraft:dark_oak_sapling" => { - let data = DarkOakSaplingData::default(); - Some(Block::DarkOakSapling(data)) - } - "minecraft:bedrock" => Some(Block::Bedrock), - "minecraft:water" => { - let data = WaterData::default(); - Some(Block::Water(data)) - } - "minecraft:lava" => { - let data = LavaData::default(); - Some(Block::Lava(data)) - } - "minecraft:sand" => Some(Block::Sand), - "minecraft:red_sand" => Some(Block::RedSand), - "minecraft:gravel" => Some(Block::Gravel), - "minecraft:gold_ore" => Some(Block::GoldOre), - "minecraft:iron_ore" => Some(Block::IronOre), - "minecraft:coal_ore" => Some(Block::CoalOre), - "minecraft:oak_log" => { - let data = OakLogData::default(); - Some(Block::OakLog(data)) - } - "minecraft:spruce_log" => { - let data = SpruceLogData::default(); - Some(Block::SpruceLog(data)) - } - "minecraft:birch_log" => { - let data = BirchLogData::default(); - Some(Block::BirchLog(data)) - } - "minecraft:jungle_log" => { - let data = JungleLogData::default(); - Some(Block::JungleLog(data)) - } - "minecraft:acacia_log" => { - let data = AcaciaLogData::default(); - Some(Block::AcaciaLog(data)) - } - "minecraft:dark_oak_log" => { - let data = DarkOakLogData::default(); - Some(Block::DarkOakLog(data)) - } - "minecraft:stripped_spruce_log" => { - let data = StrippedSpruceLogData::default(); - Some(Block::StrippedSpruceLog(data)) - } - "minecraft:stripped_birch_log" => { - let data = StrippedBirchLogData::default(); - Some(Block::StrippedBirchLog(data)) - } - "minecraft:stripped_jungle_log" => { - let data = StrippedJungleLogData::default(); - Some(Block::StrippedJungleLog(data)) - } - "minecraft:stripped_acacia_log" => { - let data = StrippedAcaciaLogData::default(); - Some(Block::StrippedAcaciaLog(data)) - } - "minecraft:stripped_dark_oak_log" => { - let data = StrippedDarkOakLogData::default(); - Some(Block::StrippedDarkOakLog(data)) - } - "minecraft:stripped_oak_log" => { - let data = StrippedOakLogData::default(); - Some(Block::StrippedOakLog(data)) - } - "minecraft:oak_wood" => { - let data = OakWoodData::default(); - Some(Block::OakWood(data)) - } - "minecraft:spruce_wood" => { - let data = SpruceWoodData::default(); - Some(Block::SpruceWood(data)) - } - "minecraft:birch_wood" => { - let data = BirchWoodData::default(); - Some(Block::BirchWood(data)) - } - "minecraft:jungle_wood" => { - let data = JungleWoodData::default(); - Some(Block::JungleWood(data)) - } - "minecraft:acacia_wood" => { - let data = AcaciaWoodData::default(); - Some(Block::AcaciaWood(data)) - } - "minecraft:dark_oak_wood" => { - let data = DarkOakWoodData::default(); - Some(Block::DarkOakWood(data)) - } - "minecraft:stripped_oak_wood" => { - let data = StrippedOakWoodData::default(); - Some(Block::StrippedOakWood(data)) - } - "minecraft:stripped_spruce_wood" => { - let data = StrippedSpruceWoodData::default(); - Some(Block::StrippedSpruceWood(data)) - } - "minecraft:stripped_birch_wood" => { - let data = StrippedBirchWoodData::default(); - Some(Block::StrippedBirchWood(data)) - } - "minecraft:stripped_jungle_wood" => { - let data = StrippedJungleWoodData::default(); - Some(Block::StrippedJungleWood(data)) - } - "minecraft:stripped_acacia_wood" => { - let data = StrippedAcaciaWoodData::default(); - Some(Block::StrippedAcaciaWood(data)) - } - "minecraft:stripped_dark_oak_wood" => { - let data = StrippedDarkOakWoodData::default(); - Some(Block::StrippedDarkOakWood(data)) - } - "minecraft:oak_leaves" => { - let data = OakLeavesData::default(); - Some(Block::OakLeaves(data)) - } - "minecraft:spruce_leaves" => { - let data = SpruceLeavesData::default(); - Some(Block::SpruceLeaves(data)) - } - "minecraft:birch_leaves" => { - let data = BirchLeavesData::default(); - Some(Block::BirchLeaves(data)) - } - "minecraft:jungle_leaves" => { - let data = JungleLeavesData::default(); - Some(Block::JungleLeaves(data)) - } - "minecraft:acacia_leaves" => { - let data = AcaciaLeavesData::default(); - Some(Block::AcaciaLeaves(data)) - } - "minecraft:dark_oak_leaves" => { - let data = DarkOakLeavesData::default(); - Some(Block::DarkOakLeaves(data)) - } - "minecraft:sponge" => Some(Block::Sponge), - "minecraft:wet_sponge" => Some(Block::WetSponge), - "minecraft:glass" => Some(Block::Glass), - "minecraft:lapis_ore" => Some(Block::LapisOre), - "minecraft:lapis_block" => Some(Block::LapisBlock), - "minecraft:dispenser" => { - let data = DispenserData::default(); - Some(Block::Dispenser(data)) - } - "minecraft:sandstone" => Some(Block::Sandstone), - "minecraft:chiseled_sandstone" => Some(Block::ChiseledSandstone), - "minecraft:cut_sandstone" => Some(Block::CutSandstone), - "minecraft:note_block" => { - let data = NoteBlockData::default(); - Some(Block::NoteBlock(data)) - } - "minecraft:white_bed" => { - let data = WhiteBedData::default(); - Some(Block::WhiteBed(data)) - } - "minecraft:orange_bed" => { - let data = OrangeBedData::default(); - Some(Block::OrangeBed(data)) - } - "minecraft:magenta_bed" => { - let data = MagentaBedData::default(); - Some(Block::MagentaBed(data)) - } - "minecraft:light_blue_bed" => { - let data = LightBlueBedData::default(); - Some(Block::LightBlueBed(data)) - } - "minecraft:yellow_bed" => { - let data = YellowBedData::default(); - Some(Block::YellowBed(data)) - } - "minecraft:lime_bed" => { - let data = LimeBedData::default(); - Some(Block::LimeBed(data)) - } - "minecraft:pink_bed" => { - let data = PinkBedData::default(); - Some(Block::PinkBed(data)) - } - "minecraft:gray_bed" => { - let data = GrayBedData::default(); - Some(Block::GrayBed(data)) - } - "minecraft:light_gray_bed" => { - let data = LightGrayBedData::default(); - Some(Block::LightGrayBed(data)) - } - "minecraft:cyan_bed" => { - let data = CyanBedData::default(); - Some(Block::CyanBed(data)) - } - "minecraft:purple_bed" => { - let data = PurpleBedData::default(); - Some(Block::PurpleBed(data)) - } - "minecraft:blue_bed" => { - let data = BlueBedData::default(); - Some(Block::BlueBed(data)) - } - "minecraft:brown_bed" => { - let data = BrownBedData::default(); - Some(Block::BrownBed(data)) - } - "minecraft:green_bed" => { - let data = GreenBedData::default(); - Some(Block::GreenBed(data)) - } - "minecraft:red_bed" => { - let data = RedBedData::default(); - Some(Block::RedBed(data)) - } - "minecraft:black_bed" => { - let data = BlackBedData::default(); - Some(Block::BlackBed(data)) - } - "minecraft:powered_rail" => { - let data = PoweredRailData::default(); - Some(Block::PoweredRail(data)) - } - "minecraft:detector_rail" => { - let data = DetectorRailData::default(); - Some(Block::DetectorRail(data)) - } - "minecraft:sticky_piston" => { - let data = StickyPistonData::default(); - Some(Block::StickyPiston(data)) - } - "minecraft:cobweb" => Some(Block::Cobweb), - "minecraft:grass" => Some(Block::Grass), - "minecraft:fern" => Some(Block::Fern), - "minecraft:dead_bush" => Some(Block::DeadBush), - "minecraft:seagrass" => Some(Block::Seagrass), - "minecraft:tall_seagrass" => { - let data = TallSeagrassData::default(); - Some(Block::TallSeagrass(data)) - } - "minecraft:piston" => { - let data = PistonData::default(); - Some(Block::Piston(data)) - } - "minecraft:piston_head" => { - let data = PistonHeadData::default(); - Some(Block::PistonHead(data)) - } - "minecraft:white_wool" => Some(Block::WhiteWool), - "minecraft:orange_wool" => Some(Block::OrangeWool), - "minecraft:magenta_wool" => Some(Block::MagentaWool), - "minecraft:light_blue_wool" => Some(Block::LightBlueWool), - "minecraft:yellow_wool" => Some(Block::YellowWool), - "minecraft:lime_wool" => Some(Block::LimeWool), - "minecraft:pink_wool" => Some(Block::PinkWool), - "minecraft:gray_wool" => Some(Block::GrayWool), - "minecraft:light_gray_wool" => Some(Block::LightGrayWool), - "minecraft:cyan_wool" => Some(Block::CyanWool), - "minecraft:purple_wool" => Some(Block::PurpleWool), - "minecraft:blue_wool" => Some(Block::BlueWool), - "minecraft:brown_wool" => Some(Block::BrownWool), - "minecraft:green_wool" => Some(Block::GreenWool), - "minecraft:red_wool" => Some(Block::RedWool), - "minecraft:black_wool" => Some(Block::BlackWool), - "minecraft:moving_piston" => { - let data = MovingPistonData::default(); - Some(Block::MovingPiston(data)) - } - "minecraft:dandelion" => Some(Block::Dandelion), - "minecraft:poppy" => Some(Block::Poppy), - "minecraft:blue_orchid" => Some(Block::BlueOrchid), - "minecraft:allium" => Some(Block::Allium), - "minecraft:azure_bluet" => Some(Block::AzureBluet), - "minecraft:red_tulip" => Some(Block::RedTulip), - "minecraft:orange_tulip" => Some(Block::OrangeTulip), - "minecraft:white_tulip" => Some(Block::WhiteTulip), - "minecraft:pink_tulip" => Some(Block::PinkTulip), - "minecraft:oxeye_daisy" => Some(Block::OxeyeDaisy), - "minecraft:brown_mushroom" => Some(Block::BrownMushroom), - "minecraft:red_mushroom" => Some(Block::RedMushroom), - "minecraft:gold_block" => Some(Block::GoldBlock), - "minecraft:iron_block" => Some(Block::IronBlock), - "minecraft:bricks" => Some(Block::Bricks), - "minecraft:tnt" => { - let data = TntData::default(); - Some(Block::Tnt(data)) - } - "minecraft:bookshelf" => Some(Block::Bookshelf), - "minecraft:mossy_cobblestone" => Some(Block::MossyCobblestone), - "minecraft:obsidian" => Some(Block::Obsidian), - "minecraft:torch" => Some(Block::Torch), - "minecraft:wall_torch" => { - let data = WallTorchData::default(); - Some(Block::WallTorch(data)) - } - "minecraft:fire" => { - let data = FireData::default(); - Some(Block::Fire(data)) - } - "minecraft:spawner" => Some(Block::Spawner), - "minecraft:oak_stairs" => { - let data = OakStairsData::default(); - Some(Block::OakStairs(data)) - } - "minecraft:chest" => { - let data = ChestData::default(); - Some(Block::Chest(data)) - } - "minecraft:redstone_wire" => { - let data = RedstoneWireData::default(); - Some(Block::RedstoneWire(data)) - } - "minecraft:diamond_ore" => Some(Block::DiamondOre), - "minecraft:diamond_block" => Some(Block::DiamondBlock), - "minecraft:crafting_table" => Some(Block::CraftingTable), - "minecraft:wheat" => { - let data = WheatData::default(); - Some(Block::Wheat(data)) - } - "minecraft:farmland" => { - let data = FarmlandData::default(); - Some(Block::Farmland(data)) - } - "minecraft:furnace" => { - let data = FurnaceData::default(); - Some(Block::Furnace(data)) - } - "minecraft:sign" => { - let data = SignData::default(); - Some(Block::Sign(data)) - } - "minecraft:oak_door" => { - let data = OakDoorData::default(); - Some(Block::OakDoor(data)) - } - "minecraft:ladder" => { - let data = LadderData::default(); - Some(Block::Ladder(data)) - } - "minecraft:rail" => { - let data = RailData::default(); - Some(Block::Rail(data)) - } - "minecraft:cobblestone_stairs" => { - let data = CobblestoneStairsData::default(); - Some(Block::CobblestoneStairs(data)) - } - "minecraft:wall_sign" => { - let data = WallSignData::default(); - Some(Block::WallSign(data)) - } - "minecraft:lever" => { - let data = LeverData::default(); - Some(Block::Lever(data)) - } - "minecraft:stone_pressure_plate" => { - let data = StonePressurePlateData::default(); - Some(Block::StonePressurePlate(data)) - } - "minecraft:iron_door" => { - let data = IronDoorData::default(); - Some(Block::IronDoor(data)) - } - "minecraft:oak_pressure_plate" => { - let data = OakPressurePlateData::default(); - Some(Block::OakPressurePlate(data)) - } - "minecraft:spruce_pressure_plate" => { - let data = SprucePressurePlateData::default(); - Some(Block::SprucePressurePlate(data)) - } - "minecraft:birch_pressure_plate" => { - let data = BirchPressurePlateData::default(); - Some(Block::BirchPressurePlate(data)) - } - "minecraft:jungle_pressure_plate" => { - let data = JunglePressurePlateData::default(); - Some(Block::JunglePressurePlate(data)) - } - "minecraft:acacia_pressure_plate" => { - let data = AcaciaPressurePlateData::default(); - Some(Block::AcaciaPressurePlate(data)) - } - "minecraft:dark_oak_pressure_plate" => { - let data = DarkOakPressurePlateData::default(); - Some(Block::DarkOakPressurePlate(data)) - } - "minecraft:redstone_ore" => { - let data = RedstoneOreData::default(); - Some(Block::RedstoneOre(data)) - } - "minecraft:redstone_torch" => { - let data = RedstoneTorchData::default(); - Some(Block::RedstoneTorch(data)) - } - "minecraft:redstone_wall_torch" => { - let data = RedstoneWallTorchData::default(); - Some(Block::RedstoneWallTorch(data)) - } - "minecraft:stone_button" => { - let data = StoneButtonData::default(); - Some(Block::StoneButton(data)) - } - "minecraft:snow" => { - let data = SnowData::default(); - Some(Block::Snow(data)) - } - "minecraft:ice" => Some(Block::Ice), - "minecraft:snow_block" => Some(Block::SnowBlock), - "minecraft:cactus" => { - let data = CactusData::default(); - Some(Block::Cactus(data)) - } - "minecraft:clay" => Some(Block::Clay), - "minecraft:sugar_cane" => { - let data = SugarCaneData::default(); - Some(Block::SugarCane(data)) - } - "minecraft:jukebox" => { - let data = JukeboxData::default(); - Some(Block::Jukebox(data)) - } - "minecraft:oak_fence" => { - let data = OakFenceData::default(); - Some(Block::OakFence(data)) - } - "minecraft:pumpkin" => Some(Block::Pumpkin), - "minecraft:netherrack" => Some(Block::Netherrack), - "minecraft:soul_sand" => Some(Block::SoulSand), - "minecraft:glowstone" => Some(Block::Glowstone), - "minecraft:nether_portal" => { - let data = NetherPortalData::default(); - Some(Block::NetherPortal(data)) - } - "minecraft:carved_pumpkin" => { - let data = CarvedPumpkinData::default(); - Some(Block::CarvedPumpkin(data)) - } - "minecraft:jack_o_lantern" => { - let data = JackOLanternData::default(); - Some(Block::JackOLantern(data)) - } - "minecraft:cake" => { - let data = CakeData::default(); - Some(Block::Cake(data)) - } - "minecraft:repeater" => { - let data = RepeaterData::default(); - Some(Block::Repeater(data)) - } - "minecraft:white_stained_glass" => Some(Block::WhiteStainedGlass), - "minecraft:orange_stained_glass" => Some(Block::OrangeStainedGlass), - "minecraft:magenta_stained_glass" => Some(Block::MagentaStainedGlass), - "minecraft:light_blue_stained_glass" => Some(Block::LightBlueStainedGlass), - "minecraft:yellow_stained_glass" => Some(Block::YellowStainedGlass), - "minecraft:lime_stained_glass" => Some(Block::LimeStainedGlass), - "minecraft:pink_stained_glass" => Some(Block::PinkStainedGlass), - "minecraft:gray_stained_glass" => Some(Block::GrayStainedGlass), - "minecraft:light_gray_stained_glass" => Some(Block::LightGrayStainedGlass), - "minecraft:cyan_stained_glass" => Some(Block::CyanStainedGlass), - "minecraft:purple_stained_glass" => Some(Block::PurpleStainedGlass), - "minecraft:blue_stained_glass" => Some(Block::BlueStainedGlass), - "minecraft:brown_stained_glass" => Some(Block::BrownStainedGlass), - "minecraft:green_stained_glass" => Some(Block::GreenStainedGlass), - "minecraft:red_stained_glass" => Some(Block::RedStainedGlass), - "minecraft:black_stained_glass" => Some(Block::BlackStainedGlass), - "minecraft:oak_trapdoor" => { - let data = OakTrapdoorData::default(); - Some(Block::OakTrapdoor(data)) - } - "minecraft:spruce_trapdoor" => { - let data = SpruceTrapdoorData::default(); - Some(Block::SpruceTrapdoor(data)) - } - "minecraft:birch_trapdoor" => { - let data = BirchTrapdoorData::default(); - Some(Block::BirchTrapdoor(data)) - } - "minecraft:jungle_trapdoor" => { - let data = JungleTrapdoorData::default(); - Some(Block::JungleTrapdoor(data)) - } - "minecraft:acacia_trapdoor" => { - let data = AcaciaTrapdoorData::default(); - Some(Block::AcaciaTrapdoor(data)) - } - "minecraft:dark_oak_trapdoor" => { - let data = DarkOakTrapdoorData::default(); - Some(Block::DarkOakTrapdoor(data)) - } - "minecraft:infested_stone" => Some(Block::InfestedStone), - "minecraft:infested_cobblestone" => Some(Block::InfestedCobblestone), - "minecraft:infested_stone_bricks" => Some(Block::InfestedStoneBricks), - "minecraft:infested_mossy_stone_bricks" => Some(Block::InfestedMossyStoneBricks), - "minecraft:infested_cracked_stone_bricks" => Some(Block::InfestedCrackedStoneBricks), - "minecraft:infested_chiseled_stone_bricks" => Some(Block::InfestedChiseledStoneBricks), - "minecraft:stone_bricks" => Some(Block::StoneBricks), - "minecraft:mossy_stone_bricks" => Some(Block::MossyStoneBricks), - "minecraft:cracked_stone_bricks" => Some(Block::CrackedStoneBricks), - "minecraft:chiseled_stone_bricks" => Some(Block::ChiseledStoneBricks), - "minecraft:brown_mushroom_block" => { - let data = BrownMushroomBlockData::default(); - Some(Block::BrownMushroomBlock(data)) - } - "minecraft:red_mushroom_block" => { - let data = RedMushroomBlockData::default(); - Some(Block::RedMushroomBlock(data)) - } - "minecraft:mushroom_stem" => { - let data = MushroomStemData::default(); - Some(Block::MushroomStem(data)) - } - "minecraft:iron_bars" => { - let data = IronBarsData::default(); - Some(Block::IronBars(data)) - } - "minecraft:glass_pane" => { - let data = GlassPaneData::default(); - Some(Block::GlassPane(data)) - } - "minecraft:melon" => Some(Block::Melon), - "minecraft:attached_pumpkin_stem" => { - let data = AttachedPumpkinStemData::default(); - Some(Block::AttachedPumpkinStem(data)) - } - "minecraft:attached_melon_stem" => { - let data = AttachedMelonStemData::default(); - Some(Block::AttachedMelonStem(data)) - } - "minecraft:pumpkin_stem" => { - let data = PumpkinStemData::default(); - Some(Block::PumpkinStem(data)) - } - "minecraft:melon_stem" => { - let data = MelonStemData::default(); - Some(Block::MelonStem(data)) - } - "minecraft:vine" => { - let data = VineData::default(); - Some(Block::Vine(data)) - } - "minecraft:oak_fence_gate" => { - let data = OakFenceGateData::default(); - Some(Block::OakFenceGate(data)) - } - "minecraft:brick_stairs" => { - let data = BrickStairsData::default(); - Some(Block::BrickStairs(data)) - } - "minecraft:stone_brick_stairs" => { - let data = StoneBrickStairsData::default(); - Some(Block::StoneBrickStairs(data)) - } - "minecraft:mycelium" => { - let data = MyceliumData::default(); - Some(Block::Mycelium(data)) - } - "minecraft:lily_pad" => Some(Block::LilyPad), - "minecraft:nether_bricks" => Some(Block::NetherBricks), - "minecraft:nether_brick_fence" => { - let data = NetherBrickFenceData::default(); - Some(Block::NetherBrickFence(data)) - } - "minecraft:nether_brick_stairs" => { - let data = NetherBrickStairsData::default(); - Some(Block::NetherBrickStairs(data)) - } - "minecraft:nether_wart" => { - let data = NetherWartData::default(); - Some(Block::NetherWart(data)) - } - "minecraft:enchanting_table" => Some(Block::EnchantingTable), - "minecraft:brewing_stand" => { - let data = BrewingStandData::default(); - Some(Block::BrewingStand(data)) - } - "minecraft:cauldron" => { - let data = CauldronData::default(); - Some(Block::Cauldron(data)) - } - "minecraft:end_portal" => Some(Block::EndPortal), - "minecraft:end_portal_frame" => { - let data = EndPortalFrameData::default(); - Some(Block::EndPortalFrame(data)) - } - "minecraft:end_stone" => Some(Block::EndStone), - "minecraft:dragon_egg" => Some(Block::DragonEgg), - "minecraft:redstone_lamp" => { - let data = RedstoneLampData::default(); - Some(Block::RedstoneLamp(data)) - } - "minecraft:cocoa" => { - let data = CocoaData::default(); - Some(Block::Cocoa(data)) - } - "minecraft:sandstone_stairs" => { - let data = SandstoneStairsData::default(); - Some(Block::SandstoneStairs(data)) - } - "minecraft:emerald_ore" => Some(Block::EmeraldOre), - "minecraft:ender_chest" => { - let data = EnderChestData::default(); - Some(Block::EnderChest(data)) - } - "minecraft:tripwire_hook" => { - let data = TripwireHookData::default(); - Some(Block::TripwireHook(data)) - } - "minecraft:tripwire" => { - let data = TripwireData::default(); - Some(Block::Tripwire(data)) - } - "minecraft:emerald_block" => Some(Block::EmeraldBlock), - "minecraft:spruce_stairs" => { - let data = SpruceStairsData::default(); - Some(Block::SpruceStairs(data)) - } - "minecraft:birch_stairs" => { - let data = BirchStairsData::default(); - Some(Block::BirchStairs(data)) - } - "minecraft:jungle_stairs" => { - let data = JungleStairsData::default(); - Some(Block::JungleStairs(data)) - } - "minecraft:command_block" => { - let data = CommandBlockData::default(); - Some(Block::CommandBlock(data)) - } - "minecraft:beacon" => Some(Block::Beacon), - "minecraft:cobblestone_wall" => { - let data = CobblestoneWallData::default(); - Some(Block::CobblestoneWall(data)) - } - "minecraft:mossy_cobblestone_wall" => { - let data = MossyCobblestoneWallData::default(); - Some(Block::MossyCobblestoneWall(data)) - } - "minecraft:flower_pot" => Some(Block::FlowerPot), - "minecraft:potted_oak_sapling" => Some(Block::PottedOakSapling), - "minecraft:potted_spruce_sapling" => Some(Block::PottedSpruceSapling), - "minecraft:potted_birch_sapling" => Some(Block::PottedBirchSapling), - "minecraft:potted_jungle_sapling" => Some(Block::PottedJungleSapling), - "minecraft:potted_acacia_sapling" => Some(Block::PottedAcaciaSapling), - "minecraft:potted_dark_oak_sapling" => Some(Block::PottedDarkOakSapling), - "minecraft:potted_fern" => Some(Block::PottedFern), - "minecraft:potted_dandelion" => Some(Block::PottedDandelion), - "minecraft:potted_poppy" => Some(Block::PottedPoppy), - "minecraft:potted_blue_orchid" => Some(Block::PottedBlueOrchid), - "minecraft:potted_allium" => Some(Block::PottedAllium), - "minecraft:potted_azure_bluet" => Some(Block::PottedAzureBluet), - "minecraft:potted_red_tulip" => Some(Block::PottedRedTulip), - "minecraft:potted_orange_tulip" => Some(Block::PottedOrangeTulip), - "minecraft:potted_white_tulip" => Some(Block::PottedWhiteTulip), - "minecraft:potted_pink_tulip" => Some(Block::PottedPinkTulip), - "minecraft:potted_oxeye_daisy" => Some(Block::PottedOxeyeDaisy), - "minecraft:potted_red_mushroom" => Some(Block::PottedRedMushroom), - "minecraft:potted_brown_mushroom" => Some(Block::PottedBrownMushroom), - "minecraft:potted_dead_bush" => Some(Block::PottedDeadBush), - "minecraft:potted_cactus" => Some(Block::PottedCactus), - "minecraft:carrots" => { - let data = CarrotsData::default(); - Some(Block::Carrots(data)) - } - "minecraft:potatoes" => { - let data = PotatoesData::default(); - Some(Block::Potatoes(data)) - } - "minecraft:oak_button" => { - let data = OakButtonData::default(); - Some(Block::OakButton(data)) - } - "minecraft:spruce_button" => { - let data = SpruceButtonData::default(); - Some(Block::SpruceButton(data)) - } - "minecraft:birch_button" => { - let data = BirchButtonData::default(); - Some(Block::BirchButton(data)) - } - "minecraft:jungle_button" => { - let data = JungleButtonData::default(); - Some(Block::JungleButton(data)) - } - "minecraft:acacia_button" => { - let data = AcaciaButtonData::default(); - Some(Block::AcaciaButton(data)) - } - "minecraft:dark_oak_button" => { - let data = DarkOakButtonData::default(); - Some(Block::DarkOakButton(data)) - } - "minecraft:skeleton_wall_skull" => { - let data = SkeletonWallSkullData::default(); - Some(Block::SkeletonWallSkull(data)) - } - "minecraft:skeleton_skull" => { - let data = SkeletonSkullData::default(); - Some(Block::SkeletonSkull(data)) - } - "minecraft:wither_skeleton_wall_skull" => { - let data = WitherSkeletonWallSkullData::default(); - Some(Block::WitherSkeletonWallSkull(data)) - } - "minecraft:wither_skeleton_skull" => { - let data = WitherSkeletonSkullData::default(); - Some(Block::WitherSkeletonSkull(data)) - } - "minecraft:zombie_wall_head" => { - let data = ZombieWallHeadData::default(); - Some(Block::ZombieWallHead(data)) - } - "minecraft:zombie_head" => { - let data = ZombieHeadData::default(); - Some(Block::ZombieHead(data)) - } - "minecraft:player_wall_head" => { - let data = PlayerWallHeadData::default(); - Some(Block::PlayerWallHead(data)) - } - "minecraft:player_head" => { - let data = PlayerHeadData::default(); - Some(Block::PlayerHead(data)) - } - "minecraft:creeper_wall_head" => { - let data = CreeperWallHeadData::default(); - Some(Block::CreeperWallHead(data)) - } - "minecraft:creeper_head" => { - let data = CreeperHeadData::default(); - Some(Block::CreeperHead(data)) - } - "minecraft:dragon_wall_head" => { - let data = DragonWallHeadData::default(); - Some(Block::DragonWallHead(data)) - } - "minecraft:dragon_head" => { - let data = DragonHeadData::default(); - Some(Block::DragonHead(data)) - } - "minecraft:anvil" => { - let data = AnvilData::default(); - Some(Block::Anvil(data)) - } - "minecraft:chipped_anvil" => { - let data = ChippedAnvilData::default(); - Some(Block::ChippedAnvil(data)) - } - "minecraft:damaged_anvil" => { - let data = DamagedAnvilData::default(); - Some(Block::DamagedAnvil(data)) - } - "minecraft:trapped_chest" => { - let data = TrappedChestData::default(); - Some(Block::TrappedChest(data)) - } - "minecraft:light_weighted_pressure_plate" => { - let data = LightWeightedPressurePlateData::default(); - Some(Block::LightWeightedPressurePlate(data)) - } - "minecraft:heavy_weighted_pressure_plate" => { - let data = HeavyWeightedPressurePlateData::default(); - Some(Block::HeavyWeightedPressurePlate(data)) - } - "minecraft:comparator" => { - let data = ComparatorData::default(); - Some(Block::Comparator(data)) - } - "minecraft:daylight_detector" => { - let data = DaylightDetectorData::default(); - Some(Block::DaylightDetector(data)) - } - "minecraft:redstone_block" => Some(Block::RedstoneBlock), - "minecraft:nether_quartz_ore" => Some(Block::NetherQuartzOre), - "minecraft:hopper" => { - let data = HopperData::default(); - Some(Block::Hopper(data)) - } - "minecraft:quartz_block" => Some(Block::QuartzBlock), - "minecraft:chiseled_quartz_block" => Some(Block::ChiseledQuartzBlock), - "minecraft:quartz_pillar" => { - let data = QuartzPillarData::default(); - Some(Block::QuartzPillar(data)) - } - "minecraft:quartz_stairs" => { - let data = QuartzStairsData::default(); - Some(Block::QuartzStairs(data)) - } - "minecraft:activator_rail" => { - let data = ActivatorRailData::default(); - Some(Block::ActivatorRail(data)) - } - "minecraft:dropper" => { - let data = DropperData::default(); - Some(Block::Dropper(data)) - } - "minecraft:white_terracotta" => Some(Block::WhiteTerracotta), - "minecraft:orange_terracotta" => Some(Block::OrangeTerracotta), - "minecraft:magenta_terracotta" => Some(Block::MagentaTerracotta), - "minecraft:light_blue_terracotta" => Some(Block::LightBlueTerracotta), - "minecraft:yellow_terracotta" => Some(Block::YellowTerracotta), - "minecraft:lime_terracotta" => Some(Block::LimeTerracotta), - "minecraft:pink_terracotta" => Some(Block::PinkTerracotta), - "minecraft:gray_terracotta" => Some(Block::GrayTerracotta), - "minecraft:light_gray_terracotta" => Some(Block::LightGrayTerracotta), - "minecraft:cyan_terracotta" => Some(Block::CyanTerracotta), - "minecraft:purple_terracotta" => Some(Block::PurpleTerracotta), - "minecraft:blue_terracotta" => Some(Block::BlueTerracotta), - "minecraft:brown_terracotta" => Some(Block::BrownTerracotta), - "minecraft:green_terracotta" => Some(Block::GreenTerracotta), - "minecraft:red_terracotta" => Some(Block::RedTerracotta), - "minecraft:black_terracotta" => Some(Block::BlackTerracotta), - "minecraft:white_stained_glass_pane" => { - let data = WhiteStainedGlassPaneData::default(); - Some(Block::WhiteStainedGlassPane(data)) - } - "minecraft:orange_stained_glass_pane" => { - let data = OrangeStainedGlassPaneData::default(); - Some(Block::OrangeStainedGlassPane(data)) - } - "minecraft:magenta_stained_glass_pane" => { - let data = MagentaStainedGlassPaneData::default(); - Some(Block::MagentaStainedGlassPane(data)) - } - "minecraft:light_blue_stained_glass_pane" => { - let data = LightBlueStainedGlassPaneData::default(); - Some(Block::LightBlueStainedGlassPane(data)) - } - "minecraft:yellow_stained_glass_pane" => { - let data = YellowStainedGlassPaneData::default(); - Some(Block::YellowStainedGlassPane(data)) - } - "minecraft:lime_stained_glass_pane" => { - let data = LimeStainedGlassPaneData::default(); - Some(Block::LimeStainedGlassPane(data)) - } - "minecraft:pink_stained_glass_pane" => { - let data = PinkStainedGlassPaneData::default(); - Some(Block::PinkStainedGlassPane(data)) - } - "minecraft:gray_stained_glass_pane" => { - let data = GrayStainedGlassPaneData::default(); - Some(Block::GrayStainedGlassPane(data)) - } - "minecraft:light_gray_stained_glass_pane" => { - let data = LightGrayStainedGlassPaneData::default(); - Some(Block::LightGrayStainedGlassPane(data)) - } - "minecraft:cyan_stained_glass_pane" => { - let data = CyanStainedGlassPaneData::default(); - Some(Block::CyanStainedGlassPane(data)) - } - "minecraft:purple_stained_glass_pane" => { - let data = PurpleStainedGlassPaneData::default(); - Some(Block::PurpleStainedGlassPane(data)) - } - "minecraft:blue_stained_glass_pane" => { - let data = BlueStainedGlassPaneData::default(); - Some(Block::BlueStainedGlassPane(data)) - } - "minecraft:brown_stained_glass_pane" => { - let data = BrownStainedGlassPaneData::default(); - Some(Block::BrownStainedGlassPane(data)) - } - "minecraft:green_stained_glass_pane" => { - let data = GreenStainedGlassPaneData::default(); - Some(Block::GreenStainedGlassPane(data)) - } - "minecraft:red_stained_glass_pane" => { - let data = RedStainedGlassPaneData::default(); - Some(Block::RedStainedGlassPane(data)) - } - "minecraft:black_stained_glass_pane" => { - let data = BlackStainedGlassPaneData::default(); - Some(Block::BlackStainedGlassPane(data)) - } - "minecraft:acacia_stairs" => { - let data = AcaciaStairsData::default(); - Some(Block::AcaciaStairs(data)) - } - "minecraft:dark_oak_stairs" => { - let data = DarkOakStairsData::default(); - Some(Block::DarkOakStairs(data)) - } - "minecraft:slime_block" => Some(Block::SlimeBlock), - "minecraft:barrier" => Some(Block::Barrier), - "minecraft:iron_trapdoor" => { - let data = IronTrapdoorData::default(); - Some(Block::IronTrapdoor(data)) - } - "minecraft:prismarine" => Some(Block::Prismarine), - "minecraft:prismarine_bricks" => Some(Block::PrismarineBricks), - "minecraft:dark_prismarine" => Some(Block::DarkPrismarine), - "minecraft:prismarine_stairs" => { - let data = PrismarineStairsData::default(); - Some(Block::PrismarineStairs(data)) - } - "minecraft:prismarine_brick_stairs" => { - let data = PrismarineBrickStairsData::default(); - Some(Block::PrismarineBrickStairs(data)) - } - "minecraft:dark_prismarine_stairs" => { - let data = DarkPrismarineStairsData::default(); - Some(Block::DarkPrismarineStairs(data)) - } - "minecraft:prismarine_slab" => { - let data = PrismarineSlabData::default(); - Some(Block::PrismarineSlab(data)) - } - "minecraft:prismarine_brick_slab" => { - let data = PrismarineBrickSlabData::default(); - Some(Block::PrismarineBrickSlab(data)) - } - "minecraft:dark_prismarine_slab" => { - let data = DarkPrismarineSlabData::default(); - Some(Block::DarkPrismarineSlab(data)) - } - "minecraft:sea_lantern" => Some(Block::SeaLantern), - "minecraft:hay_block" => { - let data = HayBlockData::default(); - Some(Block::HayBlock(data)) - } - "minecraft:white_carpet" => Some(Block::WhiteCarpet), - "minecraft:orange_carpet" => Some(Block::OrangeCarpet), - "minecraft:magenta_carpet" => Some(Block::MagentaCarpet), - "minecraft:light_blue_carpet" => Some(Block::LightBlueCarpet), - "minecraft:yellow_carpet" => Some(Block::YellowCarpet), - "minecraft:lime_carpet" => Some(Block::LimeCarpet), - "minecraft:pink_carpet" => Some(Block::PinkCarpet), - "minecraft:gray_carpet" => Some(Block::GrayCarpet), - "minecraft:light_gray_carpet" => Some(Block::LightGrayCarpet), - "minecraft:cyan_carpet" => Some(Block::CyanCarpet), - "minecraft:purple_carpet" => Some(Block::PurpleCarpet), - "minecraft:blue_carpet" => Some(Block::BlueCarpet), - "minecraft:brown_carpet" => Some(Block::BrownCarpet), - "minecraft:green_carpet" => Some(Block::GreenCarpet), - "minecraft:red_carpet" => Some(Block::RedCarpet), - "minecraft:black_carpet" => Some(Block::BlackCarpet), - "minecraft:terracotta" => Some(Block::Terracotta), - "minecraft:coal_block" => Some(Block::CoalBlock), - "minecraft:packed_ice" => Some(Block::PackedIce), - "minecraft:sunflower" => { - let data = SunflowerData::default(); - Some(Block::Sunflower(data)) - } - "minecraft:lilac" => { - let data = LilacData::default(); - Some(Block::Lilac(data)) - } - "minecraft:rose_bush" => { - let data = RoseBushData::default(); - Some(Block::RoseBush(data)) - } - "minecraft:peony" => { - let data = PeonyData::default(); - Some(Block::Peony(data)) - } - "minecraft:tall_grass" => { - let data = TallGrassData::default(); - Some(Block::TallGrass(data)) - } - "minecraft:large_fern" => { - let data = LargeFernData::default(); - Some(Block::LargeFern(data)) - } - "minecraft:white_banner" => { - let data = WhiteBannerData::default(); - Some(Block::WhiteBanner(data)) - } - "minecraft:orange_banner" => { - let data = OrangeBannerData::default(); - Some(Block::OrangeBanner(data)) - } - "minecraft:magenta_banner" => { - let data = MagentaBannerData::default(); - Some(Block::MagentaBanner(data)) - } - "minecraft:light_blue_banner" => { - let data = LightBlueBannerData::default(); - Some(Block::LightBlueBanner(data)) - } - "minecraft:yellow_banner" => { - let data = YellowBannerData::default(); - Some(Block::YellowBanner(data)) - } - "minecraft:lime_banner" => { - let data = LimeBannerData::default(); - Some(Block::LimeBanner(data)) - } - "minecraft:pink_banner" => { - let data = PinkBannerData::default(); - Some(Block::PinkBanner(data)) - } - "minecraft:gray_banner" => { - let data = GrayBannerData::default(); - Some(Block::GrayBanner(data)) - } - "minecraft:light_gray_banner" => { - let data = LightGrayBannerData::default(); - Some(Block::LightGrayBanner(data)) - } - "minecraft:cyan_banner" => { - let data = CyanBannerData::default(); - Some(Block::CyanBanner(data)) - } - "minecraft:purple_banner" => { - let data = PurpleBannerData::default(); - Some(Block::PurpleBanner(data)) - } - "minecraft:blue_banner" => { - let data = BlueBannerData::default(); - Some(Block::BlueBanner(data)) - } - "minecraft:brown_banner" => { - let data = BrownBannerData::default(); - Some(Block::BrownBanner(data)) - } - "minecraft:green_banner" => { - let data = GreenBannerData::default(); - Some(Block::GreenBanner(data)) - } - "minecraft:red_banner" => { - let data = RedBannerData::default(); - Some(Block::RedBanner(data)) - } - "minecraft:black_banner" => { - let data = BlackBannerData::default(); - Some(Block::BlackBanner(data)) - } - "minecraft:white_wall_banner" => { - let data = WhiteWallBannerData::default(); - Some(Block::WhiteWallBanner(data)) - } - "minecraft:orange_wall_banner" => { - let data = OrangeWallBannerData::default(); - Some(Block::OrangeWallBanner(data)) - } - "minecraft:magenta_wall_banner" => { - let data = MagentaWallBannerData::default(); - Some(Block::MagentaWallBanner(data)) - } - "minecraft:light_blue_wall_banner" => { - let data = LightBlueWallBannerData::default(); - Some(Block::LightBlueWallBanner(data)) - } - "minecraft:yellow_wall_banner" => { - let data = YellowWallBannerData::default(); - Some(Block::YellowWallBanner(data)) - } - "minecraft:lime_wall_banner" => { - let data = LimeWallBannerData::default(); - Some(Block::LimeWallBanner(data)) - } - "minecraft:pink_wall_banner" => { - let data = PinkWallBannerData::default(); - Some(Block::PinkWallBanner(data)) - } - "minecraft:gray_wall_banner" => { - let data = GrayWallBannerData::default(); - Some(Block::GrayWallBanner(data)) - } - "minecraft:light_gray_wall_banner" => { - let data = LightGrayWallBannerData::default(); - Some(Block::LightGrayWallBanner(data)) - } - "minecraft:cyan_wall_banner" => { - let data = CyanWallBannerData::default(); - Some(Block::CyanWallBanner(data)) - } - "minecraft:purple_wall_banner" => { - let data = PurpleWallBannerData::default(); - Some(Block::PurpleWallBanner(data)) - } - "minecraft:blue_wall_banner" => { - let data = BlueWallBannerData::default(); - Some(Block::BlueWallBanner(data)) - } - "minecraft:brown_wall_banner" => { - let data = BrownWallBannerData::default(); - Some(Block::BrownWallBanner(data)) - } - "minecraft:green_wall_banner" => { - let data = GreenWallBannerData::default(); - Some(Block::GreenWallBanner(data)) - } - "minecraft:red_wall_banner" => { - let data = RedWallBannerData::default(); - Some(Block::RedWallBanner(data)) - } - "minecraft:black_wall_banner" => { - let data = BlackWallBannerData::default(); - Some(Block::BlackWallBanner(data)) - } - "minecraft:red_sandstone" => Some(Block::RedSandstone), - "minecraft:chiseled_red_sandstone" => Some(Block::ChiseledRedSandstone), - "minecraft:cut_red_sandstone" => Some(Block::CutRedSandstone), - "minecraft:red_sandstone_stairs" => { - let data = RedSandstoneStairsData::default(); - Some(Block::RedSandstoneStairs(data)) - } - "minecraft:oak_slab" => { - let data = OakSlabData::default(); - Some(Block::OakSlab(data)) - } - "minecraft:spruce_slab" => { - let data = SpruceSlabData::default(); - Some(Block::SpruceSlab(data)) - } - "minecraft:birch_slab" => { - let data = BirchSlabData::default(); - Some(Block::BirchSlab(data)) - } - "minecraft:jungle_slab" => { - let data = JungleSlabData::default(); - Some(Block::JungleSlab(data)) - } - "minecraft:acacia_slab" => { - let data = AcaciaSlabData::default(); - Some(Block::AcaciaSlab(data)) - } - "minecraft:dark_oak_slab" => { - let data = DarkOakSlabData::default(); - Some(Block::DarkOakSlab(data)) - } - "minecraft:stone_slab" => { - let data = StoneSlabData::default(); - Some(Block::StoneSlab(data)) - } - "minecraft:sandstone_slab" => { - let data = SandstoneSlabData::default(); - Some(Block::SandstoneSlab(data)) - } - "minecraft:petrified_oak_slab" => { - let data = PetrifiedOakSlabData::default(); - Some(Block::PetrifiedOakSlab(data)) - } - "minecraft:cobblestone_slab" => { - let data = CobblestoneSlabData::default(); - Some(Block::CobblestoneSlab(data)) - } - "minecraft:brick_slab" => { - let data = BrickSlabData::default(); - Some(Block::BrickSlab(data)) - } - "minecraft:stone_brick_slab" => { - let data = StoneBrickSlabData::default(); - Some(Block::StoneBrickSlab(data)) - } - "minecraft:nether_brick_slab" => { - let data = NetherBrickSlabData::default(); - Some(Block::NetherBrickSlab(data)) - } - "minecraft:quartz_slab" => { - let data = QuartzSlabData::default(); - Some(Block::QuartzSlab(data)) - } - "minecraft:red_sandstone_slab" => { - let data = RedSandstoneSlabData::default(); - Some(Block::RedSandstoneSlab(data)) - } - "minecraft:purpur_slab" => { - let data = PurpurSlabData::default(); - Some(Block::PurpurSlab(data)) - } - "minecraft:smooth_stone" => Some(Block::SmoothStone), - "minecraft:smooth_sandstone" => Some(Block::SmoothSandstone), - "minecraft:smooth_quartz" => Some(Block::SmoothQuartz), - "minecraft:smooth_red_sandstone" => Some(Block::SmoothRedSandstone), - "minecraft:spruce_fence_gate" => { - let data = SpruceFenceGateData::default(); - Some(Block::SpruceFenceGate(data)) - } - "minecraft:birch_fence_gate" => { - let data = BirchFenceGateData::default(); - Some(Block::BirchFenceGate(data)) - } - "minecraft:jungle_fence_gate" => { - let data = JungleFenceGateData::default(); - Some(Block::JungleFenceGate(data)) - } - "minecraft:acacia_fence_gate" => { - let data = AcaciaFenceGateData::default(); - Some(Block::AcaciaFenceGate(data)) - } - "minecraft:dark_oak_fence_gate" => { - let data = DarkOakFenceGateData::default(); - Some(Block::DarkOakFenceGate(data)) - } - "minecraft:spruce_fence" => { - let data = SpruceFenceData::default(); - Some(Block::SpruceFence(data)) - } - "minecraft:birch_fence" => { - let data = BirchFenceData::default(); - Some(Block::BirchFence(data)) - } - "minecraft:jungle_fence" => { - let data = JungleFenceData::default(); - Some(Block::JungleFence(data)) - } - "minecraft:acacia_fence" => { - let data = AcaciaFenceData::default(); - Some(Block::AcaciaFence(data)) - } - "minecraft:dark_oak_fence" => { - let data = DarkOakFenceData::default(); - Some(Block::DarkOakFence(data)) - } - "minecraft:spruce_door" => { - let data = SpruceDoorData::default(); - Some(Block::SpruceDoor(data)) - } - "minecraft:birch_door" => { - let data = BirchDoorData::default(); - Some(Block::BirchDoor(data)) - } - "minecraft:jungle_door" => { - let data = JungleDoorData::default(); - Some(Block::JungleDoor(data)) - } - "minecraft:acacia_door" => { - let data = AcaciaDoorData::default(); - Some(Block::AcaciaDoor(data)) - } - "minecraft:dark_oak_door" => { - let data = DarkOakDoorData::default(); - Some(Block::DarkOakDoor(data)) - } - "minecraft:end_rod" => { - let data = EndRodData::default(); - Some(Block::EndRod(data)) - } - "minecraft:chorus_plant" => { - let data = ChorusPlantData::default(); - Some(Block::ChorusPlant(data)) - } - "minecraft:chorus_flower" => { - let data = ChorusFlowerData::default(); - Some(Block::ChorusFlower(data)) - } - "minecraft:purpur_block" => Some(Block::PurpurBlock), - "minecraft:purpur_pillar" => { - let data = PurpurPillarData::default(); - Some(Block::PurpurPillar(data)) - } - "minecraft:purpur_stairs" => { - let data = PurpurStairsData::default(); - Some(Block::PurpurStairs(data)) - } - "minecraft:end_stone_bricks" => Some(Block::EndStoneBricks), - "minecraft:beetroots" => { - let data = BeetrootsData::default(); - Some(Block::Beetroots(data)) - } - "minecraft:grass_path" => Some(Block::GrassPath), - "minecraft:end_gateway" => Some(Block::EndGateway), - "minecraft:repeating_command_block" => { - let data = RepeatingCommandBlockData::default(); - Some(Block::RepeatingCommandBlock(data)) - } - "minecraft:chain_command_block" => { - let data = ChainCommandBlockData::default(); - Some(Block::ChainCommandBlock(data)) - } - "minecraft:frosted_ice" => { - let data = FrostedIceData::default(); - Some(Block::FrostedIce(data)) - } - "minecraft:magma_block" => Some(Block::MagmaBlock), - "minecraft:nether_wart_block" => Some(Block::NetherWartBlock), - "minecraft:red_nether_bricks" => Some(Block::RedNetherBricks), - "minecraft:bone_block" => { - let data = BoneBlockData::default(); - Some(Block::BoneBlock(data)) - } - "minecraft:structure_void" => Some(Block::StructureVoid), - "minecraft:observer" => { - let data = ObserverData::default(); - Some(Block::Observer(data)) - } - "minecraft:shulker_box" => { - let data = ShulkerBoxData::default(); - Some(Block::ShulkerBox(data)) - } - "minecraft:white_shulker_box" => { - let data = WhiteShulkerBoxData::default(); - Some(Block::WhiteShulkerBox(data)) - } - "minecraft:orange_shulker_box" => { - let data = OrangeShulkerBoxData::default(); - Some(Block::OrangeShulkerBox(data)) - } - "minecraft:magenta_shulker_box" => { - let data = MagentaShulkerBoxData::default(); - Some(Block::MagentaShulkerBox(data)) - } - "minecraft:light_blue_shulker_box" => { - let data = LightBlueShulkerBoxData::default(); - Some(Block::LightBlueShulkerBox(data)) - } - "minecraft:yellow_shulker_box" => { - let data = YellowShulkerBoxData::default(); - Some(Block::YellowShulkerBox(data)) - } - "minecraft:lime_shulker_box" => { - let data = LimeShulkerBoxData::default(); - Some(Block::LimeShulkerBox(data)) - } - "minecraft:pink_shulker_box" => { - let data = PinkShulkerBoxData::default(); - Some(Block::PinkShulkerBox(data)) - } - "minecraft:gray_shulker_box" => { - let data = GrayShulkerBoxData::default(); - Some(Block::GrayShulkerBox(data)) - } - "minecraft:light_gray_shulker_box" => { - let data = LightGrayShulkerBoxData::default(); - Some(Block::LightGrayShulkerBox(data)) - } - "minecraft:cyan_shulker_box" => { - let data = CyanShulkerBoxData::default(); - Some(Block::CyanShulkerBox(data)) - } - "minecraft:purple_shulker_box" => { - let data = PurpleShulkerBoxData::default(); - Some(Block::PurpleShulkerBox(data)) - } - "minecraft:blue_shulker_box" => { - let data = BlueShulkerBoxData::default(); - Some(Block::BlueShulkerBox(data)) - } - "minecraft:brown_shulker_box" => { - let data = BrownShulkerBoxData::default(); - Some(Block::BrownShulkerBox(data)) - } - "minecraft:green_shulker_box" => { - let data = GreenShulkerBoxData::default(); - Some(Block::GreenShulkerBox(data)) - } - "minecraft:red_shulker_box" => { - let data = RedShulkerBoxData::default(); - Some(Block::RedShulkerBox(data)) - } - "minecraft:black_shulker_box" => { - let data = BlackShulkerBoxData::default(); - Some(Block::BlackShulkerBox(data)) - } - "minecraft:white_glazed_terracotta" => { - let data = WhiteGlazedTerracottaData::default(); - Some(Block::WhiteGlazedTerracotta(data)) - } - "minecraft:orange_glazed_terracotta" => { - let data = OrangeGlazedTerracottaData::default(); - Some(Block::OrangeGlazedTerracotta(data)) - } - "minecraft:magenta_glazed_terracotta" => { - let data = MagentaGlazedTerracottaData::default(); - Some(Block::MagentaGlazedTerracotta(data)) - } - "minecraft:light_blue_glazed_terracotta" => { - let data = LightBlueGlazedTerracottaData::default(); - Some(Block::LightBlueGlazedTerracotta(data)) - } - "minecraft:yellow_glazed_terracotta" => { - let data = YellowGlazedTerracottaData::default(); - Some(Block::YellowGlazedTerracotta(data)) - } - "minecraft:lime_glazed_terracotta" => { - let data = LimeGlazedTerracottaData::default(); - Some(Block::LimeGlazedTerracotta(data)) - } - "minecraft:pink_glazed_terracotta" => { - let data = PinkGlazedTerracottaData::default(); - Some(Block::PinkGlazedTerracotta(data)) - } - "minecraft:gray_glazed_terracotta" => { - let data = GrayGlazedTerracottaData::default(); - Some(Block::GrayGlazedTerracotta(data)) - } - "minecraft:light_gray_glazed_terracotta" => { - let data = LightGrayGlazedTerracottaData::default(); - Some(Block::LightGrayGlazedTerracotta(data)) - } - "minecraft:cyan_glazed_terracotta" => { - let data = CyanGlazedTerracottaData::default(); - Some(Block::CyanGlazedTerracotta(data)) - } - "minecraft:purple_glazed_terracotta" => { - let data = PurpleGlazedTerracottaData::default(); - Some(Block::PurpleGlazedTerracotta(data)) - } - "minecraft:blue_glazed_terracotta" => { - let data = BlueGlazedTerracottaData::default(); - Some(Block::BlueGlazedTerracotta(data)) - } - "minecraft:brown_glazed_terracotta" => { - let data = BrownGlazedTerracottaData::default(); - Some(Block::BrownGlazedTerracotta(data)) - } - "minecraft:green_glazed_terracotta" => { - let data = GreenGlazedTerracottaData::default(); - Some(Block::GreenGlazedTerracotta(data)) - } - "minecraft:red_glazed_terracotta" => { - let data = RedGlazedTerracottaData::default(); - Some(Block::RedGlazedTerracotta(data)) - } - "minecraft:black_glazed_terracotta" => { - let data = BlackGlazedTerracottaData::default(); - Some(Block::BlackGlazedTerracotta(data)) - } - "minecraft:white_concrete" => Some(Block::WhiteConcrete), - "minecraft:orange_concrete" => Some(Block::OrangeConcrete), - "minecraft:magenta_concrete" => Some(Block::MagentaConcrete), - "minecraft:light_blue_concrete" => Some(Block::LightBlueConcrete), - "minecraft:yellow_concrete" => Some(Block::YellowConcrete), - "minecraft:lime_concrete" => Some(Block::LimeConcrete), - "minecraft:pink_concrete" => Some(Block::PinkConcrete), - "minecraft:gray_concrete" => Some(Block::GrayConcrete), - "minecraft:light_gray_concrete" => Some(Block::LightGrayConcrete), - "minecraft:cyan_concrete" => Some(Block::CyanConcrete), - "minecraft:purple_concrete" => Some(Block::PurpleConcrete), - "minecraft:blue_concrete" => Some(Block::BlueConcrete), - "minecraft:brown_concrete" => Some(Block::BrownConcrete), - "minecraft:green_concrete" => Some(Block::GreenConcrete), - "minecraft:red_concrete" => Some(Block::RedConcrete), - "minecraft:black_concrete" => Some(Block::BlackConcrete), - "minecraft:white_concrete_powder" => Some(Block::WhiteConcretePowder), - "minecraft:orange_concrete_powder" => Some(Block::OrangeConcretePowder), - "minecraft:magenta_concrete_powder" => Some(Block::MagentaConcretePowder), - "minecraft:light_blue_concrete_powder" => Some(Block::LightBlueConcretePowder), - "minecraft:yellow_concrete_powder" => Some(Block::YellowConcretePowder), - "minecraft:lime_concrete_powder" => Some(Block::LimeConcretePowder), - "minecraft:pink_concrete_powder" => Some(Block::PinkConcretePowder), - "minecraft:gray_concrete_powder" => Some(Block::GrayConcretePowder), - "minecraft:light_gray_concrete_powder" => Some(Block::LightGrayConcretePowder), - "minecraft:cyan_concrete_powder" => Some(Block::CyanConcretePowder), - "minecraft:purple_concrete_powder" => Some(Block::PurpleConcretePowder), - "minecraft:blue_concrete_powder" => Some(Block::BlueConcretePowder), - "minecraft:brown_concrete_powder" => Some(Block::BrownConcretePowder), - "minecraft:green_concrete_powder" => Some(Block::GreenConcretePowder), - "minecraft:red_concrete_powder" => Some(Block::RedConcretePowder), - "minecraft:black_concrete_powder" => Some(Block::BlackConcretePowder), - "minecraft:kelp" => { - let data = KelpData::default(); - Some(Block::Kelp(data)) - } - "minecraft:kelp_plant" => Some(Block::KelpPlant), - "minecraft:dried_kelp_block" => Some(Block::DriedKelpBlock), - "minecraft:turtle_egg" => { - let data = TurtleEggData::default(); - Some(Block::TurtleEgg(data)) - } - "minecraft:dead_tube_coral_block" => Some(Block::DeadTubeCoralBlock), - "minecraft:dead_brain_coral_block" => Some(Block::DeadBrainCoralBlock), - "minecraft:dead_bubble_coral_block" => Some(Block::DeadBubbleCoralBlock), - "minecraft:dead_fire_coral_block" => Some(Block::DeadFireCoralBlock), - "minecraft:dead_horn_coral_block" => Some(Block::DeadHornCoralBlock), - "minecraft:tube_coral_block" => Some(Block::TubeCoralBlock), - "minecraft:brain_coral_block" => Some(Block::BrainCoralBlock), - "minecraft:bubble_coral_block" => Some(Block::BubbleCoralBlock), - "minecraft:fire_coral_block" => Some(Block::FireCoralBlock), - "minecraft:horn_coral_block" => Some(Block::HornCoralBlock), - "minecraft:dead_tube_coral" => { - let data = DeadTubeCoralData::default(); - Some(Block::DeadTubeCoral(data)) - } - "minecraft:dead_brain_coral" => { - let data = DeadBrainCoralData::default(); - Some(Block::DeadBrainCoral(data)) - } - "minecraft:dead_bubble_coral" => { - let data = DeadBubbleCoralData::default(); - Some(Block::DeadBubbleCoral(data)) - } - "minecraft:dead_fire_coral" => { - let data = DeadFireCoralData::default(); - Some(Block::DeadFireCoral(data)) - } - "minecraft:dead_horn_coral" => { - let data = DeadHornCoralData::default(); - Some(Block::DeadHornCoral(data)) - } - "minecraft:tube_coral" => { - let data = TubeCoralData::default(); - Some(Block::TubeCoral(data)) - } - "minecraft:brain_coral" => { - let data = BrainCoralData::default(); - Some(Block::BrainCoral(data)) - } - "minecraft:bubble_coral" => { - let data = BubbleCoralData::default(); - Some(Block::BubbleCoral(data)) - } - "minecraft:fire_coral" => { - let data = FireCoralData::default(); - Some(Block::FireCoral(data)) - } - "minecraft:horn_coral" => { - let data = HornCoralData::default(); - Some(Block::HornCoral(data)) - } - "minecraft:dead_tube_coral_wall_fan" => { - let data = DeadTubeCoralWallFanData::default(); - Some(Block::DeadTubeCoralWallFan(data)) - } - "minecraft:dead_brain_coral_wall_fan" => { - let data = DeadBrainCoralWallFanData::default(); - Some(Block::DeadBrainCoralWallFan(data)) - } - "minecraft:dead_bubble_coral_wall_fan" => { - let data = DeadBubbleCoralWallFanData::default(); - Some(Block::DeadBubbleCoralWallFan(data)) - } - "minecraft:dead_fire_coral_wall_fan" => { - let data = DeadFireCoralWallFanData::default(); - Some(Block::DeadFireCoralWallFan(data)) - } - "minecraft:dead_horn_coral_wall_fan" => { - let data = DeadHornCoralWallFanData::default(); - Some(Block::DeadHornCoralWallFan(data)) - } - "minecraft:tube_coral_wall_fan" => { - let data = TubeCoralWallFanData::default(); - Some(Block::TubeCoralWallFan(data)) - } - "minecraft:brain_coral_wall_fan" => { - let data = BrainCoralWallFanData::default(); - Some(Block::BrainCoralWallFan(data)) - } - "minecraft:bubble_coral_wall_fan" => { - let data = BubbleCoralWallFanData::default(); - Some(Block::BubbleCoralWallFan(data)) - } - "minecraft:fire_coral_wall_fan" => { - let data = FireCoralWallFanData::default(); - Some(Block::FireCoralWallFan(data)) - } - "minecraft:horn_coral_wall_fan" => { - let data = HornCoralWallFanData::default(); - Some(Block::HornCoralWallFan(data)) - } - "minecraft:dead_tube_coral_fan" => { - let data = DeadTubeCoralFanData::default(); - Some(Block::DeadTubeCoralFan(data)) - } - "minecraft:dead_brain_coral_fan" => { - let data = DeadBrainCoralFanData::default(); - Some(Block::DeadBrainCoralFan(data)) - } - "minecraft:dead_bubble_coral_fan" => { - let data = DeadBubbleCoralFanData::default(); - Some(Block::DeadBubbleCoralFan(data)) - } - "minecraft:dead_fire_coral_fan" => { - let data = DeadFireCoralFanData::default(); - Some(Block::DeadFireCoralFan(data)) - } - "minecraft:dead_horn_coral_fan" => { - let data = DeadHornCoralFanData::default(); - Some(Block::DeadHornCoralFan(data)) - } - "minecraft:tube_coral_fan" => { - let data = TubeCoralFanData::default(); - Some(Block::TubeCoralFan(data)) - } - "minecraft:brain_coral_fan" => { - let data = BrainCoralFanData::default(); - Some(Block::BrainCoralFan(data)) - } - "minecraft:bubble_coral_fan" => { - let data = BubbleCoralFanData::default(); - Some(Block::BubbleCoralFan(data)) - } - "minecraft:fire_coral_fan" => { - let data = FireCoralFanData::default(); - Some(Block::FireCoralFan(data)) - } - "minecraft:horn_coral_fan" => { - let data = HornCoralFanData::default(); - Some(Block::HornCoralFan(data)) - } - "minecraft:sea_pickle" => { - let data = SeaPickleData::default(); - Some(Block::SeaPickle(data)) - } - "minecraft:blue_ice" => Some(Block::BlueIce), - "minecraft:conduit" => { - let data = ConduitData::default(); - Some(Block::Conduit(data)) - } - "minecraft:void_air" => Some(Block::VoidAir), - "minecraft:cave_air" => Some(Block::CaveAir), - "minecraft:bubble_column" => { - let data = BubbleColumnData::default(); - Some(Block::BubbleColumn(data)) - } - "minecraft:structure_block" => { - let data = StructureBlockData::default(); - Some(Block::StructureBlock(data)) - } - _ => None, - } - } - pub fn from_internal_state_id(id: usize) -> Option { - match id { - 0usize => Some(Block::Air), - 1usize => Some(Block::Stone), - 2usize => Some(Block::Granite), - 3usize => Some(Block::PolishedGranite), - 4usize => Some(Block::Diorite), - 5usize => Some(Block::PolishedDiorite), - 6usize => Some(Block::Andesite), - 7usize => Some(Block::PolishedAndesite), - 8usize..=9usize => { - let offset = id - 8usize; - let data = GrassBlockData::from_value(offset)?; - Some(Block::GrassBlock(data)) - } - 10usize => Some(Block::Dirt), - 11usize => Some(Block::CoarseDirt), - 12usize..=13usize => { - let offset = id - 12usize; - let data = PodzolData::from_value(offset)?; - Some(Block::Podzol(data)) - } - 14usize => Some(Block::Cobblestone), - 15usize => Some(Block::OakPlanks), - 16usize => Some(Block::SprucePlanks), - 17usize => Some(Block::BirchPlanks), - 18usize => Some(Block::JunglePlanks), - 19usize => Some(Block::AcaciaPlanks), - 20usize => Some(Block::DarkOakPlanks), - 21usize..=22usize => { - let offset = id - 21usize; - let data = OakSaplingData::from_value(offset)?; - Some(Block::OakSapling(data)) - } - 23usize..=24usize => { - let offset = id - 23usize; - let data = SpruceSaplingData::from_value(offset)?; - Some(Block::SpruceSapling(data)) - } - 25usize..=26usize => { - let offset = id - 25usize; - let data = BirchSaplingData::from_value(offset)?; - Some(Block::BirchSapling(data)) - } - 27usize..=28usize => { - let offset = id - 27usize; - let data = JungleSaplingData::from_value(offset)?; - Some(Block::JungleSapling(data)) - } - 29usize..=30usize => { - let offset = id - 29usize; - let data = AcaciaSaplingData::from_value(offset)?; - Some(Block::AcaciaSapling(data)) - } - 31usize..=32usize => { - let offset = id - 31usize; - let data = DarkOakSaplingData::from_value(offset)?; - Some(Block::DarkOakSapling(data)) - } - 33usize => Some(Block::Bedrock), - 34usize..=49usize => { - let offset = id - 34usize; - let data = WaterData::from_value(offset)?; - Some(Block::Water(data)) - } - 50usize..=65usize => { - let offset = id - 50usize; - let data = LavaData::from_value(offset)?; - Some(Block::Lava(data)) - } - 66usize => Some(Block::Sand), - 67usize => Some(Block::RedSand), - 68usize => Some(Block::Gravel), - 69usize => Some(Block::GoldOre), - 70usize => Some(Block::IronOre), - 71usize => Some(Block::CoalOre), - 72usize..=74usize => { - let offset = id - 72usize; - let data = OakLogData::from_value(offset)?; - Some(Block::OakLog(data)) - } - 75usize..=77usize => { - let offset = id - 75usize; - let data = SpruceLogData::from_value(offset)?; - Some(Block::SpruceLog(data)) - } - 78usize..=80usize => { - let offset = id - 78usize; - let data = BirchLogData::from_value(offset)?; - Some(Block::BirchLog(data)) - } - 81usize..=83usize => { - let offset = id - 81usize; - let data = JungleLogData::from_value(offset)?; - Some(Block::JungleLog(data)) - } - 84usize..=86usize => { - let offset = id - 84usize; - let data = AcaciaLogData::from_value(offset)?; - Some(Block::AcaciaLog(data)) - } - 87usize..=89usize => { - let offset = id - 87usize; - let data = DarkOakLogData::from_value(offset)?; - Some(Block::DarkOakLog(data)) - } - 90usize..=92usize => { - let offset = id - 90usize; - let data = StrippedSpruceLogData::from_value(offset)?; - Some(Block::StrippedSpruceLog(data)) - } - 93usize..=95usize => { - let offset = id - 93usize; - let data = StrippedBirchLogData::from_value(offset)?; - Some(Block::StrippedBirchLog(data)) - } - 96usize..=98usize => { - let offset = id - 96usize; - let data = StrippedJungleLogData::from_value(offset)?; - Some(Block::StrippedJungleLog(data)) - } - 99usize..=101usize => { - let offset = id - 99usize; - let data = StrippedAcaciaLogData::from_value(offset)?; - Some(Block::StrippedAcaciaLog(data)) - } - 102usize..=104usize => { - let offset = id - 102usize; - let data = StrippedDarkOakLogData::from_value(offset)?; - Some(Block::StrippedDarkOakLog(data)) - } - 105usize..=107usize => { - let offset = id - 105usize; - let data = StrippedOakLogData::from_value(offset)?; - Some(Block::StrippedOakLog(data)) - } - 108usize..=110usize => { - let offset = id - 108usize; - let data = OakWoodData::from_value(offset)?; - Some(Block::OakWood(data)) - } - 111usize..=113usize => { - let offset = id - 111usize; - let data = SpruceWoodData::from_value(offset)?; - Some(Block::SpruceWood(data)) - } - 114usize..=116usize => { - let offset = id - 114usize; - let data = BirchWoodData::from_value(offset)?; - Some(Block::BirchWood(data)) - } - 117usize..=119usize => { - let offset = id - 117usize; - let data = JungleWoodData::from_value(offset)?; - Some(Block::JungleWood(data)) - } - 120usize..=122usize => { - let offset = id - 120usize; - let data = AcaciaWoodData::from_value(offset)?; - Some(Block::AcaciaWood(data)) - } - 123usize..=125usize => { - let offset = id - 123usize; - let data = DarkOakWoodData::from_value(offset)?; - Some(Block::DarkOakWood(data)) - } - 126usize..=128usize => { - let offset = id - 126usize; - let data = StrippedOakWoodData::from_value(offset)?; - Some(Block::StrippedOakWood(data)) - } - 129usize..=131usize => { - let offset = id - 129usize; - let data = StrippedSpruceWoodData::from_value(offset)?; - Some(Block::StrippedSpruceWood(data)) - } - 132usize..=134usize => { - let offset = id - 132usize; - let data = StrippedBirchWoodData::from_value(offset)?; - Some(Block::StrippedBirchWood(data)) - } - 135usize..=137usize => { - let offset = id - 135usize; - let data = StrippedJungleWoodData::from_value(offset)?; - Some(Block::StrippedJungleWood(data)) - } - 138usize..=140usize => { - let offset = id - 138usize; - let data = StrippedAcaciaWoodData::from_value(offset)?; - Some(Block::StrippedAcaciaWood(data)) - } - 141usize..=143usize => { - let offset = id - 141usize; - let data = StrippedDarkOakWoodData::from_value(offset)?; - Some(Block::StrippedDarkOakWood(data)) - } - 144usize..=157usize => { - let offset = id - 144usize; - let data = OakLeavesData::from_value(offset)?; - Some(Block::OakLeaves(data)) - } - 158usize..=171usize => { - let offset = id - 158usize; - let data = SpruceLeavesData::from_value(offset)?; - Some(Block::SpruceLeaves(data)) - } - 172usize..=185usize => { - let offset = id - 172usize; - let data = BirchLeavesData::from_value(offset)?; - Some(Block::BirchLeaves(data)) - } - 186usize..=199usize => { - let offset = id - 186usize; - let data = JungleLeavesData::from_value(offset)?; - Some(Block::JungleLeaves(data)) - } - 200usize..=213usize => { - let offset = id - 200usize; - let data = AcaciaLeavesData::from_value(offset)?; - Some(Block::AcaciaLeaves(data)) - } - 214usize..=227usize => { - let offset = id - 214usize; - let data = DarkOakLeavesData::from_value(offset)?; - Some(Block::DarkOakLeaves(data)) - } - 228usize => Some(Block::Sponge), - 229usize => Some(Block::WetSponge), - 230usize => Some(Block::Glass), - 231usize => Some(Block::LapisOre), - 232usize => Some(Block::LapisBlock), - 233usize..=244usize => { - let offset = id - 233usize; - let data = DispenserData::from_value(offset)?; - Some(Block::Dispenser(data)) - } - 245usize => Some(Block::Sandstone), - 246usize => Some(Block::ChiseledSandstone), - 247usize => Some(Block::CutSandstone), - 248usize..=747usize => { - let offset = id - 248usize; - let data = NoteBlockData::from_value(offset)?; - Some(Block::NoteBlock(data)) - } - 748usize..=763usize => { - let offset = id - 748usize; - let data = WhiteBedData::from_value(offset)?; - Some(Block::WhiteBed(data)) - } - 764usize..=779usize => { - let offset = id - 764usize; - let data = OrangeBedData::from_value(offset)?; - Some(Block::OrangeBed(data)) - } - 780usize..=795usize => { - let offset = id - 780usize; - let data = MagentaBedData::from_value(offset)?; - Some(Block::MagentaBed(data)) - } - 796usize..=811usize => { - let offset = id - 796usize; - let data = LightBlueBedData::from_value(offset)?; - Some(Block::LightBlueBed(data)) - } - 812usize..=827usize => { - let offset = id - 812usize; - let data = YellowBedData::from_value(offset)?; - Some(Block::YellowBed(data)) - } - 828usize..=843usize => { - let offset = id - 828usize; - let data = LimeBedData::from_value(offset)?; - Some(Block::LimeBed(data)) - } - 844usize..=859usize => { - let offset = id - 844usize; - let data = PinkBedData::from_value(offset)?; - Some(Block::PinkBed(data)) - } - 860usize..=875usize => { - let offset = id - 860usize; - let data = GrayBedData::from_value(offset)?; - Some(Block::GrayBed(data)) - } - 876usize..=891usize => { - let offset = id - 876usize; - let data = LightGrayBedData::from_value(offset)?; - Some(Block::LightGrayBed(data)) - } - 892usize..=907usize => { - let offset = id - 892usize; - let data = CyanBedData::from_value(offset)?; - Some(Block::CyanBed(data)) - } - 908usize..=923usize => { - let offset = id - 908usize; - let data = PurpleBedData::from_value(offset)?; - Some(Block::PurpleBed(data)) - } - 924usize..=939usize => { - let offset = id - 924usize; - let data = BlueBedData::from_value(offset)?; - Some(Block::BlueBed(data)) - } - 940usize..=955usize => { - let offset = id - 940usize; - let data = BrownBedData::from_value(offset)?; - Some(Block::BrownBed(data)) - } - 956usize..=971usize => { - let offset = id - 956usize; - let data = GreenBedData::from_value(offset)?; - Some(Block::GreenBed(data)) - } - 972usize..=987usize => { - let offset = id - 972usize; - let data = RedBedData::from_value(offset)?; - Some(Block::RedBed(data)) - } - 988usize..=1003usize => { - let offset = id - 988usize; - let data = BlackBedData::from_value(offset)?; - Some(Block::BlackBed(data)) - } - 1004usize..=1015usize => { - let offset = id - 1004usize; - let data = PoweredRailData::from_value(offset)?; - Some(Block::PoweredRail(data)) - } - 1016usize..=1027usize => { - let offset = id - 1016usize; - let data = DetectorRailData::from_value(offset)?; - Some(Block::DetectorRail(data)) - } - 1028usize..=1039usize => { - let offset = id - 1028usize; - let data = StickyPistonData::from_value(offset)?; - Some(Block::StickyPiston(data)) - } - 1040usize => Some(Block::Cobweb), - 1041usize => Some(Block::Grass), - 1042usize => Some(Block::Fern), - 1043usize => Some(Block::DeadBush), - 1044usize => Some(Block::Seagrass), - 1045usize..=1046usize => { - let offset = id - 1045usize; - let data = TallSeagrassData::from_value(offset)?; - Some(Block::TallSeagrass(data)) - } - 1047usize..=1058usize => { - let offset = id - 1047usize; - let data = PistonData::from_value(offset)?; - Some(Block::Piston(data)) - } - 1059usize..=1082usize => { - let offset = id - 1059usize; - let data = PistonHeadData::from_value(offset)?; - Some(Block::PistonHead(data)) - } - 1083usize => Some(Block::WhiteWool), - 1084usize => Some(Block::OrangeWool), - 1085usize => Some(Block::MagentaWool), - 1086usize => Some(Block::LightBlueWool), - 1087usize => Some(Block::YellowWool), - 1088usize => Some(Block::LimeWool), - 1089usize => Some(Block::PinkWool), - 1090usize => Some(Block::GrayWool), - 1091usize => Some(Block::LightGrayWool), - 1092usize => Some(Block::CyanWool), - 1093usize => Some(Block::PurpleWool), - 1094usize => Some(Block::BlueWool), - 1095usize => Some(Block::BrownWool), - 1096usize => Some(Block::GreenWool), - 1097usize => Some(Block::RedWool), - 1098usize => Some(Block::BlackWool), - 1099usize..=1110usize => { - let offset = id - 1099usize; - let data = MovingPistonData::from_value(offset)?; - Some(Block::MovingPiston(data)) - } - 1111usize => Some(Block::Dandelion), - 1112usize => Some(Block::Poppy), - 1113usize => Some(Block::BlueOrchid), - 1114usize => Some(Block::Allium), - 1115usize => Some(Block::AzureBluet), - 1116usize => Some(Block::RedTulip), - 1117usize => Some(Block::OrangeTulip), - 1118usize => Some(Block::WhiteTulip), - 1119usize => Some(Block::PinkTulip), - 1120usize => Some(Block::OxeyeDaisy), - 1121usize => Some(Block::BrownMushroom), - 1122usize => Some(Block::RedMushroom), - 1123usize => Some(Block::GoldBlock), - 1124usize => Some(Block::IronBlock), - 1125usize => Some(Block::Bricks), - 1126usize..=1127usize => { - let offset = id - 1126usize; - let data = TntData::from_value(offset)?; - Some(Block::Tnt(data)) - } - 1128usize => Some(Block::Bookshelf), - 1129usize => Some(Block::MossyCobblestone), - 1130usize => Some(Block::Obsidian), - 1131usize => Some(Block::Torch), - 1132usize..=1135usize => { - let offset = id - 1132usize; - let data = WallTorchData::from_value(offset)?; - Some(Block::WallTorch(data)) - } - 1136usize..=1647usize => { - let offset = id - 1136usize; - let data = FireData::from_value(offset)?; - Some(Block::Fire(data)) - } - 1648usize => Some(Block::Spawner), - 1649usize..=1728usize => { - let offset = id - 1649usize; - let data = OakStairsData::from_value(offset)?; - Some(Block::OakStairs(data)) - } - 1729usize..=1752usize => { - let offset = id - 1729usize; - let data = ChestData::from_value(offset)?; - Some(Block::Chest(data)) - } - 1753usize..=3048usize => { - let offset = id - 1753usize; - let data = RedstoneWireData::from_value(offset)?; - Some(Block::RedstoneWire(data)) - } - 3049usize => Some(Block::DiamondOre), - 3050usize => Some(Block::DiamondBlock), - 3051usize => Some(Block::CraftingTable), - 3052usize..=3059usize => { - let offset = id - 3052usize; - let data = WheatData::from_value(offset)?; - Some(Block::Wheat(data)) - } - 3060usize..=3067usize => { - let offset = id - 3060usize; - let data = FarmlandData::from_value(offset)?; - Some(Block::Farmland(data)) - } - 3068usize..=3075usize => { - let offset = id - 3068usize; - let data = FurnaceData::from_value(offset)?; - Some(Block::Furnace(data)) - } - 3076usize..=3107usize => { - let offset = id - 3076usize; - let data = SignData::from_value(offset)?; - Some(Block::Sign(data)) - } - 3108usize..=3171usize => { - let offset = id - 3108usize; - let data = OakDoorData::from_value(offset)?; - Some(Block::OakDoor(data)) - } - 3172usize..=3179usize => { - let offset = id - 3172usize; - let data = LadderData::from_value(offset)?; - Some(Block::Ladder(data)) - } - 3180usize..=3189usize => { - let offset = id - 3180usize; - let data = RailData::from_value(offset)?; - Some(Block::Rail(data)) - } - 3190usize..=3269usize => { - let offset = id - 3190usize; - let data = CobblestoneStairsData::from_value(offset)?; - Some(Block::CobblestoneStairs(data)) - } - 3270usize..=3277usize => { - let offset = id - 3270usize; - let data = WallSignData::from_value(offset)?; - Some(Block::WallSign(data)) - } - 3278usize..=3301usize => { - let offset = id - 3278usize; - let data = LeverData::from_value(offset)?; - Some(Block::Lever(data)) - } - 3302usize..=3303usize => { - let offset = id - 3302usize; - let data = StonePressurePlateData::from_value(offset)?; - Some(Block::StonePressurePlate(data)) - } - 3304usize..=3367usize => { - let offset = id - 3304usize; - let data = IronDoorData::from_value(offset)?; - Some(Block::IronDoor(data)) - } - 3368usize..=3369usize => { - let offset = id - 3368usize; - let data = OakPressurePlateData::from_value(offset)?; - Some(Block::OakPressurePlate(data)) - } - 3370usize..=3371usize => { - let offset = id - 3370usize; - let data = SprucePressurePlateData::from_value(offset)?; - Some(Block::SprucePressurePlate(data)) - } - 3372usize..=3373usize => { - let offset = id - 3372usize; - let data = BirchPressurePlateData::from_value(offset)?; - Some(Block::BirchPressurePlate(data)) - } - 3374usize..=3375usize => { - let offset = id - 3374usize; - let data = JunglePressurePlateData::from_value(offset)?; - Some(Block::JunglePressurePlate(data)) - } - 3376usize..=3377usize => { - let offset = id - 3376usize; - let data = AcaciaPressurePlateData::from_value(offset)?; - Some(Block::AcaciaPressurePlate(data)) - } - 3378usize..=3379usize => { - let offset = id - 3378usize; - let data = DarkOakPressurePlateData::from_value(offset)?; - Some(Block::DarkOakPressurePlate(data)) - } - 3380usize..=3381usize => { - let offset = id - 3380usize; - let data = RedstoneOreData::from_value(offset)?; - Some(Block::RedstoneOre(data)) - } - 3382usize..=3383usize => { - let offset = id - 3382usize; - let data = RedstoneTorchData::from_value(offset)?; - Some(Block::RedstoneTorch(data)) - } - 3384usize..=3391usize => { - let offset = id - 3384usize; - let data = RedstoneWallTorchData::from_value(offset)?; - Some(Block::RedstoneWallTorch(data)) - } - 3392usize..=3415usize => { - let offset = id - 3392usize; - let data = StoneButtonData::from_value(offset)?; - Some(Block::StoneButton(data)) - } - 3416usize..=3423usize => { - let offset = id - 3416usize; - let data = SnowData::from_value(offset)?; - Some(Block::Snow(data)) - } - 3424usize => Some(Block::Ice), - 3425usize => Some(Block::SnowBlock), - 3426usize..=3441usize => { - let offset = id - 3426usize; - let data = CactusData::from_value(offset)?; - Some(Block::Cactus(data)) - } - 3442usize => Some(Block::Clay), - 3443usize..=3458usize => { - let offset = id - 3443usize; - let data = SugarCaneData::from_value(offset)?; - Some(Block::SugarCane(data)) - } - 3459usize..=3460usize => { - let offset = id - 3459usize; - let data = JukeboxData::from_value(offset)?; - Some(Block::Jukebox(data)) - } - 3461usize..=3492usize => { - let offset = id - 3461usize; - let data = OakFenceData::from_value(offset)?; - Some(Block::OakFence(data)) - } - 3493usize => Some(Block::Pumpkin), - 3494usize => Some(Block::Netherrack), - 3495usize => Some(Block::SoulSand), - 3496usize => Some(Block::Glowstone), - 3497usize..=3498usize => { - let offset = id - 3497usize; - let data = NetherPortalData::from_value(offset)?; - Some(Block::NetherPortal(data)) - } - 3499usize..=3502usize => { - let offset = id - 3499usize; - let data = CarvedPumpkinData::from_value(offset)?; - Some(Block::CarvedPumpkin(data)) - } - 3503usize..=3506usize => { - let offset = id - 3503usize; - let data = JackOLanternData::from_value(offset)?; - Some(Block::JackOLantern(data)) - } - 3507usize..=3513usize => { - let offset = id - 3507usize; - let data = CakeData::from_value(offset)?; - Some(Block::Cake(data)) - } - 3514usize..=3577usize => { - let offset = id - 3514usize; - let data = RepeaterData::from_value(offset)?; - Some(Block::Repeater(data)) - } - 3578usize => Some(Block::WhiteStainedGlass), - 3579usize => Some(Block::OrangeStainedGlass), - 3580usize => Some(Block::MagentaStainedGlass), - 3581usize => Some(Block::LightBlueStainedGlass), - 3582usize => Some(Block::YellowStainedGlass), - 3583usize => Some(Block::LimeStainedGlass), - 3584usize => Some(Block::PinkStainedGlass), - 3585usize => Some(Block::GrayStainedGlass), - 3586usize => Some(Block::LightGrayStainedGlass), - 3587usize => Some(Block::CyanStainedGlass), - 3588usize => Some(Block::PurpleStainedGlass), - 3589usize => Some(Block::BlueStainedGlass), - 3590usize => Some(Block::BrownStainedGlass), - 3591usize => Some(Block::GreenStainedGlass), - 3592usize => Some(Block::RedStainedGlass), - 3593usize => Some(Block::BlackStainedGlass), - 3594usize..=3657usize => { - let offset = id - 3594usize; - let data = OakTrapdoorData::from_value(offset)?; - Some(Block::OakTrapdoor(data)) - } - 3658usize..=3721usize => { - let offset = id - 3658usize; - let data = SpruceTrapdoorData::from_value(offset)?; - Some(Block::SpruceTrapdoor(data)) - } - 3722usize..=3785usize => { - let offset = id - 3722usize; - let data = BirchTrapdoorData::from_value(offset)?; - Some(Block::BirchTrapdoor(data)) - } - 3786usize..=3849usize => { - let offset = id - 3786usize; - let data = JungleTrapdoorData::from_value(offset)?; - Some(Block::JungleTrapdoor(data)) - } - 3850usize..=3913usize => { - let offset = id - 3850usize; - let data = AcaciaTrapdoorData::from_value(offset)?; - Some(Block::AcaciaTrapdoor(data)) - } - 3914usize..=3977usize => { - let offset = id - 3914usize; - let data = DarkOakTrapdoorData::from_value(offset)?; - Some(Block::DarkOakTrapdoor(data)) - } - 3978usize => Some(Block::InfestedStone), - 3979usize => Some(Block::InfestedCobblestone), - 3980usize => Some(Block::InfestedStoneBricks), - 3981usize => Some(Block::InfestedMossyStoneBricks), - 3982usize => Some(Block::InfestedCrackedStoneBricks), - 3983usize => Some(Block::InfestedChiseledStoneBricks), - 3984usize => Some(Block::StoneBricks), - 3985usize => Some(Block::MossyStoneBricks), - 3986usize => Some(Block::CrackedStoneBricks), - 3987usize => Some(Block::ChiseledStoneBricks), - 3988usize..=4051usize => { - let offset = id - 3988usize; - let data = BrownMushroomBlockData::from_value(offset)?; - Some(Block::BrownMushroomBlock(data)) - } - 4052usize..=4115usize => { - let offset = id - 4052usize; - let data = RedMushroomBlockData::from_value(offset)?; - Some(Block::RedMushroomBlock(data)) - } - 4116usize..=4179usize => { - let offset = id - 4116usize; - let data = MushroomStemData::from_value(offset)?; - Some(Block::MushroomStem(data)) - } - 4180usize..=4211usize => { - let offset = id - 4180usize; - let data = IronBarsData::from_value(offset)?; - Some(Block::IronBars(data)) - } - 4212usize..=4243usize => { - let offset = id - 4212usize; - let data = GlassPaneData::from_value(offset)?; - Some(Block::GlassPane(data)) - } - 4244usize => Some(Block::Melon), - 4245usize..=4248usize => { - let offset = id - 4245usize; - let data = AttachedPumpkinStemData::from_value(offset)?; - Some(Block::AttachedPumpkinStem(data)) - } - 4249usize..=4252usize => { - let offset = id - 4249usize; - let data = AttachedMelonStemData::from_value(offset)?; - Some(Block::AttachedMelonStem(data)) - } - 4253usize..=4260usize => { - let offset = id - 4253usize; - let data = PumpkinStemData::from_value(offset)?; - Some(Block::PumpkinStem(data)) - } - 4261usize..=4268usize => { - let offset = id - 4261usize; - let data = MelonStemData::from_value(offset)?; - Some(Block::MelonStem(data)) - } - 4269usize..=4300usize => { - let offset = id - 4269usize; - let data = VineData::from_value(offset)?; - Some(Block::Vine(data)) - } - 4301usize..=4332usize => { - let offset = id - 4301usize; - let data = OakFenceGateData::from_value(offset)?; - Some(Block::OakFenceGate(data)) - } - 4333usize..=4412usize => { - let offset = id - 4333usize; - let data = BrickStairsData::from_value(offset)?; - Some(Block::BrickStairs(data)) - } - 4413usize..=4492usize => { - let offset = id - 4413usize; - let data = StoneBrickStairsData::from_value(offset)?; - Some(Block::StoneBrickStairs(data)) - } - 4493usize..=4494usize => { - let offset = id - 4493usize; - let data = MyceliumData::from_value(offset)?; - Some(Block::Mycelium(data)) - } - 4495usize => Some(Block::LilyPad), - 4496usize => Some(Block::NetherBricks), - 4497usize..=4528usize => { - let offset = id - 4497usize; - let data = NetherBrickFenceData::from_value(offset)?; - Some(Block::NetherBrickFence(data)) - } - 4529usize..=4608usize => { - let offset = id - 4529usize; - let data = NetherBrickStairsData::from_value(offset)?; - Some(Block::NetherBrickStairs(data)) - } - 4609usize..=4612usize => { - let offset = id - 4609usize; - let data = NetherWartData::from_value(offset)?; - Some(Block::NetherWart(data)) - } - 4613usize => Some(Block::EnchantingTable), - 4614usize..=4621usize => { - let offset = id - 4614usize; - let data = BrewingStandData::from_value(offset)?; - Some(Block::BrewingStand(data)) - } - 4622usize..=4625usize => { - let offset = id - 4622usize; - let data = CauldronData::from_value(offset)?; - Some(Block::Cauldron(data)) - } - 4626usize => Some(Block::EndPortal), - 4627usize..=4634usize => { - let offset = id - 4627usize; - let data = EndPortalFrameData::from_value(offset)?; - Some(Block::EndPortalFrame(data)) - } - 4635usize => Some(Block::EndStone), - 4636usize => Some(Block::DragonEgg), - 4637usize..=4638usize => { - let offset = id - 4637usize; - let data = RedstoneLampData::from_value(offset)?; - Some(Block::RedstoneLamp(data)) - } - 4639usize..=4650usize => { - let offset = id - 4639usize; - let data = CocoaData::from_value(offset)?; - Some(Block::Cocoa(data)) - } - 4651usize..=4730usize => { - let offset = id - 4651usize; - let data = SandstoneStairsData::from_value(offset)?; - Some(Block::SandstoneStairs(data)) - } - 4731usize => Some(Block::EmeraldOre), - 4732usize..=4739usize => { - let offset = id - 4732usize; - let data = EnderChestData::from_value(offset)?; - Some(Block::EnderChest(data)) - } - 4740usize..=4755usize => { - let offset = id - 4740usize; - let data = TripwireHookData::from_value(offset)?; - Some(Block::TripwireHook(data)) - } - 4756usize..=4883usize => { - let offset = id - 4756usize; - let data = TripwireData::from_value(offset)?; - Some(Block::Tripwire(data)) - } - 4884usize => Some(Block::EmeraldBlock), - 4885usize..=4964usize => { - let offset = id - 4885usize; - let data = SpruceStairsData::from_value(offset)?; - Some(Block::SpruceStairs(data)) - } - 4965usize..=5044usize => { - let offset = id - 4965usize; - let data = BirchStairsData::from_value(offset)?; - Some(Block::BirchStairs(data)) - } - 5045usize..=5124usize => { - let offset = id - 5045usize; - let data = JungleStairsData::from_value(offset)?; - Some(Block::JungleStairs(data)) - } - 5125usize..=5136usize => { - let offset = id - 5125usize; - let data = CommandBlockData::from_value(offset)?; - Some(Block::CommandBlock(data)) - } - 5137usize => Some(Block::Beacon), - 5138usize..=5201usize => { - let offset = id - 5138usize; - let data = CobblestoneWallData::from_value(offset)?; - Some(Block::CobblestoneWall(data)) - } - 5202usize..=5265usize => { - let offset = id - 5202usize; - let data = MossyCobblestoneWallData::from_value(offset)?; - Some(Block::MossyCobblestoneWall(data)) - } - 5266usize => Some(Block::FlowerPot), - 5267usize => Some(Block::PottedOakSapling), - 5268usize => Some(Block::PottedSpruceSapling), - 5269usize => Some(Block::PottedBirchSapling), - 5270usize => Some(Block::PottedJungleSapling), - 5271usize => Some(Block::PottedAcaciaSapling), - 5272usize => Some(Block::PottedDarkOakSapling), - 5273usize => Some(Block::PottedFern), - 5274usize => Some(Block::PottedDandelion), - 5275usize => Some(Block::PottedPoppy), - 5276usize => Some(Block::PottedBlueOrchid), - 5277usize => Some(Block::PottedAllium), - 5278usize => Some(Block::PottedAzureBluet), - 5279usize => Some(Block::PottedRedTulip), - 5280usize => Some(Block::PottedOrangeTulip), - 5281usize => Some(Block::PottedWhiteTulip), - 5282usize => Some(Block::PottedPinkTulip), - 5283usize => Some(Block::PottedOxeyeDaisy), - 5284usize => Some(Block::PottedRedMushroom), - 5285usize => Some(Block::PottedBrownMushroom), - 5286usize => Some(Block::PottedDeadBush), - 5287usize => Some(Block::PottedCactus), - 5288usize..=5295usize => { - let offset = id - 5288usize; - let data = CarrotsData::from_value(offset)?; - Some(Block::Carrots(data)) - } - 5296usize..=5303usize => { - let offset = id - 5296usize; - let data = PotatoesData::from_value(offset)?; - Some(Block::Potatoes(data)) - } - 5304usize..=5327usize => { - let offset = id - 5304usize; - let data = OakButtonData::from_value(offset)?; - Some(Block::OakButton(data)) - } - 5328usize..=5351usize => { - let offset = id - 5328usize; - let data = SpruceButtonData::from_value(offset)?; - Some(Block::SpruceButton(data)) - } - 5352usize..=5375usize => { - let offset = id - 5352usize; - let data = BirchButtonData::from_value(offset)?; - Some(Block::BirchButton(data)) - } - 5376usize..=5399usize => { - let offset = id - 5376usize; - let data = JungleButtonData::from_value(offset)?; - Some(Block::JungleButton(data)) - } - 5400usize..=5423usize => { - let offset = id - 5400usize; - let data = AcaciaButtonData::from_value(offset)?; - Some(Block::AcaciaButton(data)) - } - 5424usize..=5447usize => { - let offset = id - 5424usize; - let data = DarkOakButtonData::from_value(offset)?; - Some(Block::DarkOakButton(data)) - } - 5448usize..=5451usize => { - let offset = id - 5448usize; - let data = SkeletonWallSkullData::from_value(offset)?; - Some(Block::SkeletonWallSkull(data)) - } - 5452usize..=5467usize => { - let offset = id - 5452usize; - let data = SkeletonSkullData::from_value(offset)?; - Some(Block::SkeletonSkull(data)) - } - 5468usize..=5471usize => { - let offset = id - 5468usize; - let data = WitherSkeletonWallSkullData::from_value(offset)?; - Some(Block::WitherSkeletonWallSkull(data)) - } - 5472usize..=5487usize => { - let offset = id - 5472usize; - let data = WitherSkeletonSkullData::from_value(offset)?; - Some(Block::WitherSkeletonSkull(data)) - } - 5488usize..=5491usize => { - let offset = id - 5488usize; - let data = ZombieWallHeadData::from_value(offset)?; - Some(Block::ZombieWallHead(data)) - } - 5492usize..=5507usize => { - let offset = id - 5492usize; - let data = ZombieHeadData::from_value(offset)?; - Some(Block::ZombieHead(data)) - } - 5508usize..=5511usize => { - let offset = id - 5508usize; - let data = PlayerWallHeadData::from_value(offset)?; - Some(Block::PlayerWallHead(data)) - } - 5512usize..=5527usize => { - let offset = id - 5512usize; - let data = PlayerHeadData::from_value(offset)?; - Some(Block::PlayerHead(data)) - } - 5528usize..=5531usize => { - let offset = id - 5528usize; - let data = CreeperWallHeadData::from_value(offset)?; - Some(Block::CreeperWallHead(data)) - } - 5532usize..=5547usize => { - let offset = id - 5532usize; - let data = CreeperHeadData::from_value(offset)?; - Some(Block::CreeperHead(data)) - } - 5548usize..=5551usize => { - let offset = id - 5548usize; - let data = DragonWallHeadData::from_value(offset)?; - Some(Block::DragonWallHead(data)) - } - 5552usize..=5567usize => { - let offset = id - 5552usize; - let data = DragonHeadData::from_value(offset)?; - Some(Block::DragonHead(data)) - } - 5568usize..=5571usize => { - let offset = id - 5568usize; - let data = AnvilData::from_value(offset)?; - Some(Block::Anvil(data)) - } - 5572usize..=5575usize => { - let offset = id - 5572usize; - let data = ChippedAnvilData::from_value(offset)?; - Some(Block::ChippedAnvil(data)) - } - 5576usize..=5579usize => { - let offset = id - 5576usize; - let data = DamagedAnvilData::from_value(offset)?; - Some(Block::DamagedAnvil(data)) - } - 5580usize..=5603usize => { - let offset = id - 5580usize; - let data = TrappedChestData::from_value(offset)?; - Some(Block::TrappedChest(data)) - } - 5604usize..=5619usize => { - let offset = id - 5604usize; - let data = LightWeightedPressurePlateData::from_value(offset)?; - Some(Block::LightWeightedPressurePlate(data)) - } - 5620usize..=5635usize => { - let offset = id - 5620usize; - let data = HeavyWeightedPressurePlateData::from_value(offset)?; - Some(Block::HeavyWeightedPressurePlate(data)) - } - 5636usize..=5651usize => { - let offset = id - 5636usize; - let data = ComparatorData::from_value(offset)?; - Some(Block::Comparator(data)) - } - 5652usize..=5683usize => { - let offset = id - 5652usize; - let data = DaylightDetectorData::from_value(offset)?; - Some(Block::DaylightDetector(data)) - } - 5684usize => Some(Block::RedstoneBlock), - 5685usize => Some(Block::NetherQuartzOre), - 5686usize..=5695usize => { - let offset = id - 5686usize; - let data = HopperData::from_value(offset)?; - Some(Block::Hopper(data)) - } - 5696usize => Some(Block::QuartzBlock), - 5697usize => Some(Block::ChiseledQuartzBlock), - 5698usize..=5700usize => { - let offset = id - 5698usize; - let data = QuartzPillarData::from_value(offset)?; - Some(Block::QuartzPillar(data)) - } - 5701usize..=5780usize => { - let offset = id - 5701usize; - let data = QuartzStairsData::from_value(offset)?; - Some(Block::QuartzStairs(data)) - } - 5781usize..=5792usize => { - let offset = id - 5781usize; - let data = ActivatorRailData::from_value(offset)?; - Some(Block::ActivatorRail(data)) - } - 5793usize..=5804usize => { - let offset = id - 5793usize; - let data = DropperData::from_value(offset)?; - Some(Block::Dropper(data)) - } - 5805usize => Some(Block::WhiteTerracotta), - 5806usize => Some(Block::OrangeTerracotta), - 5807usize => Some(Block::MagentaTerracotta), - 5808usize => Some(Block::LightBlueTerracotta), - 5809usize => Some(Block::YellowTerracotta), - 5810usize => Some(Block::LimeTerracotta), - 5811usize => Some(Block::PinkTerracotta), - 5812usize => Some(Block::GrayTerracotta), - 5813usize => Some(Block::LightGrayTerracotta), - 5814usize => Some(Block::CyanTerracotta), - 5815usize => Some(Block::PurpleTerracotta), - 5816usize => Some(Block::BlueTerracotta), - 5817usize => Some(Block::BrownTerracotta), - 5818usize => Some(Block::GreenTerracotta), - 5819usize => Some(Block::RedTerracotta), - 5820usize => Some(Block::BlackTerracotta), - 5821usize..=5852usize => { - let offset = id - 5821usize; - let data = WhiteStainedGlassPaneData::from_value(offset)?; - Some(Block::WhiteStainedGlassPane(data)) - } - 5853usize..=5884usize => { - let offset = id - 5853usize; - let data = OrangeStainedGlassPaneData::from_value(offset)?; - Some(Block::OrangeStainedGlassPane(data)) - } - 5885usize..=5916usize => { - let offset = id - 5885usize; - let data = MagentaStainedGlassPaneData::from_value(offset)?; - Some(Block::MagentaStainedGlassPane(data)) - } - 5917usize..=5948usize => { - let offset = id - 5917usize; - let data = LightBlueStainedGlassPaneData::from_value(offset)?; - Some(Block::LightBlueStainedGlassPane(data)) - } - 5949usize..=5980usize => { - let offset = id - 5949usize; - let data = YellowStainedGlassPaneData::from_value(offset)?; - Some(Block::YellowStainedGlassPane(data)) - } - 5981usize..=6012usize => { - let offset = id - 5981usize; - let data = LimeStainedGlassPaneData::from_value(offset)?; - Some(Block::LimeStainedGlassPane(data)) - } - 6013usize..=6044usize => { - let offset = id - 6013usize; - let data = PinkStainedGlassPaneData::from_value(offset)?; - Some(Block::PinkStainedGlassPane(data)) - } - 6045usize..=6076usize => { - let offset = id - 6045usize; - let data = GrayStainedGlassPaneData::from_value(offset)?; - Some(Block::GrayStainedGlassPane(data)) - } - 6077usize..=6108usize => { - let offset = id - 6077usize; - let data = LightGrayStainedGlassPaneData::from_value(offset)?; - Some(Block::LightGrayStainedGlassPane(data)) - } - 6109usize..=6140usize => { - let offset = id - 6109usize; - let data = CyanStainedGlassPaneData::from_value(offset)?; - Some(Block::CyanStainedGlassPane(data)) - } - 6141usize..=6172usize => { - let offset = id - 6141usize; - let data = PurpleStainedGlassPaneData::from_value(offset)?; - Some(Block::PurpleStainedGlassPane(data)) - } - 6173usize..=6204usize => { - let offset = id - 6173usize; - let data = BlueStainedGlassPaneData::from_value(offset)?; - Some(Block::BlueStainedGlassPane(data)) - } - 6205usize..=6236usize => { - let offset = id - 6205usize; - let data = BrownStainedGlassPaneData::from_value(offset)?; - Some(Block::BrownStainedGlassPane(data)) - } - 6237usize..=6268usize => { - let offset = id - 6237usize; - let data = GreenStainedGlassPaneData::from_value(offset)?; - Some(Block::GreenStainedGlassPane(data)) - } - 6269usize..=6300usize => { - let offset = id - 6269usize; - let data = RedStainedGlassPaneData::from_value(offset)?; - Some(Block::RedStainedGlassPane(data)) - } - 6301usize..=6332usize => { - let offset = id - 6301usize; - let data = BlackStainedGlassPaneData::from_value(offset)?; - Some(Block::BlackStainedGlassPane(data)) - } - 6333usize..=6412usize => { - let offset = id - 6333usize; - let data = AcaciaStairsData::from_value(offset)?; - Some(Block::AcaciaStairs(data)) - } - 6413usize..=6492usize => { - let offset = id - 6413usize; - let data = DarkOakStairsData::from_value(offset)?; - Some(Block::DarkOakStairs(data)) - } - 6493usize => Some(Block::SlimeBlock), - 6494usize => Some(Block::Barrier), - 6495usize..=6558usize => { - let offset = id - 6495usize; - let data = IronTrapdoorData::from_value(offset)?; - Some(Block::IronTrapdoor(data)) - } - 6559usize => Some(Block::Prismarine), - 6560usize => Some(Block::PrismarineBricks), - 6561usize => Some(Block::DarkPrismarine), - 6562usize..=6641usize => { - let offset = id - 6562usize; - let data = PrismarineStairsData::from_value(offset)?; - Some(Block::PrismarineStairs(data)) - } - 6642usize..=6721usize => { - let offset = id - 6642usize; - let data = PrismarineBrickStairsData::from_value(offset)?; - Some(Block::PrismarineBrickStairs(data)) - } - 6722usize..=6801usize => { - let offset = id - 6722usize; - let data = DarkPrismarineStairsData::from_value(offset)?; - Some(Block::DarkPrismarineStairs(data)) - } - 6802usize..=6807usize => { - let offset = id - 6802usize; - let data = PrismarineSlabData::from_value(offset)?; - Some(Block::PrismarineSlab(data)) - } - 6808usize..=6813usize => { - let offset = id - 6808usize; - let data = PrismarineBrickSlabData::from_value(offset)?; - Some(Block::PrismarineBrickSlab(data)) - } - 6814usize..=6819usize => { - let offset = id - 6814usize; - let data = DarkPrismarineSlabData::from_value(offset)?; - Some(Block::DarkPrismarineSlab(data)) - } - 6820usize => Some(Block::SeaLantern), - 6821usize..=6823usize => { - let offset = id - 6821usize; - let data = HayBlockData::from_value(offset)?; - Some(Block::HayBlock(data)) - } - 6824usize => Some(Block::WhiteCarpet), - 6825usize => Some(Block::OrangeCarpet), - 6826usize => Some(Block::MagentaCarpet), - 6827usize => Some(Block::LightBlueCarpet), - 6828usize => Some(Block::YellowCarpet), - 6829usize => Some(Block::LimeCarpet), - 6830usize => Some(Block::PinkCarpet), - 6831usize => Some(Block::GrayCarpet), - 6832usize => Some(Block::LightGrayCarpet), - 6833usize => Some(Block::CyanCarpet), - 6834usize => Some(Block::PurpleCarpet), - 6835usize => Some(Block::BlueCarpet), - 6836usize => Some(Block::BrownCarpet), - 6837usize => Some(Block::GreenCarpet), - 6838usize => Some(Block::RedCarpet), - 6839usize => Some(Block::BlackCarpet), - 6840usize => Some(Block::Terracotta), - 6841usize => Some(Block::CoalBlock), - 6842usize => Some(Block::PackedIce), - 6843usize..=6844usize => { - let offset = id - 6843usize; - let data = SunflowerData::from_value(offset)?; - Some(Block::Sunflower(data)) - } - 6845usize..=6846usize => { - let offset = id - 6845usize; - let data = LilacData::from_value(offset)?; - Some(Block::Lilac(data)) - } - 6847usize..=6848usize => { - let offset = id - 6847usize; - let data = RoseBushData::from_value(offset)?; - Some(Block::RoseBush(data)) - } - 6849usize..=6850usize => { - let offset = id - 6849usize; - let data = PeonyData::from_value(offset)?; - Some(Block::Peony(data)) - } - 6851usize..=6852usize => { - let offset = id - 6851usize; - let data = TallGrassData::from_value(offset)?; - Some(Block::TallGrass(data)) - } - 6853usize..=6854usize => { - let offset = id - 6853usize; - let data = LargeFernData::from_value(offset)?; - Some(Block::LargeFern(data)) - } - 6855usize..=6870usize => { - let offset = id - 6855usize; - let data = WhiteBannerData::from_value(offset)?; - Some(Block::WhiteBanner(data)) - } - 6871usize..=6886usize => { - let offset = id - 6871usize; - let data = OrangeBannerData::from_value(offset)?; - Some(Block::OrangeBanner(data)) - } - 6887usize..=6902usize => { - let offset = id - 6887usize; - let data = MagentaBannerData::from_value(offset)?; - Some(Block::MagentaBanner(data)) - } - 6903usize..=6918usize => { - let offset = id - 6903usize; - let data = LightBlueBannerData::from_value(offset)?; - Some(Block::LightBlueBanner(data)) - } - 6919usize..=6934usize => { - let offset = id - 6919usize; - let data = YellowBannerData::from_value(offset)?; - Some(Block::YellowBanner(data)) - } - 6935usize..=6950usize => { - let offset = id - 6935usize; - let data = LimeBannerData::from_value(offset)?; - Some(Block::LimeBanner(data)) - } - 6951usize..=6966usize => { - let offset = id - 6951usize; - let data = PinkBannerData::from_value(offset)?; - Some(Block::PinkBanner(data)) - } - 6967usize..=6982usize => { - let offset = id - 6967usize; - let data = GrayBannerData::from_value(offset)?; - Some(Block::GrayBanner(data)) - } - 6983usize..=6998usize => { - let offset = id - 6983usize; - let data = LightGrayBannerData::from_value(offset)?; - Some(Block::LightGrayBanner(data)) - } - 6999usize..=7014usize => { - let offset = id - 6999usize; - let data = CyanBannerData::from_value(offset)?; - Some(Block::CyanBanner(data)) - } - 7015usize..=7030usize => { - let offset = id - 7015usize; - let data = PurpleBannerData::from_value(offset)?; - Some(Block::PurpleBanner(data)) - } - 7031usize..=7046usize => { - let offset = id - 7031usize; - let data = BlueBannerData::from_value(offset)?; - Some(Block::BlueBanner(data)) - } - 7047usize..=7062usize => { - let offset = id - 7047usize; - let data = BrownBannerData::from_value(offset)?; - Some(Block::BrownBanner(data)) - } - 7063usize..=7078usize => { - let offset = id - 7063usize; - let data = GreenBannerData::from_value(offset)?; - Some(Block::GreenBanner(data)) - } - 7079usize..=7094usize => { - let offset = id - 7079usize; - let data = RedBannerData::from_value(offset)?; - Some(Block::RedBanner(data)) - } - 7095usize..=7110usize => { - let offset = id - 7095usize; - let data = BlackBannerData::from_value(offset)?; - Some(Block::BlackBanner(data)) - } - 7111usize..=7114usize => { - let offset = id - 7111usize; - let data = WhiteWallBannerData::from_value(offset)?; - Some(Block::WhiteWallBanner(data)) - } - 7115usize..=7118usize => { - let offset = id - 7115usize; - let data = OrangeWallBannerData::from_value(offset)?; - Some(Block::OrangeWallBanner(data)) - } - 7119usize..=7122usize => { - let offset = id - 7119usize; - let data = MagentaWallBannerData::from_value(offset)?; - Some(Block::MagentaWallBanner(data)) - } - 7123usize..=7126usize => { - let offset = id - 7123usize; - let data = LightBlueWallBannerData::from_value(offset)?; - Some(Block::LightBlueWallBanner(data)) - } - 7127usize..=7130usize => { - let offset = id - 7127usize; - let data = YellowWallBannerData::from_value(offset)?; - Some(Block::YellowWallBanner(data)) - } - 7131usize..=7134usize => { - let offset = id - 7131usize; - let data = LimeWallBannerData::from_value(offset)?; - Some(Block::LimeWallBanner(data)) - } - 7135usize..=7138usize => { - let offset = id - 7135usize; - let data = PinkWallBannerData::from_value(offset)?; - Some(Block::PinkWallBanner(data)) - } - 7139usize..=7142usize => { - let offset = id - 7139usize; - let data = GrayWallBannerData::from_value(offset)?; - Some(Block::GrayWallBanner(data)) - } - 7143usize..=7146usize => { - let offset = id - 7143usize; - let data = LightGrayWallBannerData::from_value(offset)?; - Some(Block::LightGrayWallBanner(data)) - } - 7147usize..=7150usize => { - let offset = id - 7147usize; - let data = CyanWallBannerData::from_value(offset)?; - Some(Block::CyanWallBanner(data)) - } - 7151usize..=7154usize => { - let offset = id - 7151usize; - let data = PurpleWallBannerData::from_value(offset)?; - Some(Block::PurpleWallBanner(data)) - } - 7155usize..=7158usize => { - let offset = id - 7155usize; - let data = BlueWallBannerData::from_value(offset)?; - Some(Block::BlueWallBanner(data)) - } - 7159usize..=7162usize => { - let offset = id - 7159usize; - let data = BrownWallBannerData::from_value(offset)?; - Some(Block::BrownWallBanner(data)) - } - 7163usize..=7166usize => { - let offset = id - 7163usize; - let data = GreenWallBannerData::from_value(offset)?; - Some(Block::GreenWallBanner(data)) - } - 7167usize..=7170usize => { - let offset = id - 7167usize; - let data = RedWallBannerData::from_value(offset)?; - Some(Block::RedWallBanner(data)) - } - 7171usize..=7174usize => { - let offset = id - 7171usize; - let data = BlackWallBannerData::from_value(offset)?; - Some(Block::BlackWallBanner(data)) - } - 7175usize => Some(Block::RedSandstone), - 7176usize => Some(Block::ChiseledRedSandstone), - 7177usize => Some(Block::CutRedSandstone), - 7178usize..=7257usize => { - let offset = id - 7178usize; - let data = RedSandstoneStairsData::from_value(offset)?; - Some(Block::RedSandstoneStairs(data)) - } - 7258usize..=7263usize => { - let offset = id - 7258usize; - let data = OakSlabData::from_value(offset)?; - Some(Block::OakSlab(data)) - } - 7264usize..=7269usize => { - let offset = id - 7264usize; - let data = SpruceSlabData::from_value(offset)?; - Some(Block::SpruceSlab(data)) - } - 7270usize..=7275usize => { - let offset = id - 7270usize; - let data = BirchSlabData::from_value(offset)?; - Some(Block::BirchSlab(data)) - } - 7276usize..=7281usize => { - let offset = id - 7276usize; - let data = JungleSlabData::from_value(offset)?; - Some(Block::JungleSlab(data)) - } - 7282usize..=7287usize => { - let offset = id - 7282usize; - let data = AcaciaSlabData::from_value(offset)?; - Some(Block::AcaciaSlab(data)) - } - 7288usize..=7293usize => { - let offset = id - 7288usize; - let data = DarkOakSlabData::from_value(offset)?; - Some(Block::DarkOakSlab(data)) - } - 7294usize..=7299usize => { - let offset = id - 7294usize; - let data = StoneSlabData::from_value(offset)?; - Some(Block::StoneSlab(data)) - } - 7300usize..=7305usize => { - let offset = id - 7300usize; - let data = SandstoneSlabData::from_value(offset)?; - Some(Block::SandstoneSlab(data)) - } - 7306usize..=7311usize => { - let offset = id - 7306usize; - let data = PetrifiedOakSlabData::from_value(offset)?; - Some(Block::PetrifiedOakSlab(data)) - } - 7312usize..=7317usize => { - let offset = id - 7312usize; - let data = CobblestoneSlabData::from_value(offset)?; - Some(Block::CobblestoneSlab(data)) - } - 7318usize..=7323usize => { - let offset = id - 7318usize; - let data = BrickSlabData::from_value(offset)?; - Some(Block::BrickSlab(data)) - } - 7324usize..=7329usize => { - let offset = id - 7324usize; - let data = StoneBrickSlabData::from_value(offset)?; - Some(Block::StoneBrickSlab(data)) - } - 7330usize..=7335usize => { - let offset = id - 7330usize; - let data = NetherBrickSlabData::from_value(offset)?; - Some(Block::NetherBrickSlab(data)) - } - 7336usize..=7341usize => { - let offset = id - 7336usize; - let data = QuartzSlabData::from_value(offset)?; - Some(Block::QuartzSlab(data)) - } - 7342usize..=7347usize => { - let offset = id - 7342usize; - let data = RedSandstoneSlabData::from_value(offset)?; - Some(Block::RedSandstoneSlab(data)) - } - 7348usize..=7353usize => { - let offset = id - 7348usize; - let data = PurpurSlabData::from_value(offset)?; - Some(Block::PurpurSlab(data)) - } - 7354usize => Some(Block::SmoothStone), - 7355usize => Some(Block::SmoothSandstone), - 7356usize => Some(Block::SmoothQuartz), - 7357usize => Some(Block::SmoothRedSandstone), - 7358usize..=7389usize => { - let offset = id - 7358usize; - let data = SpruceFenceGateData::from_value(offset)?; - Some(Block::SpruceFenceGate(data)) - } - 7390usize..=7421usize => { - let offset = id - 7390usize; - let data = BirchFenceGateData::from_value(offset)?; - Some(Block::BirchFenceGate(data)) - } - 7422usize..=7453usize => { - let offset = id - 7422usize; - let data = JungleFenceGateData::from_value(offset)?; - Some(Block::JungleFenceGate(data)) - } - 7454usize..=7485usize => { - let offset = id - 7454usize; - let data = AcaciaFenceGateData::from_value(offset)?; - Some(Block::AcaciaFenceGate(data)) - } - 7486usize..=7517usize => { - let offset = id - 7486usize; - let data = DarkOakFenceGateData::from_value(offset)?; - Some(Block::DarkOakFenceGate(data)) - } - 7518usize..=7549usize => { - let offset = id - 7518usize; - let data = SpruceFenceData::from_value(offset)?; - Some(Block::SpruceFence(data)) - } - 7550usize..=7581usize => { - let offset = id - 7550usize; - let data = BirchFenceData::from_value(offset)?; - Some(Block::BirchFence(data)) - } - 7582usize..=7613usize => { - let offset = id - 7582usize; - let data = JungleFenceData::from_value(offset)?; - Some(Block::JungleFence(data)) - } - 7614usize..=7645usize => { - let offset = id - 7614usize; - let data = AcaciaFenceData::from_value(offset)?; - Some(Block::AcaciaFence(data)) - } - 7646usize..=7677usize => { - let offset = id - 7646usize; - let data = DarkOakFenceData::from_value(offset)?; - Some(Block::DarkOakFence(data)) - } - 7678usize..=7741usize => { - let offset = id - 7678usize; - let data = SpruceDoorData::from_value(offset)?; - Some(Block::SpruceDoor(data)) - } - 7742usize..=7805usize => { - let offset = id - 7742usize; - let data = BirchDoorData::from_value(offset)?; - Some(Block::BirchDoor(data)) - } - 7806usize..=7869usize => { - let offset = id - 7806usize; - let data = JungleDoorData::from_value(offset)?; - Some(Block::JungleDoor(data)) - } - 7870usize..=7933usize => { - let offset = id - 7870usize; - let data = AcaciaDoorData::from_value(offset)?; - Some(Block::AcaciaDoor(data)) - } - 7934usize..=7997usize => { - let offset = id - 7934usize; - let data = DarkOakDoorData::from_value(offset)?; - Some(Block::DarkOakDoor(data)) - } - 7998usize..=8003usize => { - let offset = id - 7998usize; - let data = EndRodData::from_value(offset)?; - Some(Block::EndRod(data)) - } - 8004usize..=8067usize => { - let offset = id - 8004usize; - let data = ChorusPlantData::from_value(offset)?; - Some(Block::ChorusPlant(data)) - } - 8068usize..=8073usize => { - let offset = id - 8068usize; - let data = ChorusFlowerData::from_value(offset)?; - Some(Block::ChorusFlower(data)) - } - 8074usize => Some(Block::PurpurBlock), - 8075usize..=8077usize => { - let offset = id - 8075usize; - let data = PurpurPillarData::from_value(offset)?; - Some(Block::PurpurPillar(data)) - } - 8078usize..=8157usize => { - let offset = id - 8078usize; - let data = PurpurStairsData::from_value(offset)?; - Some(Block::PurpurStairs(data)) - } - 8158usize => Some(Block::EndStoneBricks), - 8159usize..=8162usize => { - let offset = id - 8159usize; - let data = BeetrootsData::from_value(offset)?; - Some(Block::Beetroots(data)) - } - 8163usize => Some(Block::GrassPath), - 8164usize => Some(Block::EndGateway), - 8165usize..=8176usize => { - let offset = id - 8165usize; - let data = RepeatingCommandBlockData::from_value(offset)?; - Some(Block::RepeatingCommandBlock(data)) - } - 8177usize..=8188usize => { - let offset = id - 8177usize; - let data = ChainCommandBlockData::from_value(offset)?; - Some(Block::ChainCommandBlock(data)) - } - 8189usize..=8192usize => { - let offset = id - 8189usize; - let data = FrostedIceData::from_value(offset)?; - Some(Block::FrostedIce(data)) - } - 8193usize => Some(Block::MagmaBlock), - 8194usize => Some(Block::NetherWartBlock), - 8195usize => Some(Block::RedNetherBricks), - 8196usize..=8198usize => { - let offset = id - 8196usize; - let data = BoneBlockData::from_value(offset)?; - Some(Block::BoneBlock(data)) - } - 8199usize => Some(Block::StructureVoid), - 8200usize..=8211usize => { - let offset = id - 8200usize; - let data = ObserverData::from_value(offset)?; - Some(Block::Observer(data)) - } - 8212usize..=8217usize => { - let offset = id - 8212usize; - let data = ShulkerBoxData::from_value(offset)?; - Some(Block::ShulkerBox(data)) - } - 8218usize..=8223usize => { - let offset = id - 8218usize; - let data = WhiteShulkerBoxData::from_value(offset)?; - Some(Block::WhiteShulkerBox(data)) - } - 8224usize..=8229usize => { - let offset = id - 8224usize; - let data = OrangeShulkerBoxData::from_value(offset)?; - Some(Block::OrangeShulkerBox(data)) - } - 8230usize..=8235usize => { - let offset = id - 8230usize; - let data = MagentaShulkerBoxData::from_value(offset)?; - Some(Block::MagentaShulkerBox(data)) - } - 8236usize..=8241usize => { - let offset = id - 8236usize; - let data = LightBlueShulkerBoxData::from_value(offset)?; - Some(Block::LightBlueShulkerBox(data)) - } - 8242usize..=8247usize => { - let offset = id - 8242usize; - let data = YellowShulkerBoxData::from_value(offset)?; - Some(Block::YellowShulkerBox(data)) - } - 8248usize..=8253usize => { - let offset = id - 8248usize; - let data = LimeShulkerBoxData::from_value(offset)?; - Some(Block::LimeShulkerBox(data)) - } - 8254usize..=8259usize => { - let offset = id - 8254usize; - let data = PinkShulkerBoxData::from_value(offset)?; - Some(Block::PinkShulkerBox(data)) - } - 8260usize..=8265usize => { - let offset = id - 8260usize; - let data = GrayShulkerBoxData::from_value(offset)?; - Some(Block::GrayShulkerBox(data)) - } - 8266usize..=8271usize => { - let offset = id - 8266usize; - let data = LightGrayShulkerBoxData::from_value(offset)?; - Some(Block::LightGrayShulkerBox(data)) - } - 8272usize..=8277usize => { - let offset = id - 8272usize; - let data = CyanShulkerBoxData::from_value(offset)?; - Some(Block::CyanShulkerBox(data)) - } - 8278usize..=8283usize => { - let offset = id - 8278usize; - let data = PurpleShulkerBoxData::from_value(offset)?; - Some(Block::PurpleShulkerBox(data)) - } - 8284usize..=8289usize => { - let offset = id - 8284usize; - let data = BlueShulkerBoxData::from_value(offset)?; - Some(Block::BlueShulkerBox(data)) - } - 8290usize..=8295usize => { - let offset = id - 8290usize; - let data = BrownShulkerBoxData::from_value(offset)?; - Some(Block::BrownShulkerBox(data)) - } - 8296usize..=8301usize => { - let offset = id - 8296usize; - let data = GreenShulkerBoxData::from_value(offset)?; - Some(Block::GreenShulkerBox(data)) - } - 8302usize..=8307usize => { - let offset = id - 8302usize; - let data = RedShulkerBoxData::from_value(offset)?; - Some(Block::RedShulkerBox(data)) - } - 8308usize..=8313usize => { - let offset = id - 8308usize; - let data = BlackShulkerBoxData::from_value(offset)?; - Some(Block::BlackShulkerBox(data)) - } - 8314usize..=8317usize => { - let offset = id - 8314usize; - let data = WhiteGlazedTerracottaData::from_value(offset)?; - Some(Block::WhiteGlazedTerracotta(data)) - } - 8318usize..=8321usize => { - let offset = id - 8318usize; - let data = OrangeGlazedTerracottaData::from_value(offset)?; - Some(Block::OrangeGlazedTerracotta(data)) - } - 8322usize..=8325usize => { - let offset = id - 8322usize; - let data = MagentaGlazedTerracottaData::from_value(offset)?; - Some(Block::MagentaGlazedTerracotta(data)) - } - 8326usize..=8329usize => { - let offset = id - 8326usize; - let data = LightBlueGlazedTerracottaData::from_value(offset)?; - Some(Block::LightBlueGlazedTerracotta(data)) - } - 8330usize..=8333usize => { - let offset = id - 8330usize; - let data = YellowGlazedTerracottaData::from_value(offset)?; - Some(Block::YellowGlazedTerracotta(data)) - } - 8334usize..=8337usize => { - let offset = id - 8334usize; - let data = LimeGlazedTerracottaData::from_value(offset)?; - Some(Block::LimeGlazedTerracotta(data)) - } - 8338usize..=8341usize => { - let offset = id - 8338usize; - let data = PinkGlazedTerracottaData::from_value(offset)?; - Some(Block::PinkGlazedTerracotta(data)) - } - 8342usize..=8345usize => { - let offset = id - 8342usize; - let data = GrayGlazedTerracottaData::from_value(offset)?; - Some(Block::GrayGlazedTerracotta(data)) - } - 8346usize..=8349usize => { - let offset = id - 8346usize; - let data = LightGrayGlazedTerracottaData::from_value(offset)?; - Some(Block::LightGrayGlazedTerracotta(data)) - } - 8350usize..=8353usize => { - let offset = id - 8350usize; - let data = CyanGlazedTerracottaData::from_value(offset)?; - Some(Block::CyanGlazedTerracotta(data)) - } - 8354usize..=8357usize => { - let offset = id - 8354usize; - let data = PurpleGlazedTerracottaData::from_value(offset)?; - Some(Block::PurpleGlazedTerracotta(data)) - } - 8358usize..=8361usize => { - let offset = id - 8358usize; - let data = BlueGlazedTerracottaData::from_value(offset)?; - Some(Block::BlueGlazedTerracotta(data)) - } - 8362usize..=8365usize => { - let offset = id - 8362usize; - let data = BrownGlazedTerracottaData::from_value(offset)?; - Some(Block::BrownGlazedTerracotta(data)) - } - 8366usize..=8369usize => { - let offset = id - 8366usize; - let data = GreenGlazedTerracottaData::from_value(offset)?; - Some(Block::GreenGlazedTerracotta(data)) - } - 8370usize..=8373usize => { - let offset = id - 8370usize; - let data = RedGlazedTerracottaData::from_value(offset)?; - Some(Block::RedGlazedTerracotta(data)) - } - 8374usize..=8377usize => { - let offset = id - 8374usize; - let data = BlackGlazedTerracottaData::from_value(offset)?; - Some(Block::BlackGlazedTerracotta(data)) - } - 8378usize => Some(Block::WhiteConcrete), - 8379usize => Some(Block::OrangeConcrete), - 8380usize => Some(Block::MagentaConcrete), - 8381usize => Some(Block::LightBlueConcrete), - 8382usize => Some(Block::YellowConcrete), - 8383usize => Some(Block::LimeConcrete), - 8384usize => Some(Block::PinkConcrete), - 8385usize => Some(Block::GrayConcrete), - 8386usize => Some(Block::LightGrayConcrete), - 8387usize => Some(Block::CyanConcrete), - 8388usize => Some(Block::PurpleConcrete), - 8389usize => Some(Block::BlueConcrete), - 8390usize => Some(Block::BrownConcrete), - 8391usize => Some(Block::GreenConcrete), - 8392usize => Some(Block::RedConcrete), - 8393usize => Some(Block::BlackConcrete), - 8394usize => Some(Block::WhiteConcretePowder), - 8395usize => Some(Block::OrangeConcretePowder), - 8396usize => Some(Block::MagentaConcretePowder), - 8397usize => Some(Block::LightBlueConcretePowder), - 8398usize => Some(Block::YellowConcretePowder), - 8399usize => Some(Block::LimeConcretePowder), - 8400usize => Some(Block::PinkConcretePowder), - 8401usize => Some(Block::GrayConcretePowder), - 8402usize => Some(Block::LightGrayConcretePowder), - 8403usize => Some(Block::CyanConcretePowder), - 8404usize => Some(Block::PurpleConcretePowder), - 8405usize => Some(Block::BlueConcretePowder), - 8406usize => Some(Block::BrownConcretePowder), - 8407usize => Some(Block::GreenConcretePowder), - 8408usize => Some(Block::RedConcretePowder), - 8409usize => Some(Block::BlackConcretePowder), - 8410usize..=8435usize => { - let offset = id - 8410usize; - let data = KelpData::from_value(offset)?; - Some(Block::Kelp(data)) - } - 8436usize => Some(Block::KelpPlant), - 8437usize => Some(Block::DriedKelpBlock), - 8438usize..=8449usize => { - let offset = id - 8438usize; - let data = TurtleEggData::from_value(offset)?; - Some(Block::TurtleEgg(data)) - } - 8450usize => Some(Block::DeadTubeCoralBlock), - 8451usize => Some(Block::DeadBrainCoralBlock), - 8452usize => Some(Block::DeadBubbleCoralBlock), - 8453usize => Some(Block::DeadFireCoralBlock), - 8454usize => Some(Block::DeadHornCoralBlock), - 8455usize => Some(Block::TubeCoralBlock), - 8456usize => Some(Block::BrainCoralBlock), - 8457usize => Some(Block::BubbleCoralBlock), - 8458usize => Some(Block::FireCoralBlock), - 8459usize => Some(Block::HornCoralBlock), - 8460usize..=8461usize => { - let offset = id - 8460usize; - let data = DeadTubeCoralData::from_value(offset)?; - Some(Block::DeadTubeCoral(data)) - } - 8462usize..=8463usize => { - let offset = id - 8462usize; - let data = DeadBrainCoralData::from_value(offset)?; - Some(Block::DeadBrainCoral(data)) - } - 8464usize..=8465usize => { - let offset = id - 8464usize; - let data = DeadBubbleCoralData::from_value(offset)?; - Some(Block::DeadBubbleCoral(data)) - } - 8466usize..=8467usize => { - let offset = id - 8466usize; - let data = DeadFireCoralData::from_value(offset)?; - Some(Block::DeadFireCoral(data)) - } - 8468usize..=8469usize => { - let offset = id - 8468usize; - let data = DeadHornCoralData::from_value(offset)?; - Some(Block::DeadHornCoral(data)) - } - 8470usize..=8471usize => { - let offset = id - 8470usize; - let data = TubeCoralData::from_value(offset)?; - Some(Block::TubeCoral(data)) - } - 8472usize..=8473usize => { - let offset = id - 8472usize; - let data = BrainCoralData::from_value(offset)?; - Some(Block::BrainCoral(data)) - } - 8474usize..=8475usize => { - let offset = id - 8474usize; - let data = BubbleCoralData::from_value(offset)?; - Some(Block::BubbleCoral(data)) - } - 8476usize..=8477usize => { - let offset = id - 8476usize; - let data = FireCoralData::from_value(offset)?; - Some(Block::FireCoral(data)) - } - 8478usize..=8479usize => { - let offset = id - 8478usize; - let data = HornCoralData::from_value(offset)?; - Some(Block::HornCoral(data)) - } - 8480usize..=8487usize => { - let offset = id - 8480usize; - let data = DeadTubeCoralWallFanData::from_value(offset)?; - Some(Block::DeadTubeCoralWallFan(data)) - } - 8488usize..=8495usize => { - let offset = id - 8488usize; - let data = DeadBrainCoralWallFanData::from_value(offset)?; - Some(Block::DeadBrainCoralWallFan(data)) - } - 8496usize..=8503usize => { - let offset = id - 8496usize; - let data = DeadBubbleCoralWallFanData::from_value(offset)?; - Some(Block::DeadBubbleCoralWallFan(data)) - } - 8504usize..=8511usize => { - let offset = id - 8504usize; - let data = DeadFireCoralWallFanData::from_value(offset)?; - Some(Block::DeadFireCoralWallFan(data)) - } - 8512usize..=8519usize => { - let offset = id - 8512usize; - let data = DeadHornCoralWallFanData::from_value(offset)?; - Some(Block::DeadHornCoralWallFan(data)) - } - 8520usize..=8527usize => { - let offset = id - 8520usize; - let data = TubeCoralWallFanData::from_value(offset)?; - Some(Block::TubeCoralWallFan(data)) - } - 8528usize..=8535usize => { - let offset = id - 8528usize; - let data = BrainCoralWallFanData::from_value(offset)?; - Some(Block::BrainCoralWallFan(data)) - } - 8536usize..=8543usize => { - let offset = id - 8536usize; - let data = BubbleCoralWallFanData::from_value(offset)?; - Some(Block::BubbleCoralWallFan(data)) - } - 8544usize..=8551usize => { - let offset = id - 8544usize; - let data = FireCoralWallFanData::from_value(offset)?; - Some(Block::FireCoralWallFan(data)) - } - 8552usize..=8559usize => { - let offset = id - 8552usize; - let data = HornCoralWallFanData::from_value(offset)?; - Some(Block::HornCoralWallFan(data)) - } - 8560usize..=8561usize => { - let offset = id - 8560usize; - let data = DeadTubeCoralFanData::from_value(offset)?; - Some(Block::DeadTubeCoralFan(data)) - } - 8562usize..=8563usize => { - let offset = id - 8562usize; - let data = DeadBrainCoralFanData::from_value(offset)?; - Some(Block::DeadBrainCoralFan(data)) - } - 8564usize..=8565usize => { - let offset = id - 8564usize; - let data = DeadBubbleCoralFanData::from_value(offset)?; - Some(Block::DeadBubbleCoralFan(data)) - } - 8566usize..=8567usize => { - let offset = id - 8566usize; - let data = DeadFireCoralFanData::from_value(offset)?; - Some(Block::DeadFireCoralFan(data)) - } - 8568usize..=8569usize => { - let offset = id - 8568usize; - let data = DeadHornCoralFanData::from_value(offset)?; - Some(Block::DeadHornCoralFan(data)) - } - 8570usize..=8571usize => { - let offset = id - 8570usize; - let data = TubeCoralFanData::from_value(offset)?; - Some(Block::TubeCoralFan(data)) - } - 8572usize..=8573usize => { - let offset = id - 8572usize; - let data = BrainCoralFanData::from_value(offset)?; - Some(Block::BrainCoralFan(data)) - } - 8574usize..=8575usize => { - let offset = id - 8574usize; - let data = BubbleCoralFanData::from_value(offset)?; - Some(Block::BubbleCoralFan(data)) - } - 8576usize..=8577usize => { - let offset = id - 8576usize; - let data = FireCoralFanData::from_value(offset)?; - Some(Block::FireCoralFan(data)) - } - 8578usize..=8579usize => { - let offset = id - 8578usize; - let data = HornCoralFanData::from_value(offset)?; - Some(Block::HornCoralFan(data)) - } - 8580usize..=8587usize => { - let offset = id - 8580usize; - let data = SeaPickleData::from_value(offset)?; - Some(Block::SeaPickle(data)) - } - 8588usize => Some(Block::BlueIce), - 8589usize..=8590usize => { - let offset = id - 8589usize; - let data = ConduitData::from_value(offset)?; - Some(Block::Conduit(data)) - } - 8591usize => Some(Block::VoidAir), - 8592usize => Some(Block::CaveAir), - 8593usize..=8594usize => { - let offset = id - 8593usize; - let data = BubbleColumnData::from_value(offset)?; - Some(Block::BubbleColumn(data)) - } - 8595usize..=8598usize => { - let offset = id - 8595usize; - let data = StructureBlockData::from_value(offset)?; - Some(Block::StructureBlock(data)) - } - _ => None, - } - } -} -pub trait Value { - fn value(&self) -> usize; - fn from_value(val: usize) -> Option - where - Self: Sized; -} -impl Value for i32 { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Some(val as i32) - } -} -impl Value for bool { - fn value(&self) -> usize { - match *self { - true => 1, - false => 0, - } - } - fn from_value(val: usize) -> Option { - match val { - 0 => Some(false), - 1 => Some(true), - _ => None, - } - } -} -pub trait FromSnakeCase { - fn from_snake_case(val: &str) -> Option - where - Self: Sized; -} -impl FromSnakeCase for i32 { - fn from_snake_case(val: &str) -> Option { - use std::str::FromStr; - match i32::from_str(val) { - Ok(x) => Some(x), - Err(_) => None, - } - } -} -impl FromSnakeCase for bool { - fn from_snake_case(val: &str) -> Option { - use std::str::FromStr; - match bool::from_str(val) { - Ok(x) => Some(x), - Err(_) => None, - } - } -} -pub trait ToSnakeCase { - fn to_snake_case(&self) -> String; -} -impl ToSnakeCase for i32 { - fn to_snake_case(&self) -> String { - self.to_string() - } -} -impl ToSnakeCase for bool { - fn to_snake_case(&self) -> String { - self.to_string() - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GrassBlockData { - pub snowy: bool, -} -impl GrassBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - snowy: bool::from_snake_case(map.get("snowy")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("snowy".to_string(), self.snowy.to_snake_case()); - m - } -} -impl Default for GrassBlockData { - fn default() -> Self { - Self { snowy: false } - } -} -impl Value for GrassBlockData { - fn value(&self) -> usize { - (self.snowy.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let snowy = bool::from_value(val / 1usize).unwrap(); - val -= (snowy.value() - 0usize) * 1usize; - Some(Self { snowy }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PodzolData { - pub snowy: bool, -} -impl PodzolData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - snowy: bool::from_snake_case(map.get("snowy")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("snowy".to_string(), self.snowy.to_snake_case()); - m - } -} -impl Default for PodzolData { - fn default() -> Self { - Self { snowy: false } - } -} -impl Value for PodzolData { - fn value(&self) -> usize { - (self.snowy.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let snowy = bool::from_value(val / 1usize).unwrap(); - val -= (snowy.value() - 0usize) * 1usize; - Some(Self { snowy }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakSaplingData { - pub stage: i32, -} -impl OakSaplingData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - stage: i32::from_snake_case(map.get("stage")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("stage".to_string(), self.stage.to_snake_case()); - m - } -} -impl Default for OakSaplingData { - fn default() -> Self { - Self { stage: 0 } - } -} -impl Value for OakSaplingData { - fn value(&self) -> usize { - (self.stage.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let stage = i32::from_value(val / 1usize).unwrap(); - val -= (stage.value() - 0usize) * 1usize; - Some(Self { stage }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceSaplingData { - pub stage: i32, -} -impl SpruceSaplingData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - stage: i32::from_snake_case(map.get("stage")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("stage".to_string(), self.stage.to_snake_case()); - m - } -} -impl Default for SpruceSaplingData { - fn default() -> Self { - Self { stage: 0 } - } -} -impl Value for SpruceSaplingData { - fn value(&self) -> usize { - (self.stage.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let stage = i32::from_value(val / 1usize).unwrap(); - val -= (stage.value() - 0usize) * 1usize; - Some(Self { stage }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchSaplingData { - pub stage: i32, -} -impl BirchSaplingData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - stage: i32::from_snake_case(map.get("stage")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("stage".to_string(), self.stage.to_snake_case()); - m - } -} -impl Default for BirchSaplingData { - fn default() -> Self { - Self { stage: 0 } - } -} -impl Value for BirchSaplingData { - fn value(&self) -> usize { - (self.stage.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let stage = i32::from_value(val / 1usize).unwrap(); - val -= (stage.value() - 0usize) * 1usize; - Some(Self { stage }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleSaplingData { - pub stage: i32, -} -impl JungleSaplingData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - stage: i32::from_snake_case(map.get("stage")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("stage".to_string(), self.stage.to_snake_case()); - m - } -} -impl Default for JungleSaplingData { - fn default() -> Self { - Self { stage: 0 } - } -} -impl Value for JungleSaplingData { - fn value(&self) -> usize { - (self.stage.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let stage = i32::from_value(val / 1usize).unwrap(); - val -= (stage.value() - 0usize) * 1usize; - Some(Self { stage }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaSaplingData { - pub stage: i32, -} -impl AcaciaSaplingData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - stage: i32::from_snake_case(map.get("stage")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("stage".to_string(), self.stage.to_snake_case()); - m - } -} -impl Default for AcaciaSaplingData { - fn default() -> Self { - Self { stage: 0 } - } -} -impl Value for AcaciaSaplingData { - fn value(&self) -> usize { - (self.stage.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let stage = i32::from_value(val / 1usize).unwrap(); - val -= (stage.value() - 0usize) * 1usize; - Some(Self { stage }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakSaplingData { - pub stage: i32, -} -impl DarkOakSaplingData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - stage: i32::from_snake_case(map.get("stage")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("stage".to_string(), self.stage.to_snake_case()); - m - } -} -impl Default for DarkOakSaplingData { - fn default() -> Self { - Self { stage: 0 } - } -} -impl Value for DarkOakSaplingData { - fn value(&self) -> usize { - (self.stage.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let stage = i32::from_value(val / 1usize).unwrap(); - val -= (stage.value() - 0usize) * 1usize; - Some(Self { stage }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WaterData { - pub level: i32, -} -impl WaterData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - level: i32::from_snake_case(map.get("level")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("level".to_string(), self.level.to_snake_case()); - m - } -} -impl Default for WaterData { - fn default() -> Self { - Self { level: 0 } - } -} -impl Value for WaterData { - fn value(&self) -> usize { - (self.level.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let level = i32::from_value(val / 1usize).unwrap(); - val -= (level.value() - 0usize) * 1usize; - Some(Self { level }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LavaData { - pub level: i32, -} -impl LavaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - level: i32::from_snake_case(map.get("level")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("level".to_string(), self.level.to_snake_case()); - m - } -} -impl Default for LavaData { - fn default() -> Self { - Self { level: 0 } - } -} -impl Value for LavaData { - fn value(&self) -> usize { - (self.level.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let level = i32::from_value(val / 1usize).unwrap(); - val -= (level.value() - 0usize) * 1usize; - Some(Self { level }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakLogData { - pub axis: OakLogAxis, -} -impl OakLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: OakLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for OakLogData { - fn default() -> Self { - Self { - axis: OakLogAxis::Y, - } - } -} -impl Value for OakLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = OakLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceLogData { - pub axis: SpruceLogAxis, -} -impl SpruceLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: SpruceLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for SpruceLogData { - fn default() -> Self { - Self { - axis: SpruceLogAxis::Y, - } - } -} -impl Value for SpruceLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = SpruceLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchLogData { - pub axis: BirchLogAxis, -} -impl BirchLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: BirchLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for BirchLogData { - fn default() -> Self { - Self { - axis: BirchLogAxis::Y, - } - } -} -impl Value for BirchLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = BirchLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleLogData { - pub axis: JungleLogAxis, -} -impl JungleLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: JungleLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for JungleLogData { - fn default() -> Self { - Self { - axis: JungleLogAxis::Y, - } - } -} -impl Value for JungleLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = JungleLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaLogData { - pub axis: AcaciaLogAxis, -} -impl AcaciaLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: AcaciaLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for AcaciaLogData { - fn default() -> Self { - Self { - axis: AcaciaLogAxis::Y, - } - } -} -impl Value for AcaciaLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = AcaciaLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakLogData { - pub axis: DarkOakLogAxis, -} -impl DarkOakLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: DarkOakLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for DarkOakLogData { - fn default() -> Self { - Self { - axis: DarkOakLogAxis::Y, - } - } -} -impl Value for DarkOakLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = DarkOakLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedSpruceLogData { - pub axis: StrippedSpruceLogAxis, -} -impl StrippedSpruceLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedSpruceLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedSpruceLogData { - fn default() -> Self { - Self { - axis: StrippedSpruceLogAxis::Y, - } - } -} -impl Value for StrippedSpruceLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedSpruceLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedBirchLogData { - pub axis: StrippedBirchLogAxis, -} -impl StrippedBirchLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedBirchLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedBirchLogData { - fn default() -> Self { - Self { - axis: StrippedBirchLogAxis::Y, - } - } -} -impl Value for StrippedBirchLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedBirchLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedJungleLogData { - pub axis: StrippedJungleLogAxis, -} -impl StrippedJungleLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedJungleLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedJungleLogData { - fn default() -> Self { - Self { - axis: StrippedJungleLogAxis::Y, - } - } -} -impl Value for StrippedJungleLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedJungleLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedAcaciaLogData { - pub axis: StrippedAcaciaLogAxis, -} -impl StrippedAcaciaLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedAcaciaLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedAcaciaLogData { - fn default() -> Self { - Self { - axis: StrippedAcaciaLogAxis::Y, - } - } -} -impl Value for StrippedAcaciaLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedAcaciaLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedDarkOakLogData { - pub axis: StrippedDarkOakLogAxis, -} -impl StrippedDarkOakLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedDarkOakLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedDarkOakLogData { - fn default() -> Self { - Self { - axis: StrippedDarkOakLogAxis::Y, - } - } -} -impl Value for StrippedDarkOakLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedDarkOakLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedOakLogData { - pub axis: StrippedOakLogAxis, -} -impl StrippedOakLogData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedOakLogAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedOakLogData { - fn default() -> Self { - Self { - axis: StrippedOakLogAxis::Y, - } - } -} -impl Value for StrippedOakLogData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedOakLogAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakWoodData { - pub axis: OakWoodAxis, -} -impl OakWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: OakWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for OakWoodData { - fn default() -> Self { - Self { - axis: OakWoodAxis::Y, - } - } -} -impl Value for OakWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = OakWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceWoodData { - pub axis: SpruceWoodAxis, -} -impl SpruceWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: SpruceWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for SpruceWoodData { - fn default() -> Self { - Self { - axis: SpruceWoodAxis::Y, - } - } -} -impl Value for SpruceWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = SpruceWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchWoodData { - pub axis: BirchWoodAxis, -} -impl BirchWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: BirchWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for BirchWoodData { - fn default() -> Self { - Self { - axis: BirchWoodAxis::Y, - } - } -} -impl Value for BirchWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = BirchWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleWoodData { - pub axis: JungleWoodAxis, -} -impl JungleWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: JungleWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for JungleWoodData { - fn default() -> Self { - Self { - axis: JungleWoodAxis::Y, - } - } -} -impl Value for JungleWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = JungleWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaWoodData { - pub axis: AcaciaWoodAxis, -} -impl AcaciaWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: AcaciaWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for AcaciaWoodData { - fn default() -> Self { - Self { - axis: AcaciaWoodAxis::Y, - } - } -} -impl Value for AcaciaWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = AcaciaWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakWoodData { - pub axis: DarkOakWoodAxis, -} -impl DarkOakWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: DarkOakWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for DarkOakWoodData { - fn default() -> Self { - Self { - axis: DarkOakWoodAxis::Y, - } - } -} -impl Value for DarkOakWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = DarkOakWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedOakWoodData { - pub axis: StrippedOakWoodAxis, -} -impl StrippedOakWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedOakWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedOakWoodData { - fn default() -> Self { - Self { - axis: StrippedOakWoodAxis::Y, - } - } -} -impl Value for StrippedOakWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedOakWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedSpruceWoodData { - pub axis: StrippedSpruceWoodAxis, -} -impl StrippedSpruceWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedSpruceWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedSpruceWoodData { - fn default() -> Self { - Self { - axis: StrippedSpruceWoodAxis::Y, - } - } -} -impl Value for StrippedSpruceWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedSpruceWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedBirchWoodData { - pub axis: StrippedBirchWoodAxis, -} -impl StrippedBirchWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedBirchWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedBirchWoodData { - fn default() -> Self { - Self { - axis: StrippedBirchWoodAxis::Y, - } - } -} -impl Value for StrippedBirchWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedBirchWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedJungleWoodData { - pub axis: StrippedJungleWoodAxis, -} -impl StrippedJungleWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedJungleWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedJungleWoodData { - fn default() -> Self { - Self { - axis: StrippedJungleWoodAxis::Y, - } - } -} -impl Value for StrippedJungleWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedJungleWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedAcaciaWoodData { - pub axis: StrippedAcaciaWoodAxis, -} -impl StrippedAcaciaWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedAcaciaWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedAcaciaWoodData { - fn default() -> Self { - Self { - axis: StrippedAcaciaWoodAxis::Y, - } - } -} -impl Value for StrippedAcaciaWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedAcaciaWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StrippedDarkOakWoodData { - pub axis: StrippedDarkOakWoodAxis, -} -impl StrippedDarkOakWoodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: StrippedDarkOakWoodAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for StrippedDarkOakWoodData { - fn default() -> Self { - Self { - axis: StrippedDarkOakWoodAxis::Y, - } - } -} -impl Value for StrippedDarkOakWoodData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = StrippedDarkOakWoodAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakLeavesData { - pub distance: i32, - pub persistent: bool, -} -impl OakLeavesData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - distance: i32::from_snake_case(map.get("distance")?)?, - persistent: bool::from_snake_case(map.get("persistent")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("distance".to_string(), self.distance.to_snake_case()); - m.insert("persistent".to_string(), self.persistent.to_snake_case()); - m - } -} -impl Default for OakLeavesData { - fn default() -> Self { - Self { - distance: 7, - persistent: false, - } - } -} -impl Value for OakLeavesData { - fn value(&self) -> usize { - ((self.distance.value() - 1) * 2usize) + (self.persistent.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 14usize { - return None; - } - let distance = i32::from_value(val / 2usize).unwrap() + 1i32; - val -= (distance.value() - 1usize) * 2usize; - let persistent = bool::from_value(val / 1usize).unwrap(); - val -= (persistent.value() - 0usize) * 1usize; - Some(Self { - distance, - persistent, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceLeavesData { - pub persistent: bool, - pub distance: i32, -} -impl SpruceLeavesData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - persistent: bool::from_snake_case(map.get("persistent")?)?, - distance: i32::from_snake_case(map.get("distance")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("persistent".to_string(), self.persistent.to_snake_case()); - m.insert("distance".to_string(), self.distance.to_snake_case()); - m - } -} -impl Default for SpruceLeavesData { - fn default() -> Self { - Self { - persistent: false, - distance: 7, - } - } -} -impl Value for SpruceLeavesData { - fn value(&self) -> usize { - (self.persistent.value() * 7usize) + ((self.distance.value() - 1) * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 14usize { - return None; - } - let persistent = bool::from_value(val / 7usize).unwrap(); - val -= (persistent.value() - 0usize) * 7usize; - let distance = i32::from_value(val / 1usize).unwrap() + 1i32; - val -= (distance.value() - 1usize) * 1usize; - Some(Self { - persistent, - distance, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchLeavesData { - pub persistent: bool, - pub distance: i32, -} -impl BirchLeavesData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - persistent: bool::from_snake_case(map.get("persistent")?)?, - distance: i32::from_snake_case(map.get("distance")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("persistent".to_string(), self.persistent.to_snake_case()); - m.insert("distance".to_string(), self.distance.to_snake_case()); - m - } -} -impl Default for BirchLeavesData { - fn default() -> Self { - Self { - persistent: false, - distance: 7, - } - } -} -impl Value for BirchLeavesData { - fn value(&self) -> usize { - (self.persistent.value() * 7usize) + ((self.distance.value() - 1) * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 14usize { - return None; - } - let persistent = bool::from_value(val / 7usize).unwrap(); - val -= (persistent.value() - 0usize) * 7usize; - let distance = i32::from_value(val / 1usize).unwrap() + 1i32; - val -= (distance.value() - 1usize) * 1usize; - Some(Self { - persistent, - distance, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleLeavesData { - pub persistent: bool, - pub distance: i32, -} -impl JungleLeavesData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - persistent: bool::from_snake_case(map.get("persistent")?)?, - distance: i32::from_snake_case(map.get("distance")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("persistent".to_string(), self.persistent.to_snake_case()); - m.insert("distance".to_string(), self.distance.to_snake_case()); - m - } -} -impl Default for JungleLeavesData { - fn default() -> Self { - Self { - persistent: false, - distance: 7, - } - } -} -impl Value for JungleLeavesData { - fn value(&self) -> usize { - (self.persistent.value() * 7usize) + ((self.distance.value() - 1) * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 14usize { - return None; - } - let persistent = bool::from_value(val / 7usize).unwrap(); - val -= (persistent.value() - 0usize) * 7usize; - let distance = i32::from_value(val / 1usize).unwrap() + 1i32; - val -= (distance.value() - 1usize) * 1usize; - Some(Self { - persistent, - distance, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaLeavesData { - pub distance: i32, - pub persistent: bool, -} -impl AcaciaLeavesData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - distance: i32::from_snake_case(map.get("distance")?)?, - persistent: bool::from_snake_case(map.get("persistent")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("distance".to_string(), self.distance.to_snake_case()); - m.insert("persistent".to_string(), self.persistent.to_snake_case()); - m - } -} -impl Default for AcaciaLeavesData { - fn default() -> Self { - Self { - distance: 7, - persistent: false, - } - } -} -impl Value for AcaciaLeavesData { - fn value(&self) -> usize { - ((self.distance.value() - 1) * 2usize) + (self.persistent.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 14usize { - return None; - } - let distance = i32::from_value(val / 2usize).unwrap() + 1i32; - val -= (distance.value() - 1usize) * 2usize; - let persistent = bool::from_value(val / 1usize).unwrap(); - val -= (persistent.value() - 0usize) * 1usize; - Some(Self { - distance, - persistent, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakLeavesData { - pub distance: i32, - pub persistent: bool, -} -impl DarkOakLeavesData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - distance: i32::from_snake_case(map.get("distance")?)?, - persistent: bool::from_snake_case(map.get("persistent")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("distance".to_string(), self.distance.to_snake_case()); - m.insert("persistent".to_string(), self.persistent.to_snake_case()); - m - } -} -impl Default for DarkOakLeavesData { - fn default() -> Self { - Self { - distance: 7, - persistent: false, - } - } -} -impl Value for DarkOakLeavesData { - fn value(&self) -> usize { - ((self.distance.value() - 1) * 2usize) + (self.persistent.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 14usize { - return None; - } - let distance = i32::from_value(val / 2usize).unwrap() + 1i32; - val -= (distance.value() - 1usize) * 2usize; - let persistent = bool::from_value(val / 1usize).unwrap(); - val -= (persistent.value() - 0usize) * 1usize; - Some(Self { - distance, - persistent, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DispenserData { - pub facing: DispenserFacing, - pub triggered: bool, -} -impl DispenserData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: DispenserFacing::from_snake_case(map.get("facing")?)?, - triggered: bool::from_snake_case(map.get("triggered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("triggered".to_string(), self.triggered.to_snake_case()); - m - } -} -impl Default for DispenserData { - fn default() -> Self { - Self { - facing: DispenserFacing::North, - triggered: false, - } - } -} -impl Value for DispenserData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.triggered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let facing = DispenserFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let triggered = bool::from_value(val / 1usize).unwrap(); - val -= (triggered.value() - 0usize) * 1usize; - Some(Self { facing, triggered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct NoteBlockData { - pub note: i32, - pub powered: bool, - pub instrument: NoteBlockInstrument, -} -impl NoteBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - note: i32::from_snake_case(map.get("note")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - instrument: NoteBlockInstrument::from_snake_case(map.get("instrument")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("note".to_string(), self.note.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("instrument".to_string(), self.instrument.to_snake_case()); - m - } -} -impl Default for NoteBlockData { - fn default() -> Self { - Self { - note: 0, - powered: false, - instrument: NoteBlockInstrument::Harp, - } - } -} -impl Value for NoteBlockData { - fn value(&self) -> usize { - (self.note.value() * 20usize) - + (self.powered.value() * 10usize) - + (self.instrument.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 500usize { - return None; - } - let note = i32::from_value(val / 20usize).unwrap(); - val -= (note.value() - 0usize) * 20usize; - let powered = bool::from_value(val / 10usize).unwrap(); - val -= (powered.value() - 0usize) * 10usize; - let instrument = NoteBlockInstrument::from_value(val / 1usize).unwrap(); - val -= (instrument.value() - 0usize) * 1usize; - Some(Self { - note, - powered, - instrument, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WhiteBedData { - pub part: WhiteBedPart, - pub facing: WhiteBedFacing, - pub occupied: bool, -} -impl WhiteBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - part: WhiteBedPart::from_snake_case(map.get("part")?)?, - facing: WhiteBedFacing::from_snake_case(map.get("facing")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m - } -} -impl Default for WhiteBedData { - fn default() -> Self { - Self { - part: WhiteBedPart::Foot, - facing: WhiteBedFacing::North, - occupied: false, - } - } -} -impl Value for WhiteBedData { - fn value(&self) -> usize { - (self.part.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.occupied.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let part = WhiteBedPart::from_value(val / 8usize).unwrap(); - val -= (part.value() - 0usize) * 8usize; - let facing = WhiteBedFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let occupied = bool::from_value(val / 1usize).unwrap(); - val -= (occupied.value() - 0usize) * 1usize; - Some(Self { - part, - facing, - occupied, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OrangeBedData { - pub occupied: bool, - pub facing: OrangeBedFacing, - pub part: OrangeBedPart, -} -impl OrangeBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - occupied: bool::from_snake_case(map.get("occupied")?)?, - facing: OrangeBedFacing::from_snake_case(map.get("facing")?)?, - part: OrangeBedPart::from_snake_case(map.get("part")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m - } -} -impl Default for OrangeBedData { - fn default() -> Self { - Self { - occupied: false, - facing: OrangeBedFacing::North, - part: OrangeBedPart::Foot, - } - } -} -impl Value for OrangeBedData { - fn value(&self) -> usize { - (self.occupied.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.part.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let occupied = bool::from_value(val / 8usize).unwrap(); - val -= (occupied.value() - 0usize) * 8usize; - let facing = OrangeBedFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let part = OrangeBedPart::from_value(val / 1usize).unwrap(); - val -= (part.value() - 0usize) * 1usize; - Some(Self { - occupied, - facing, - part, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MagentaBedData { - pub facing: MagentaBedFacing, - pub part: MagentaBedPart, - pub occupied: bool, -} -impl MagentaBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: MagentaBedFacing::from_snake_case(map.get("facing")?)?, - part: MagentaBedPart::from_snake_case(map.get("part")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m - } -} -impl Default for MagentaBedData { - fn default() -> Self { - Self { - facing: MagentaBedFacing::North, - part: MagentaBedPart::Foot, - occupied: false, - } - } -} -impl Value for MagentaBedData { - fn value(&self) -> usize { - (self.facing.value() * 4usize) - + (self.part.value() * 2usize) - + (self.occupied.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let facing = MagentaBedFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let part = MagentaBedPart::from_value(val / 2usize).unwrap(); - val -= (part.value() - 0usize) * 2usize; - let occupied = bool::from_value(val / 1usize).unwrap(); - val -= (occupied.value() - 0usize) * 1usize; - Some(Self { - facing, - part, - occupied, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightBlueBedData { - pub part: LightBlueBedPart, - pub occupied: bool, - pub facing: LightBlueBedFacing, -} -impl LightBlueBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - part: LightBlueBedPart::from_snake_case(map.get("part")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - facing: LightBlueBedFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LightBlueBedData { - fn default() -> Self { - Self { - part: LightBlueBedPart::Foot, - occupied: false, - facing: LightBlueBedFacing::North, - } - } -} -impl Value for LightBlueBedData { - fn value(&self) -> usize { - (self.part.value() * 8usize) - + (self.occupied.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let part = LightBlueBedPart::from_value(val / 8usize).unwrap(); - val -= (part.value() - 0usize) * 8usize; - let occupied = bool::from_value(val / 4usize).unwrap(); - val -= (occupied.value() - 0usize) * 4usize; - let facing = LightBlueBedFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - part, - occupied, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct YellowBedData { - pub facing: YellowBedFacing, - pub occupied: bool, - pub part: YellowBedPart, -} -impl YellowBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: YellowBedFacing::from_snake_case(map.get("facing")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - part: YellowBedPart::from_snake_case(map.get("part")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m - } -} -impl Default for YellowBedData { - fn default() -> Self { - Self { - facing: YellowBedFacing::North, - occupied: false, - part: YellowBedPart::Foot, - } - } -} -impl Value for YellowBedData { - fn value(&self) -> usize { - (self.facing.value() * 4usize) - + (self.occupied.value() * 2usize) - + (self.part.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let facing = YellowBedFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let occupied = bool::from_value(val / 2usize).unwrap(); - val -= (occupied.value() - 0usize) * 2usize; - let part = YellowBedPart::from_value(val / 1usize).unwrap(); - val -= (part.value() - 0usize) * 1usize; - Some(Self { - facing, - occupied, - part, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LimeBedData { - pub facing: LimeBedFacing, - pub occupied: bool, - pub part: LimeBedPart, -} -impl LimeBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LimeBedFacing::from_snake_case(map.get("facing")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - part: LimeBedPart::from_snake_case(map.get("part")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m - } -} -impl Default for LimeBedData { - fn default() -> Self { - Self { - facing: LimeBedFacing::North, - occupied: false, - part: LimeBedPart::Foot, - } - } -} -impl Value for LimeBedData { - fn value(&self) -> usize { - (self.facing.value() * 4usize) - + (self.occupied.value() * 2usize) - + (self.part.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let facing = LimeBedFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let occupied = bool::from_value(val / 2usize).unwrap(); - val -= (occupied.value() - 0usize) * 2usize; - let part = LimeBedPart::from_value(val / 1usize).unwrap(); - val -= (part.value() - 0usize) * 1usize; - Some(Self { - facing, - occupied, - part, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PinkBedData { - pub part: PinkBedPart, - pub facing: PinkBedFacing, - pub occupied: bool, -} -impl PinkBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - part: PinkBedPart::from_snake_case(map.get("part")?)?, - facing: PinkBedFacing::from_snake_case(map.get("facing")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m - } -} -impl Default for PinkBedData { - fn default() -> Self { - Self { - part: PinkBedPart::Foot, - facing: PinkBedFacing::North, - occupied: false, - } - } -} -impl Value for PinkBedData { - fn value(&self) -> usize { - (self.part.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.occupied.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let part = PinkBedPart::from_value(val / 8usize).unwrap(); - val -= (part.value() - 0usize) * 8usize; - let facing = PinkBedFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let occupied = bool::from_value(val / 1usize).unwrap(); - val -= (occupied.value() - 0usize) * 1usize; - Some(Self { - part, - facing, - occupied, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GrayBedData { - pub occupied: bool, - pub facing: GrayBedFacing, - pub part: GrayBedPart, -} -impl GrayBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - occupied: bool::from_snake_case(map.get("occupied")?)?, - facing: GrayBedFacing::from_snake_case(map.get("facing")?)?, - part: GrayBedPart::from_snake_case(map.get("part")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m - } -} -impl Default for GrayBedData { - fn default() -> Self { - Self { - occupied: false, - facing: GrayBedFacing::North, - part: GrayBedPart::Foot, - } - } -} -impl Value for GrayBedData { - fn value(&self) -> usize { - (self.occupied.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.part.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let occupied = bool::from_value(val / 8usize).unwrap(); - val -= (occupied.value() - 0usize) * 8usize; - let facing = GrayBedFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let part = GrayBedPart::from_value(val / 1usize).unwrap(); - val -= (part.value() - 0usize) * 1usize; - Some(Self { - occupied, - facing, - part, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightGrayBedData { - pub occupied: bool, - pub part: LightGrayBedPart, - pub facing: LightGrayBedFacing, -} -impl LightGrayBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - occupied: bool::from_snake_case(map.get("occupied")?)?, - part: LightGrayBedPart::from_snake_case(map.get("part")?)?, - facing: LightGrayBedFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LightGrayBedData { - fn default() -> Self { - Self { - occupied: false, - part: LightGrayBedPart::Foot, - facing: LightGrayBedFacing::North, - } - } -} -impl Value for LightGrayBedData { - fn value(&self) -> usize { - (self.occupied.value() * 8usize) - + (self.part.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let occupied = bool::from_value(val / 8usize).unwrap(); - val -= (occupied.value() - 0usize) * 8usize; - let part = LightGrayBedPart::from_value(val / 4usize).unwrap(); - val -= (part.value() - 0usize) * 4usize; - let facing = LightGrayBedFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - occupied, - part, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CyanBedData { - pub occupied: bool, - pub facing: CyanBedFacing, - pub part: CyanBedPart, -} -impl CyanBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - occupied: bool::from_snake_case(map.get("occupied")?)?, - facing: CyanBedFacing::from_snake_case(map.get("facing")?)?, - part: CyanBedPart::from_snake_case(map.get("part")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m - } -} -impl Default for CyanBedData { - fn default() -> Self { - Self { - occupied: false, - facing: CyanBedFacing::North, - part: CyanBedPart::Foot, - } - } -} -impl Value for CyanBedData { - fn value(&self) -> usize { - (self.occupied.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.part.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let occupied = bool::from_value(val / 8usize).unwrap(); - val -= (occupied.value() - 0usize) * 8usize; - let facing = CyanBedFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let part = CyanBedPart::from_value(val / 1usize).unwrap(); - val -= (part.value() - 0usize) * 1usize; - Some(Self { - occupied, - facing, - part, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpleBedData { - pub occupied: bool, - pub part: PurpleBedPart, - pub facing: PurpleBedFacing, -} -impl PurpleBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - occupied: bool::from_snake_case(map.get("occupied")?)?, - part: PurpleBedPart::from_snake_case(map.get("part")?)?, - facing: PurpleBedFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PurpleBedData { - fn default() -> Self { - Self { - occupied: false, - part: PurpleBedPart::Foot, - facing: PurpleBedFacing::North, - } - } -} -impl Value for PurpleBedData { - fn value(&self) -> usize { - (self.occupied.value() * 8usize) - + (self.part.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let occupied = bool::from_value(val / 8usize).unwrap(); - val -= (occupied.value() - 0usize) * 8usize; - let part = PurpleBedPart::from_value(val / 4usize).unwrap(); - val -= (part.value() - 0usize) * 4usize; - let facing = PurpleBedFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - occupied, - part, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlueBedData { - pub part: BlueBedPart, - pub facing: BlueBedFacing, - pub occupied: bool, -} -impl BlueBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - part: BlueBedPart::from_snake_case(map.get("part")?)?, - facing: BlueBedFacing::from_snake_case(map.get("facing")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m - } -} -impl Default for BlueBedData { - fn default() -> Self { - Self { - part: BlueBedPart::Foot, - facing: BlueBedFacing::North, - occupied: false, - } - } -} -impl Value for BlueBedData { - fn value(&self) -> usize { - (self.part.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.occupied.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let part = BlueBedPart::from_value(val / 8usize).unwrap(); - val -= (part.value() - 0usize) * 8usize; - let facing = BlueBedFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let occupied = bool::from_value(val / 1usize).unwrap(); - val -= (occupied.value() - 0usize) * 1usize; - Some(Self { - part, - facing, - occupied, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrownBedData { - pub part: BrownBedPart, - pub occupied: bool, - pub facing: BrownBedFacing, -} -impl BrownBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - part: BrownBedPart::from_snake_case(map.get("part")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - facing: BrownBedFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BrownBedData { - fn default() -> Self { - Self { - part: BrownBedPart::Foot, - occupied: false, - facing: BrownBedFacing::North, - } - } -} -impl Value for BrownBedData { - fn value(&self) -> usize { - (self.part.value() * 8usize) - + (self.occupied.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let part = BrownBedPart::from_value(val / 8usize).unwrap(); - val -= (part.value() - 0usize) * 8usize; - let occupied = bool::from_value(val / 4usize).unwrap(); - val -= (occupied.value() - 0usize) * 4usize; - let facing = BrownBedFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - part, - occupied, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GreenBedData { - pub facing: GreenBedFacing, - pub part: GreenBedPart, - pub occupied: bool, -} -impl GreenBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: GreenBedFacing::from_snake_case(map.get("facing")?)?, - part: GreenBedPart::from_snake_case(map.get("part")?)?, - occupied: bool::from_snake_case(map.get("occupied")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m - } -} -impl Default for GreenBedData { - fn default() -> Self { - Self { - facing: GreenBedFacing::North, - part: GreenBedPart::Foot, - occupied: false, - } - } -} -impl Value for GreenBedData { - fn value(&self) -> usize { - (self.facing.value() * 4usize) - + (self.part.value() * 2usize) - + (self.occupied.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let facing = GreenBedFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let part = GreenBedPart::from_value(val / 2usize).unwrap(); - val -= (part.value() - 0usize) * 2usize; - let occupied = bool::from_value(val / 1usize).unwrap(); - val -= (occupied.value() - 0usize) * 1usize; - Some(Self { - facing, - part, - occupied, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedBedData { - pub occupied: bool, - pub part: RedBedPart, - pub facing: RedBedFacing, -} -impl RedBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - occupied: bool::from_snake_case(map.get("occupied")?)?, - part: RedBedPart::from_snake_case(map.get("part")?)?, - facing: RedBedFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for RedBedData { - fn default() -> Self { - Self { - occupied: false, - part: RedBedPart::Foot, - facing: RedBedFacing::North, - } - } -} -impl Value for RedBedData { - fn value(&self) -> usize { - (self.occupied.value() * 8usize) - + (self.part.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let occupied = bool::from_value(val / 8usize).unwrap(); - val -= (occupied.value() - 0usize) * 8usize; - let part = RedBedPart::from_value(val / 4usize).unwrap(); - val -= (part.value() - 0usize) * 4usize; - let facing = RedBedFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - occupied, - part, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlackBedData { - pub occupied: bool, - pub part: BlackBedPart, - pub facing: BlackBedFacing, -} -impl BlackBedData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - occupied: bool::from_snake_case(map.get("occupied")?)?, - part: BlackBedPart::from_snake_case(map.get("part")?)?, - facing: BlackBedFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("occupied".to_string(), self.occupied.to_snake_case()); - m.insert("part".to_string(), self.part.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BlackBedData { - fn default() -> Self { - Self { - occupied: false, - part: BlackBedPart::Foot, - facing: BlackBedFacing::North, - } - } -} -impl Value for BlackBedData { - fn value(&self) -> usize { - (self.occupied.value() * 8usize) - + (self.part.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let occupied = bool::from_value(val / 8usize).unwrap(); - val -= (occupied.value() - 0usize) * 8usize; - let part = BlackBedPart::from_value(val / 4usize).unwrap(); - val -= (part.value() - 0usize) * 4usize; - let facing = BlackBedFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - occupied, - part, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PoweredRailData { - pub shape: PoweredRailShape, - pub powered: bool, -} -impl PoweredRailData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - shape: PoweredRailShape::from_snake_case(map.get("shape")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for PoweredRailData { - fn default() -> Self { - Self { - shape: PoweredRailShape::NorthSouth, - powered: false, - } - } -} -impl Value for PoweredRailData { - fn value(&self) -> usize { - (self.shape.value() * 2usize) + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let shape = PoweredRailShape::from_value(val / 2usize).unwrap(); - val -= (shape.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { shape, powered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DetectorRailData { - pub powered: bool, - pub shape: DetectorRailShape, -} -impl DetectorRailData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - shape: DetectorRailShape::from_snake_case(map.get("shape")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m - } -} -impl Default for DetectorRailData { - fn default() -> Self { - Self { - powered: false, - shape: DetectorRailShape::NorthSouth, - } - } -} -impl Value for DetectorRailData { - fn value(&self) -> usize { - (self.powered.value() * 6usize) + (self.shape.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let powered = bool::from_value(val / 6usize).unwrap(); - val -= (powered.value() - 0usize) * 6usize; - let shape = DetectorRailShape::from_value(val / 1usize).unwrap(); - val -= (shape.value() - 0usize) * 1usize; - Some(Self { powered, shape }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StickyPistonData { - pub extended: bool, - pub facing: StickyPistonFacing, -} -impl StickyPistonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - extended: bool::from_snake_case(map.get("extended")?)?, - facing: StickyPistonFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("extended".to_string(), self.extended.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for StickyPistonData { - fn default() -> Self { - Self { - extended: false, - facing: StickyPistonFacing::North, - } - } -} -impl Value for StickyPistonData { - fn value(&self) -> usize { - (self.extended.value() * 6usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let extended = bool::from_value(val / 6usize).unwrap(); - val -= (extended.value() - 0usize) * 6usize; - let facing = StickyPistonFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { extended, facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TallSeagrassData { - pub half: TallSeagrassHalf, -} -impl TallSeagrassData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: TallSeagrassHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for TallSeagrassData { - fn default() -> Self { - Self { - half: TallSeagrassHalf::Lower, - } - } -} -impl Value for TallSeagrassData { - fn value(&self) -> usize { - (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let half = TallSeagrassHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { half }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PistonData { - pub extended: bool, - pub facing: PistonFacing, -} -impl PistonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - extended: bool::from_snake_case(map.get("extended")?)?, - facing: PistonFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("extended".to_string(), self.extended.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PistonData { - fn default() -> Self { - Self { - extended: false, - facing: PistonFacing::North, - } - } -} -impl Value for PistonData { - fn value(&self) -> usize { - (self.extended.value() * 6usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let extended = bool::from_value(val / 6usize).unwrap(); - val -= (extended.value() - 0usize) * 6usize; - let facing = PistonFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { extended, facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PistonHeadData { - pub short: bool, - pub facing: PistonHeadFacing, - pub ty: PistonHeadType, -} -impl PistonHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - short: bool::from_snake_case(map.get("short")?)?, - facing: PistonHeadFacing::from_snake_case(map.get("facing")?)?, - ty: PistonHeadType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("short".to_string(), self.short.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for PistonHeadData { - fn default() -> Self { - Self { - short: false, - facing: PistonHeadFacing::North, - ty: PistonHeadType::Normal, - } - } -} -impl Value for PistonHeadData { - fn value(&self) -> usize { - (self.short.value() * 12usize) + (self.facing.value() * 2usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let short = bool::from_value(val / 12usize).unwrap(); - val -= (short.value() - 0usize) * 12usize; - let facing = PistonHeadFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let ty = PistonHeadType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { short, facing, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MovingPistonData { - pub facing: MovingPistonFacing, - pub ty: MovingPistonType, -} -impl MovingPistonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: MovingPistonFacing::from_snake_case(map.get("facing")?)?, - ty: MovingPistonType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for MovingPistonData { - fn default() -> Self { - Self { - facing: MovingPistonFacing::North, - ty: MovingPistonType::Normal, - } - } -} -impl Value for MovingPistonData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let facing = MovingPistonFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let ty = MovingPistonType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { facing, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TntData { - pub unstable: bool, -} -impl TntData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - unstable: bool::from_snake_case(map.get("unstable")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("unstable".to_string(), self.unstable.to_snake_case()); - m - } -} -impl Default for TntData { - fn default() -> Self { - Self { unstable: false } - } -} -impl Value for TntData { - fn value(&self) -> usize { - (self.unstable.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let unstable = bool::from_value(val / 1usize).unwrap(); - val -= (unstable.value() - 0usize) * 1usize; - Some(Self { unstable }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WallTorchData { - pub facing: WallTorchFacing, -} -impl WallTorchData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: WallTorchFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for WallTorchData { - fn default() -> Self { - Self { - facing: WallTorchFacing::North, - } - } -} -impl Value for WallTorchData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = WallTorchFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct FireData { - pub west: bool, - pub up: bool, - pub east: bool, - pub age: i32, - pub north: bool, - pub south: bool, -} -impl FireData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - up: bool::from_snake_case(map.get("up")?)?, - east: bool::from_snake_case(map.get("east")?)?, - age: i32::from_snake_case(map.get("age")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("up".to_string(), self.up.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("age".to_string(), self.age.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m - } -} -impl Default for FireData { - fn default() -> Self { - Self { - west: false, - up: false, - east: false, - age: 0, - north: false, - south: false, - } - } -} -impl Value for FireData { - fn value(&self) -> usize { - (self.west.value() * 256usize) - + (self.up.value() * 128usize) - + (self.east.value() * 64usize) - + (self.age.value() * 4usize) - + (self.north.value() * 2usize) - + (self.south.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 512usize { - return None; - } - let west = bool::from_value(val / 256usize).unwrap(); - val -= (west.value() - 0usize) * 256usize; - let up = bool::from_value(val / 128usize).unwrap(); - val -= (up.value() - 0usize) * 128usize; - let east = bool::from_value(val / 64usize).unwrap(); - val -= (east.value() - 0usize) * 64usize; - let age = i32::from_value(val / 4usize).unwrap(); - val -= (age.value() - 0usize) * 4usize; - let north = bool::from_value(val / 2usize).unwrap(); - val -= (north.value() - 0usize) * 2usize; - let south = bool::from_value(val / 1usize).unwrap(); - val -= (south.value() - 0usize) * 1usize; - Some(Self { - west, - up, - east, - age, - north, - south, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakStairsData { - pub shape: OakStairsShape, - pub half: OakStairsHalf, - pub facing: OakStairsFacing, - pub waterlogged: bool, -} -impl OakStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - shape: OakStairsShape::from_snake_case(map.get("shape")?)?, - half: OakStairsHalf::from_snake_case(map.get("half")?)?, - facing: OakStairsFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for OakStairsData { - fn default() -> Self { - Self { - shape: OakStairsShape::Straight, - half: OakStairsHalf::Bottom, - facing: OakStairsFacing::North, - waterlogged: false, - } - } -} -impl Value for OakStairsData { - fn value(&self) -> usize { - (self.shape.value() * 16usize) - + (self.half.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let shape = OakStairsShape::from_value(val / 16usize).unwrap(); - val -= (shape.value() - 0usize) * 16usize; - let half = OakStairsHalf::from_value(val / 8usize).unwrap(); - val -= (half.value() - 0usize) * 8usize; - let facing = OakStairsFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - shape, - half, - facing, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ChestData { - pub facing: ChestFacing, - pub ty: ChestType, - pub waterlogged: bool, -} -impl ChestData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: ChestFacing::from_snake_case(map.get("facing")?)?, - ty: ChestType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for ChestData { - fn default() -> Self { - Self { - facing: ChestFacing::North, - ty: ChestType::Single, - waterlogged: false, - } - } -} -impl Value for ChestData { - fn value(&self) -> usize { - (self.facing.value() * 6usize) - + (self.ty.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let facing = ChestFacing::from_value(val / 6usize).unwrap(); - val -= (facing.value() - 0usize) * 6usize; - let ty = ChestType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - ty, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedstoneWireData { - pub east: RedstoneWireEast, - pub north: RedstoneWireNorth, - pub power: i32, - pub south: RedstoneWireSouth, - pub west: RedstoneWireWest, -} -impl RedstoneWireData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: RedstoneWireEast::from_snake_case(map.get("east")?)?, - north: RedstoneWireNorth::from_snake_case(map.get("north")?)?, - power: i32::from_snake_case(map.get("power")?)?, - south: RedstoneWireSouth::from_snake_case(map.get("south")?)?, - west: RedstoneWireWest::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("power".to_string(), self.power.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for RedstoneWireData { - fn default() -> Self { - Self { - east: RedstoneWireEast::None, - north: RedstoneWireNorth::None, - power: 0, - south: RedstoneWireSouth::None, - west: RedstoneWireWest::None, - } - } -} -impl Value for RedstoneWireData { - fn value(&self) -> usize { - (self.east.value() * 432usize) - + (self.north.value() * 144usize) - + (self.power.value() * 9usize) - + (self.south.value() * 3usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 1296usize { - return None; - } - let east = RedstoneWireEast::from_value(val / 432usize).unwrap(); - val -= (east.value() - 0usize) * 432usize; - let north = RedstoneWireNorth::from_value(val / 144usize).unwrap(); - val -= (north.value() - 0usize) * 144usize; - let power = i32::from_value(val / 9usize).unwrap(); - val -= (power.value() - 0usize) * 9usize; - let south = RedstoneWireSouth::from_value(val / 3usize).unwrap(); - val -= (south.value() - 0usize) * 3usize; - let west = RedstoneWireWest::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - east, - north, - power, - south, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WheatData { - pub age: i32, -} -impl WheatData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for WheatData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for WheatData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct FarmlandData { - pub moisture: i32, -} -impl FarmlandData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - moisture: i32::from_snake_case(map.get("moisture")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("moisture".to_string(), self.moisture.to_snake_case()); - m - } -} -impl Default for FarmlandData { - fn default() -> Self { - Self { moisture: 0 } - } -} -impl Value for FarmlandData { - fn value(&self) -> usize { - (self.moisture.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let moisture = i32::from_value(val / 1usize).unwrap(); - val -= (moisture.value() - 0usize) * 1usize; - Some(Self { moisture }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct FurnaceData { - pub lit: bool, - pub facing: FurnaceFacing, -} -impl FurnaceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - lit: bool::from_snake_case(map.get("lit")?)?, - facing: FurnaceFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("lit".to_string(), self.lit.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for FurnaceData { - fn default() -> Self { - Self { - lit: false, - facing: FurnaceFacing::North, - } - } -} -impl Value for FurnaceData { - fn value(&self) -> usize { - (self.lit.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let lit = bool::from_value(val / 4usize).unwrap(); - val -= (lit.value() - 0usize) * 4usize; - let facing = FurnaceFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { lit, facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SignData { - pub rotation: i32, - pub waterlogged: bool, -} -impl SignData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for SignData { - fn default() -> Self { - Self { - rotation: 0, - waterlogged: false, - } - } -} -impl Value for SignData { - fn value(&self) -> usize { - (self.rotation.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let rotation = i32::from_value(val / 2usize).unwrap(); - val -= (rotation.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - rotation, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakDoorData { - pub facing: OakDoorFacing, - pub hinge: OakDoorHinge, - pub half: OakDoorHalf, - pub powered: bool, - pub open: bool, -} -impl OakDoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: OakDoorFacing::from_snake_case(map.get("facing")?)?, - hinge: OakDoorHinge::from_snake_case(map.get("hinge")?)?, - half: OakDoorHalf::from_snake_case(map.get("half")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - open: bool::from_snake_case(map.get("open")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("hinge".to_string(), self.hinge.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m - } -} -impl Default for OakDoorData { - fn default() -> Self { - Self { - facing: OakDoorFacing::North, - hinge: OakDoorHinge::Left, - half: OakDoorHalf::Lower, - powered: false, - open: false, - } - } -} -impl Value for OakDoorData { - fn value(&self) -> usize { - (self.facing.value() * 16usize) - + (self.hinge.value() * 8usize) - + (self.half.value() * 4usize) - + (self.powered.value() * 2usize) - + (self.open.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let facing = OakDoorFacing::from_value(val / 16usize).unwrap(); - val -= (facing.value() - 0usize) * 16usize; - let hinge = OakDoorHinge::from_value(val / 8usize).unwrap(); - val -= (hinge.value() - 0usize) * 8usize; - let half = OakDoorHalf::from_value(val / 4usize).unwrap(); - val -= (half.value() - 0usize) * 4usize; - let powered = bool::from_value(val / 2usize).unwrap(); - val -= (powered.value() - 0usize) * 2usize; - let open = bool::from_value(val / 1usize).unwrap(); - val -= (open.value() - 0usize) * 1usize; - Some(Self { - facing, - hinge, - half, - powered, - open, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LadderData { - pub waterlogged: bool, - pub facing: LadderFacing, -} -impl LadderData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: LadderFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LadderData { - fn default() -> Self { - Self { - waterlogged: false, - facing: LadderFacing::North, - } - } -} -impl Value for LadderData { - fn value(&self) -> usize { - (self.waterlogged.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = LadderFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RailData { - pub shape: RailShape, -} -impl RailData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - shape: RailShape::from_snake_case(map.get("shape")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m - } -} -impl Default for RailData { - fn default() -> Self { - Self { - shape: RailShape::NorthSouth, - } - } -} -impl Value for RailData { - fn value(&self) -> usize { - (self.shape.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 10usize { - return None; - } - let shape = RailShape::from_value(val / 1usize).unwrap(); - val -= (shape.value() - 0usize) * 1usize; - Some(Self { shape }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CobblestoneStairsData { - pub shape: CobblestoneStairsShape, - pub waterlogged: bool, - pub half: CobblestoneStairsHalf, - pub facing: CobblestoneStairsFacing, -} -impl CobblestoneStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - shape: CobblestoneStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: CobblestoneStairsHalf::from_snake_case(map.get("half")?)?, - facing: CobblestoneStairsFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for CobblestoneStairsData { - fn default() -> Self { - Self { - shape: CobblestoneStairsShape::Straight, - waterlogged: false, - half: CobblestoneStairsHalf::Bottom, - facing: CobblestoneStairsFacing::North, - } - } -} -impl Value for CobblestoneStairsData { - fn value(&self) -> usize { - (self.shape.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.half.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let shape = CobblestoneStairsShape::from_value(val / 16usize).unwrap(); - val -= (shape.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let half = CobblestoneStairsHalf::from_value(val / 4usize).unwrap(); - val -= (half.value() - 0usize) * 4usize; - let facing = CobblestoneStairsFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - shape, - waterlogged, - half, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WallSignData { - pub facing: WallSignFacing, - pub waterlogged: bool, -} -impl WallSignData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: WallSignFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for WallSignData { - fn default() -> Self { - Self { - facing: WallSignFacing::North, - waterlogged: false, - } - } -} -impl Value for WallSignData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let facing = WallSignFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LeverData { - pub powered: bool, - pub facing: LeverFacing, - pub face: LeverFace, -} -impl LeverData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - facing: LeverFacing::from_snake_case(map.get("facing")?)?, - face: LeverFace::from_snake_case(map.get("face")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("face".to_string(), self.face.to_snake_case()); - m - } -} -impl Default for LeverData { - fn default() -> Self { - Self { - powered: false, - facing: LeverFacing::North, - face: LeverFace::Wall, - } - } -} -impl Value for LeverData { - fn value(&self) -> usize { - (self.powered.value() * 12usize) - + (self.facing.value() * 3usize) - + (self.face.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let powered = bool::from_value(val / 12usize).unwrap(); - val -= (powered.value() - 0usize) * 12usize; - let facing = LeverFacing::from_value(val / 3usize).unwrap(); - val -= (facing.value() - 0usize) * 3usize; - let face = LeverFace::from_value(val / 1usize).unwrap(); - val -= (face.value() - 0usize) * 1usize; - Some(Self { - powered, - facing, - face, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StonePressurePlateData { - pub powered: bool, -} -impl StonePressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for StonePressurePlateData { - fn default() -> Self { - Self { powered: false } - } -} -impl Value for StonePressurePlateData { - fn value(&self) -> usize { - (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { powered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct IronDoorData { - pub facing: IronDoorFacing, - pub powered: bool, - pub half: IronDoorHalf, - pub hinge: IronDoorHinge, - pub open: bool, -} -impl IronDoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: IronDoorFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - half: IronDoorHalf::from_snake_case(map.get("half")?)?, - hinge: IronDoorHinge::from_snake_case(map.get("hinge")?)?, - open: bool::from_snake_case(map.get("open")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("hinge".to_string(), self.hinge.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m - } -} -impl Default for IronDoorData { - fn default() -> Self { - Self { - facing: IronDoorFacing::North, - powered: false, - half: IronDoorHalf::Lower, - hinge: IronDoorHinge::Left, - open: false, - } - } -} -impl Value for IronDoorData { - fn value(&self) -> usize { - (self.facing.value() * 16usize) - + (self.powered.value() * 8usize) - + (self.half.value() * 4usize) - + (self.hinge.value() * 2usize) - + (self.open.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let facing = IronDoorFacing::from_value(val / 16usize).unwrap(); - val -= (facing.value() - 0usize) * 16usize; - let powered = bool::from_value(val / 8usize).unwrap(); - val -= (powered.value() - 0usize) * 8usize; - let half = IronDoorHalf::from_value(val / 4usize).unwrap(); - val -= (half.value() - 0usize) * 4usize; - let hinge = IronDoorHinge::from_value(val / 2usize).unwrap(); - val -= (hinge.value() - 0usize) * 2usize; - let open = bool::from_value(val / 1usize).unwrap(); - val -= (open.value() - 0usize) * 1usize; - Some(Self { - facing, - powered, - half, - hinge, - open, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakPressurePlateData { - pub powered: bool, -} -impl OakPressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for OakPressurePlateData { - fn default() -> Self { - Self { powered: false } - } -} -impl Value for OakPressurePlateData { - fn value(&self) -> usize { - (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { powered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SprucePressurePlateData { - pub powered: bool, -} -impl SprucePressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for SprucePressurePlateData { - fn default() -> Self { - Self { powered: false } - } -} -impl Value for SprucePressurePlateData { - fn value(&self) -> usize { - (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { powered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchPressurePlateData { - pub powered: bool, -} -impl BirchPressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for BirchPressurePlateData { - fn default() -> Self { - Self { powered: false } - } -} -impl Value for BirchPressurePlateData { - fn value(&self) -> usize { - (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { powered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JunglePressurePlateData { - pub powered: bool, -} -impl JunglePressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for JunglePressurePlateData { - fn default() -> Self { - Self { powered: false } - } -} -impl Value for JunglePressurePlateData { - fn value(&self) -> usize { - (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { powered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaPressurePlateData { - pub powered: bool, -} -impl AcaciaPressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for AcaciaPressurePlateData { - fn default() -> Self { - Self { powered: false } - } -} -impl Value for AcaciaPressurePlateData { - fn value(&self) -> usize { - (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { powered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakPressurePlateData { - pub powered: bool, -} -impl DarkOakPressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for DarkOakPressurePlateData { - fn default() -> Self { - Self { powered: false } - } -} -impl Value for DarkOakPressurePlateData { - fn value(&self) -> usize { - (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { powered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedstoneOreData { - pub lit: bool, -} -impl RedstoneOreData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - lit: bool::from_snake_case(map.get("lit")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("lit".to_string(), self.lit.to_snake_case()); - m - } -} -impl Default for RedstoneOreData { - fn default() -> Self { - Self { lit: false } - } -} -impl Value for RedstoneOreData { - fn value(&self) -> usize { - (self.lit.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let lit = bool::from_value(val / 1usize).unwrap(); - val -= (lit.value() - 0usize) * 1usize; - Some(Self { lit }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedstoneTorchData { - pub lit: bool, -} -impl RedstoneTorchData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - lit: bool::from_snake_case(map.get("lit")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("lit".to_string(), self.lit.to_snake_case()); - m - } -} -impl Default for RedstoneTorchData { - fn default() -> Self { - Self { lit: true } - } -} -impl Value for RedstoneTorchData { - fn value(&self) -> usize { - (self.lit.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let lit = bool::from_value(val / 1usize).unwrap(); - val -= (lit.value() - 0usize) * 1usize; - Some(Self { lit }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedstoneWallTorchData { - pub facing: RedstoneWallTorchFacing, - pub lit: bool, -} -impl RedstoneWallTorchData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: RedstoneWallTorchFacing::from_snake_case(map.get("facing")?)?, - lit: bool::from_snake_case(map.get("lit")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("lit".to_string(), self.lit.to_snake_case()); - m - } -} -impl Default for RedstoneWallTorchData { - fn default() -> Self { - Self { - facing: RedstoneWallTorchFacing::North, - lit: true, - } - } -} -impl Value for RedstoneWallTorchData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.lit.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let facing = RedstoneWallTorchFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let lit = bool::from_value(val / 1usize).unwrap(); - val -= (lit.value() - 0usize) * 1usize; - Some(Self { facing, lit }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StoneButtonData { - pub facing: StoneButtonFacing, - pub face: StoneButtonFace, - pub powered: bool, -} -impl StoneButtonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: StoneButtonFacing::from_snake_case(map.get("facing")?)?, - face: StoneButtonFace::from_snake_case(map.get("face")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("face".to_string(), self.face.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for StoneButtonData { - fn default() -> Self { - Self { - facing: StoneButtonFacing::North, - face: StoneButtonFace::Wall, - powered: false, - } - } -} -impl Value for StoneButtonData { - fn value(&self) -> usize { - (self.facing.value() * 6usize) - + (self.face.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let facing = StoneButtonFacing::from_value(val / 6usize).unwrap(); - val -= (facing.value() - 0usize) * 6usize; - let face = StoneButtonFace::from_value(val / 2usize).unwrap(); - val -= (face.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - facing, - face, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SnowData { - pub layers: i32, -} -impl SnowData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - layers: i32::from_snake_case(map.get("layers")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("layers".to_string(), self.layers.to_snake_case()); - m - } -} -impl Default for SnowData { - fn default() -> Self { - Self { layers: 1 } - } -} -impl Value for SnowData { - fn value(&self) -> usize { - ((self.layers.value() - 1) * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let layers = i32::from_value(val / 1usize).unwrap() + 1i32; - val -= (layers.value() - 1usize) * 1usize; - Some(Self { layers }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CactusData { - pub age: i32, -} -impl CactusData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for CactusData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for CactusData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SugarCaneData { - pub age: i32, -} -impl SugarCaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for SugarCaneData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for SugarCaneData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JukeboxData { - pub has_record: bool, -} -impl JukeboxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - has_record: bool::from_snake_case(map.get("has_record")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("has_record".to_string(), self.has_record.to_snake_case()); - m - } -} -impl Default for JukeboxData { - fn default() -> Self { - Self { has_record: false } - } -} -impl Value for JukeboxData { - fn value(&self) -> usize { - (self.has_record.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let has_record = bool::from_value(val / 1usize).unwrap(); - val -= (has_record.value() - 0usize) * 1usize; - Some(Self { has_record }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakFenceData { - pub west: bool, - pub east: bool, - pub waterlogged: bool, - pub south: bool, - pub north: bool, -} -impl OakFenceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - south: bool::from_snake_case(map.get("south")?)?, - north: bool::from_snake_case(map.get("north")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m - } -} -impl Default for OakFenceData { - fn default() -> Self { - Self { - west: false, - east: false, - waterlogged: false, - south: false, - north: false, - } - } -} -impl Value for OakFenceData { - fn value(&self) -> usize { - (self.west.value() * 16usize) - + (self.east.value() * 8usize) - + (self.waterlogged.value() * 4usize) - + (self.south.value() * 2usize) - + (self.north.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let east = bool::from_value(val / 8usize).unwrap(); - val -= (east.value() - 0usize) * 8usize; - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let south = bool::from_value(val / 2usize).unwrap(); - val -= (south.value() - 0usize) * 2usize; - let north = bool::from_value(val / 1usize).unwrap(); - val -= (north.value() - 0usize) * 1usize; - Some(Self { - west, - east, - waterlogged, - south, - north, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct NetherPortalData { - pub axis: NetherPortalAxis, -} -impl NetherPortalData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: NetherPortalAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for NetherPortalData { - fn default() -> Self { - Self { - axis: NetherPortalAxis::X, - } - } -} -impl Value for NetherPortalData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let axis = NetherPortalAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CarvedPumpkinData { - pub facing: CarvedPumpkinFacing, -} -impl CarvedPumpkinData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: CarvedPumpkinFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for CarvedPumpkinData { - fn default() -> Self { - Self { - facing: CarvedPumpkinFacing::North, - } - } -} -impl Value for CarvedPumpkinData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = CarvedPumpkinFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JackOLanternData { - pub facing: JackOLanternFacing, -} -impl JackOLanternData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: JackOLanternFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for JackOLanternData { - fn default() -> Self { - Self { - facing: JackOLanternFacing::North, - } - } -} -impl Value for JackOLanternData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = JackOLanternFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CakeData { - pub bites: i32, -} -impl CakeData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - bites: i32::from_snake_case(map.get("bites")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("bites".to_string(), self.bites.to_snake_case()); - m - } -} -impl Default for CakeData { - fn default() -> Self { - Self { bites: 0 } - } -} -impl Value for CakeData { - fn value(&self) -> usize { - (self.bites.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 7usize { - return None; - } - let bites = i32::from_value(val / 1usize).unwrap(); - val -= (bites.value() - 0usize) * 1usize; - Some(Self { bites }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RepeaterData { - pub delay: i32, - pub locked: bool, - pub facing: RepeaterFacing, - pub powered: bool, -} -impl RepeaterData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - delay: i32::from_snake_case(map.get("delay")?)?, - locked: bool::from_snake_case(map.get("locked")?)?, - facing: RepeaterFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("delay".to_string(), self.delay.to_snake_case()); - m.insert("locked".to_string(), self.locked.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for RepeaterData { - fn default() -> Self { - Self { - delay: 1, - locked: false, - facing: RepeaterFacing::North, - powered: false, - } - } -} -impl Value for RepeaterData { - fn value(&self) -> usize { - ((self.delay.value() - 1) * 16usize) - + (self.locked.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let delay = i32::from_value(val / 16usize).unwrap() + 1i32; - val -= (delay.value() - 1usize) * 16usize; - let locked = bool::from_value(val / 8usize).unwrap(); - val -= (locked.value() - 0usize) * 8usize; - let facing = RepeaterFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - delay, - locked, - facing, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakTrapdoorData { - pub open: bool, - pub powered: bool, - pub waterlogged: bool, - pub half: OakTrapdoorHalf, - pub facing: OakTrapdoorFacing, -} -impl OakTrapdoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - open: bool::from_snake_case(map.get("open")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: OakTrapdoorHalf::from_snake_case(map.get("half")?)?, - facing: OakTrapdoorFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for OakTrapdoorData { - fn default() -> Self { - Self { - open: false, - powered: false, - waterlogged: false, - half: OakTrapdoorHalf::Bottom, - facing: OakTrapdoorFacing::North, - } - } -} -impl Value for OakTrapdoorData { - fn value(&self) -> usize { - (self.open.value() * 32usize) - + (self.powered.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.half.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let open = bool::from_value(val / 32usize).unwrap(); - val -= (open.value() - 0usize) * 32usize; - let powered = bool::from_value(val / 16usize).unwrap(); - val -= (powered.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let half = OakTrapdoorHalf::from_value(val / 4usize).unwrap(); - val -= (half.value() - 0usize) * 4usize; - let facing = OakTrapdoorFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - open, - powered, - waterlogged, - half, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceTrapdoorData { - pub open: bool, - pub half: SpruceTrapdoorHalf, - pub powered: bool, - pub waterlogged: bool, - pub facing: SpruceTrapdoorFacing, -} -impl SpruceTrapdoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - open: bool::from_snake_case(map.get("open")?)?, - half: SpruceTrapdoorHalf::from_snake_case(map.get("half")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: SpruceTrapdoorFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for SpruceTrapdoorData { - fn default() -> Self { - Self { - open: false, - half: SpruceTrapdoorHalf::Bottom, - powered: false, - waterlogged: false, - facing: SpruceTrapdoorFacing::North, - } - } -} -impl Value for SpruceTrapdoorData { - fn value(&self) -> usize { - (self.open.value() * 32usize) - + (self.half.value() * 16usize) - + (self.powered.value() * 8usize) - + (self.waterlogged.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let open = bool::from_value(val / 32usize).unwrap(); - val -= (open.value() - 0usize) * 32usize; - let half = SpruceTrapdoorHalf::from_value(val / 16usize).unwrap(); - val -= (half.value() - 0usize) * 16usize; - let powered = bool::from_value(val / 8usize).unwrap(); - val -= (powered.value() - 0usize) * 8usize; - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = SpruceTrapdoorFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - open, - half, - powered, - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchTrapdoorData { - pub powered: bool, - pub half: BirchTrapdoorHalf, - pub waterlogged: bool, - pub facing: BirchTrapdoorFacing, - pub open: bool, -} -impl BirchTrapdoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - half: BirchTrapdoorHalf::from_snake_case(map.get("half")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: BirchTrapdoorFacing::from_snake_case(map.get("facing")?)?, - open: bool::from_snake_case(map.get("open")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m - } -} -impl Default for BirchTrapdoorData { - fn default() -> Self { - Self { - powered: false, - half: BirchTrapdoorHalf::Bottom, - waterlogged: false, - facing: BirchTrapdoorFacing::North, - open: false, - } - } -} -impl Value for BirchTrapdoorData { - fn value(&self) -> usize { - (self.powered.value() * 32usize) - + (self.half.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.open.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let powered = bool::from_value(val / 32usize).unwrap(); - val -= (powered.value() - 0usize) * 32usize; - let half = BirchTrapdoorHalf::from_value(val / 16usize).unwrap(); - val -= (half.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let facing = BirchTrapdoorFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let open = bool::from_value(val / 1usize).unwrap(); - val -= (open.value() - 0usize) * 1usize; - Some(Self { - powered, - half, - waterlogged, - facing, - open, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleTrapdoorData { - pub waterlogged: bool, - pub facing: JungleTrapdoorFacing, - pub open: bool, - pub half: JungleTrapdoorHalf, - pub powered: bool, -} -impl JungleTrapdoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: JungleTrapdoorFacing::from_snake_case(map.get("facing")?)?, - open: bool::from_snake_case(map.get("open")?)?, - half: JungleTrapdoorHalf::from_snake_case(map.get("half")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for JungleTrapdoorData { - fn default() -> Self { - Self { - waterlogged: false, - facing: JungleTrapdoorFacing::North, - open: false, - half: JungleTrapdoorHalf::Bottom, - powered: false, - } - } -} -impl Value for JungleTrapdoorData { - fn value(&self) -> usize { - (self.waterlogged.value() * 32usize) - + (self.facing.value() * 8usize) - + (self.open.value() * 4usize) - + (self.half.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let waterlogged = bool::from_value(val / 32usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 32usize; - let facing = JungleTrapdoorFacing::from_value(val / 8usize).unwrap(); - val -= (facing.value() - 0usize) * 8usize; - let open = bool::from_value(val / 4usize).unwrap(); - val -= (open.value() - 0usize) * 4usize; - let half = JungleTrapdoorHalf::from_value(val / 2usize).unwrap(); - val -= (half.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - facing, - open, - half, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaTrapdoorData { - pub open: bool, - pub waterlogged: bool, - pub facing: AcaciaTrapdoorFacing, - pub half: AcaciaTrapdoorHalf, - pub powered: bool, -} -impl AcaciaTrapdoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - open: bool::from_snake_case(map.get("open")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: AcaciaTrapdoorFacing::from_snake_case(map.get("facing")?)?, - half: AcaciaTrapdoorHalf::from_snake_case(map.get("half")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for AcaciaTrapdoorData { - fn default() -> Self { - Self { - open: false, - waterlogged: false, - facing: AcaciaTrapdoorFacing::North, - half: AcaciaTrapdoorHalf::Bottom, - powered: false, - } - } -} -impl Value for AcaciaTrapdoorData { - fn value(&self) -> usize { - (self.open.value() * 32usize) - + (self.waterlogged.value() * 16usize) - + (self.facing.value() * 4usize) - + (self.half.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let open = bool::from_value(val / 32usize).unwrap(); - val -= (open.value() - 0usize) * 32usize; - let waterlogged = bool::from_value(val / 16usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 16usize; - let facing = AcaciaTrapdoorFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let half = AcaciaTrapdoorHalf::from_value(val / 2usize).unwrap(); - val -= (half.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - open, - waterlogged, - facing, - half, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakTrapdoorData { - pub waterlogged: bool, - pub half: DarkOakTrapdoorHalf, - pub powered: bool, - pub facing: DarkOakTrapdoorFacing, - pub open: bool, -} -impl DarkOakTrapdoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: DarkOakTrapdoorHalf::from_snake_case(map.get("half")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - facing: DarkOakTrapdoorFacing::from_snake_case(map.get("facing")?)?, - open: bool::from_snake_case(map.get("open")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m - } -} -impl Default for DarkOakTrapdoorData { - fn default() -> Self { - Self { - waterlogged: false, - half: DarkOakTrapdoorHalf::Bottom, - powered: false, - facing: DarkOakTrapdoorFacing::North, - open: false, - } - } -} -impl Value for DarkOakTrapdoorData { - fn value(&self) -> usize { - (self.waterlogged.value() * 32usize) - + (self.half.value() * 16usize) - + (self.powered.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.open.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let waterlogged = bool::from_value(val / 32usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 32usize; - let half = DarkOakTrapdoorHalf::from_value(val / 16usize).unwrap(); - val -= (half.value() - 0usize) * 16usize; - let powered = bool::from_value(val / 8usize).unwrap(); - val -= (powered.value() - 0usize) * 8usize; - let facing = DarkOakTrapdoorFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let open = bool::from_value(val / 1usize).unwrap(); - val -= (open.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - half, - powered, - facing, - open, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrownMushroomBlockData { - pub north: bool, - pub down: bool, - pub up: bool, - pub west: bool, - pub south: bool, - pub east: bool, -} -impl BrownMushroomBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - north: bool::from_snake_case(map.get("north")?)?, - down: bool::from_snake_case(map.get("down")?)?, - up: bool::from_snake_case(map.get("up")?)?, - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - east: bool::from_snake_case(map.get("east")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("down".to_string(), self.down.to_snake_case()); - m.insert("up".to_string(), self.up.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m - } -} -impl Default for BrownMushroomBlockData { - fn default() -> Self { - Self { - north: true, - down: true, - up: true, - west: true, - south: true, - east: true, - } - } -} -impl Value for BrownMushroomBlockData { - fn value(&self) -> usize { - (self.north.value() * 32usize) - + (self.down.value() * 16usize) - + (self.up.value() * 8usize) - + (self.west.value() * 4usize) - + (self.south.value() * 2usize) - + (self.east.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let north = bool::from_value(val / 32usize).unwrap(); - val -= (north.value() - 0usize) * 32usize; - let down = bool::from_value(val / 16usize).unwrap(); - val -= (down.value() - 0usize) * 16usize; - let up = bool::from_value(val / 8usize).unwrap(); - val -= (up.value() - 0usize) * 8usize; - let west = bool::from_value(val / 4usize).unwrap(); - val -= (west.value() - 0usize) * 4usize; - let south = bool::from_value(val / 2usize).unwrap(); - val -= (south.value() - 0usize) * 2usize; - let east = bool::from_value(val / 1usize).unwrap(); - val -= (east.value() - 0usize) * 1usize; - Some(Self { - north, - down, - up, - west, - south, - east, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedMushroomBlockData { - pub south: bool, - pub down: bool, - pub up: bool, - pub north: bool, - pub west: bool, - pub east: bool, -} -impl RedMushroomBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - south: bool::from_snake_case(map.get("south")?)?, - down: bool::from_snake_case(map.get("down")?)?, - up: bool::from_snake_case(map.get("up")?)?, - north: bool::from_snake_case(map.get("north")?)?, - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("down".to_string(), self.down.to_snake_case()); - m.insert("up".to_string(), self.up.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m - } -} -impl Default for RedMushroomBlockData { - fn default() -> Self { - Self { - south: true, - down: true, - up: true, - north: true, - west: true, - east: true, - } - } -} -impl Value for RedMushroomBlockData { - fn value(&self) -> usize { - (self.south.value() * 32usize) - + (self.down.value() * 16usize) - + (self.up.value() * 8usize) - + (self.north.value() * 4usize) - + (self.west.value() * 2usize) - + (self.east.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let south = bool::from_value(val / 32usize).unwrap(); - val -= (south.value() - 0usize) * 32usize; - let down = bool::from_value(val / 16usize).unwrap(); - val -= (down.value() - 0usize) * 16usize; - let up = bool::from_value(val / 8usize).unwrap(); - val -= (up.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let west = bool::from_value(val / 2usize).unwrap(); - val -= (west.value() - 0usize) * 2usize; - let east = bool::from_value(val / 1usize).unwrap(); - val -= (east.value() - 0usize) * 1usize; - Some(Self { - south, - down, - up, - north, - west, - east, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MushroomStemData { - pub up: bool, - pub west: bool, - pub north: bool, - pub east: bool, - pub south: bool, - pub down: bool, -} -impl MushroomStemData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - up: bool::from_snake_case(map.get("up")?)?, - west: bool::from_snake_case(map.get("west")?)?, - north: bool::from_snake_case(map.get("north")?)?, - east: bool::from_snake_case(map.get("east")?)?, - south: bool::from_snake_case(map.get("south")?)?, - down: bool::from_snake_case(map.get("down")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("up".to_string(), self.up.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("down".to_string(), self.down.to_snake_case()); - m - } -} -impl Default for MushroomStemData { - fn default() -> Self { - Self { - up: true, - west: true, - north: true, - east: true, - south: true, - down: true, - } - } -} -impl Value for MushroomStemData { - fn value(&self) -> usize { - (self.up.value() * 32usize) - + (self.west.value() * 16usize) - + (self.north.value() * 8usize) - + (self.east.value() * 4usize) - + (self.south.value() * 2usize) - + (self.down.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let up = bool::from_value(val / 32usize).unwrap(); - val -= (up.value() - 0usize) * 32usize; - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let east = bool::from_value(val / 4usize).unwrap(); - val -= (east.value() - 0usize) * 4usize; - let south = bool::from_value(val / 2usize).unwrap(); - val -= (south.value() - 0usize) * 2usize; - let down = bool::from_value(val / 1usize).unwrap(); - val -= (down.value() - 0usize) * 1usize; - Some(Self { - up, - west, - north, - east, - south, - down, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct IronBarsData { - pub waterlogged: bool, - pub east: bool, - pub north: bool, - pub south: bool, - pub west: bool, -} -impl IronBarsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for IronBarsData { - fn default() -> Self { - Self { - waterlogged: false, - east: false, - north: false, - south: false, - west: false, - } - } -} -impl Value for IronBarsData { - fn value(&self) -> usize { - (self.waterlogged.value() * 16usize) - + (self.east.value() * 8usize) - + (self.north.value() * 4usize) - + (self.south.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let waterlogged = bool::from_value(val / 16usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 16usize; - let east = bool::from_value(val / 8usize).unwrap(); - val -= (east.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let south = bool::from_value(val / 2usize).unwrap(); - val -= (south.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - east, - north, - south, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GlassPaneData { - pub east: bool, - pub waterlogged: bool, - pub south: bool, - pub west: bool, - pub north: bool, -} -impl GlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - south: bool::from_snake_case(map.get("south")?)?, - west: bool::from_snake_case(map.get("west")?)?, - north: bool::from_snake_case(map.get("north")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m - } -} -impl Default for GlassPaneData { - fn default() -> Self { - Self { - east: false, - waterlogged: false, - south: false, - west: false, - north: false, - } - } -} -impl Value for GlassPaneData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.south.value() * 4usize) - + (self.west.value() * 2usize) - + (self.north.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let south = bool::from_value(val / 4usize).unwrap(); - val -= (south.value() - 0usize) * 4usize; - let west = bool::from_value(val / 2usize).unwrap(); - val -= (west.value() - 0usize) * 2usize; - let north = bool::from_value(val / 1usize).unwrap(); - val -= (north.value() - 0usize) * 1usize; - Some(Self { - east, - waterlogged, - south, - west, - north, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AttachedPumpkinStemData { - pub facing: AttachedPumpkinStemFacing, -} -impl AttachedPumpkinStemData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: AttachedPumpkinStemFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for AttachedPumpkinStemData { - fn default() -> Self { - Self { - facing: AttachedPumpkinStemFacing::North, - } - } -} -impl Value for AttachedPumpkinStemData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = AttachedPumpkinStemFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AttachedMelonStemData { - pub facing: AttachedMelonStemFacing, -} -impl AttachedMelonStemData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: AttachedMelonStemFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for AttachedMelonStemData { - fn default() -> Self { - Self { - facing: AttachedMelonStemFacing::North, - } - } -} -impl Value for AttachedMelonStemData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = AttachedMelonStemFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PumpkinStemData { - pub age: i32, -} -impl PumpkinStemData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for PumpkinStemData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for PumpkinStemData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MelonStemData { - pub age: i32, -} -impl MelonStemData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for MelonStemData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for MelonStemData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct VineData { - pub up: bool, - pub north: bool, - pub east: bool, - pub west: bool, - pub south: bool, -} -impl VineData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - up: bool::from_snake_case(map.get("up")?)?, - north: bool::from_snake_case(map.get("north")?)?, - east: bool::from_snake_case(map.get("east")?)?, - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("up".to_string(), self.up.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m - } -} -impl Default for VineData { - fn default() -> Self { - Self { - up: false, - north: false, - east: false, - west: false, - south: false, - } - } -} -impl Value for VineData { - fn value(&self) -> usize { - (self.up.value() * 16usize) - + (self.north.value() * 8usize) - + (self.east.value() * 4usize) - + (self.west.value() * 2usize) - + (self.south.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let up = bool::from_value(val / 16usize).unwrap(); - val -= (up.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let east = bool::from_value(val / 4usize).unwrap(); - val -= (east.value() - 0usize) * 4usize; - let west = bool::from_value(val / 2usize).unwrap(); - val -= (west.value() - 0usize) * 2usize; - let south = bool::from_value(val / 1usize).unwrap(); - val -= (south.value() - 0usize) * 1usize; - Some(Self { - up, - north, - east, - west, - south, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakFenceGateData { - pub powered: bool, - pub open: bool, - pub in_wall: bool, - pub facing: OakFenceGateFacing, -} -impl OakFenceGateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - open: bool::from_snake_case(map.get("open")?)?, - in_wall: bool::from_snake_case(map.get("in_wall")?)?, - facing: OakFenceGateFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("in_wall".to_string(), self.in_wall.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for OakFenceGateData { - fn default() -> Self { - Self { - powered: false, - open: false, - in_wall: false, - facing: OakFenceGateFacing::North, - } - } -} -impl Value for OakFenceGateData { - fn value(&self) -> usize { - (self.powered.value() * 16usize) - + (self.open.value() * 8usize) - + (self.in_wall.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let powered = bool::from_value(val / 16usize).unwrap(); - val -= (powered.value() - 0usize) * 16usize; - let open = bool::from_value(val / 8usize).unwrap(); - val -= (open.value() - 0usize) * 8usize; - let in_wall = bool::from_value(val / 4usize).unwrap(); - val -= (in_wall.value() - 0usize) * 4usize; - let facing = OakFenceGateFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - powered, - open, - in_wall, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrickStairsData { - pub facing: BrickStairsFacing, - pub shape: BrickStairsShape, - pub waterlogged: bool, - pub half: BrickStairsHalf, -} -impl BrickStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BrickStairsFacing::from_snake_case(map.get("facing")?)?, - shape: BrickStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: BrickStairsHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for BrickStairsData { - fn default() -> Self { - Self { - facing: BrickStairsFacing::North, - shape: BrickStairsShape::Straight, - waterlogged: false, - half: BrickStairsHalf::Bottom, - } - } -} -impl Value for BrickStairsData { - fn value(&self) -> usize { - (self.facing.value() * 20usize) - + (self.shape.value() * 4usize) - + (self.waterlogged.value() * 2usize) - + (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let facing = BrickStairsFacing::from_value(val / 20usize).unwrap(); - val -= (facing.value() - 0usize) * 20usize; - let shape = BrickStairsShape::from_value(val / 4usize).unwrap(); - val -= (shape.value() - 0usize) * 4usize; - let waterlogged = bool::from_value(val / 2usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 2usize; - let half = BrickStairsHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { - facing, - shape, - waterlogged, - half, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StoneBrickStairsData { - pub waterlogged: bool, - pub half: StoneBrickStairsHalf, - pub facing: StoneBrickStairsFacing, - pub shape: StoneBrickStairsShape, -} -impl StoneBrickStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: StoneBrickStairsHalf::from_snake_case(map.get("half")?)?, - facing: StoneBrickStairsFacing::from_snake_case(map.get("facing")?)?, - shape: StoneBrickStairsShape::from_snake_case(map.get("shape")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m - } -} -impl Default for StoneBrickStairsData { - fn default() -> Self { - Self { - waterlogged: false, - half: StoneBrickStairsHalf::Bottom, - facing: StoneBrickStairsFacing::North, - shape: StoneBrickStairsShape::Straight, - } - } -} -impl Value for StoneBrickStairsData { - fn value(&self) -> usize { - (self.waterlogged.value() * 40usize) - + (self.half.value() * 20usize) - + (self.facing.value() * 5usize) - + (self.shape.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let waterlogged = bool::from_value(val / 40usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 40usize; - let half = StoneBrickStairsHalf::from_value(val / 20usize).unwrap(); - val -= (half.value() - 0usize) * 20usize; - let facing = StoneBrickStairsFacing::from_value(val / 5usize).unwrap(); - val -= (facing.value() - 0usize) * 5usize; - let shape = StoneBrickStairsShape::from_value(val / 1usize).unwrap(); - val -= (shape.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - half, - facing, - shape, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MyceliumData { - pub snowy: bool, -} -impl MyceliumData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - snowy: bool::from_snake_case(map.get("snowy")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("snowy".to_string(), self.snowy.to_snake_case()); - m - } -} -impl Default for MyceliumData { - fn default() -> Self { - Self { snowy: false } - } -} -impl Value for MyceliumData { - fn value(&self) -> usize { - (self.snowy.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let snowy = bool::from_value(val / 1usize).unwrap(); - val -= (snowy.value() - 0usize) * 1usize; - Some(Self { snowy }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct NetherBrickFenceData { - pub west: bool, - pub east: bool, - pub north: bool, - pub south: bool, - pub waterlogged: bool, -} -impl NetherBrickFenceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for NetherBrickFenceData { - fn default() -> Self { - Self { - west: false, - east: false, - north: false, - south: false, - waterlogged: false, - } - } -} -impl Value for NetherBrickFenceData { - fn value(&self) -> usize { - (self.west.value() * 16usize) - + (self.east.value() * 8usize) - + (self.north.value() * 4usize) - + (self.south.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let east = bool::from_value(val / 8usize).unwrap(); - val -= (east.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let south = bool::from_value(val / 2usize).unwrap(); - val -= (south.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - west, - east, - north, - south, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct NetherBrickStairsData { - pub half: NetherBrickStairsHalf, - pub facing: NetherBrickStairsFacing, - pub shape: NetherBrickStairsShape, - pub waterlogged: bool, -} -impl NetherBrickStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: NetherBrickStairsHalf::from_snake_case(map.get("half")?)?, - facing: NetherBrickStairsFacing::from_snake_case(map.get("facing")?)?, - shape: NetherBrickStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for NetherBrickStairsData { - fn default() -> Self { - Self { - half: NetherBrickStairsHalf::Bottom, - facing: NetherBrickStairsFacing::North, - shape: NetherBrickStairsShape::Straight, - waterlogged: false, - } - } -} -impl Value for NetherBrickStairsData { - fn value(&self) -> usize { - (self.half.value() * 40usize) - + (self.facing.value() * 10usize) - + (self.shape.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let half = NetherBrickStairsHalf::from_value(val / 40usize).unwrap(); - val -= (half.value() - 0usize) * 40usize; - let facing = NetherBrickStairsFacing::from_value(val / 10usize).unwrap(); - val -= (facing.value() - 0usize) * 10usize; - let shape = NetherBrickStairsShape::from_value(val / 2usize).unwrap(); - val -= (shape.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - half, - facing, - shape, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct NetherWartData { - pub age: i32, -} -impl NetherWartData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for NetherWartData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for NetherWartData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrewingStandData { - pub has_bottle_2: bool, - pub has_bottle_0: bool, - pub has_bottle_1: bool, -} -impl BrewingStandData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - has_bottle_2: bool::from_snake_case(map.get("has_bottle_2")?)?, - has_bottle_0: bool::from_snake_case(map.get("has_bottle_0")?)?, - has_bottle_1: bool::from_snake_case(map.get("has_bottle_1")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert( - "has_bottle_2".to_string(), - self.has_bottle_2.to_snake_case(), - ); - m.insert( - "has_bottle_0".to_string(), - self.has_bottle_0.to_snake_case(), - ); - m.insert( - "has_bottle_1".to_string(), - self.has_bottle_1.to_snake_case(), - ); - m - } -} -impl Default for BrewingStandData { - fn default() -> Self { - Self { - has_bottle_2: false, - has_bottle_0: false, - has_bottle_1: false, - } - } -} -impl Value for BrewingStandData { - fn value(&self) -> usize { - (self.has_bottle_2.value() * 4usize) - + (self.has_bottle_0.value() * 2usize) - + (self.has_bottle_1.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let has_bottle_2 = bool::from_value(val / 4usize).unwrap(); - val -= (has_bottle_2.value() - 0usize) * 4usize; - let has_bottle_0 = bool::from_value(val / 2usize).unwrap(); - val -= (has_bottle_0.value() - 0usize) * 2usize; - let has_bottle_1 = bool::from_value(val / 1usize).unwrap(); - val -= (has_bottle_1.value() - 0usize) * 1usize; - Some(Self { - has_bottle_2, - has_bottle_0, - has_bottle_1, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CauldronData { - pub level: i32, -} -impl CauldronData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - level: i32::from_snake_case(map.get("level")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("level".to_string(), self.level.to_snake_case()); - m - } -} -impl Default for CauldronData { - fn default() -> Self { - Self { level: 0 } - } -} -impl Value for CauldronData { - fn value(&self) -> usize { - (self.level.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let level = i32::from_value(val / 1usize).unwrap(); - val -= (level.value() - 0usize) * 1usize; - Some(Self { level }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct EndPortalFrameData { - pub eye: bool, - pub facing: EndPortalFrameFacing, -} -impl EndPortalFrameData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - eye: bool::from_snake_case(map.get("eye")?)?, - facing: EndPortalFrameFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("eye".to_string(), self.eye.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for EndPortalFrameData { - fn default() -> Self { - Self { - eye: false, - facing: EndPortalFrameFacing::North, - } - } -} -impl Value for EndPortalFrameData { - fn value(&self) -> usize { - (self.eye.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let eye = bool::from_value(val / 4usize).unwrap(); - val -= (eye.value() - 0usize) * 4usize; - let facing = EndPortalFrameFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { eye, facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedstoneLampData { - pub lit: bool, -} -impl RedstoneLampData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - lit: bool::from_snake_case(map.get("lit")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("lit".to_string(), self.lit.to_snake_case()); - m - } -} -impl Default for RedstoneLampData { - fn default() -> Self { - Self { lit: false } - } -} -impl Value for RedstoneLampData { - fn value(&self) -> usize { - (self.lit.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let lit = bool::from_value(val / 1usize).unwrap(); - val -= (lit.value() - 0usize) * 1usize; - Some(Self { lit }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CocoaData { - pub age: i32, - pub facing: CocoaFacing, -} -impl CocoaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - facing: CocoaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for CocoaData { - fn default() -> Self { - Self { - age: 0, - facing: CocoaFacing::North, - } - } -} -impl Value for CocoaData { - fn value(&self) -> usize { - (self.age.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let age = i32::from_value(val / 4usize).unwrap(); - val -= (age.value() - 0usize) * 4usize; - let facing = CocoaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { age, facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SandstoneStairsData { - pub half: SandstoneStairsHalf, - pub shape: SandstoneStairsShape, - pub waterlogged: bool, - pub facing: SandstoneStairsFacing, -} -impl SandstoneStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: SandstoneStairsHalf::from_snake_case(map.get("half")?)?, - shape: SandstoneStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: SandstoneStairsFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for SandstoneStairsData { - fn default() -> Self { - Self { - half: SandstoneStairsHalf::Bottom, - shape: SandstoneStairsShape::Straight, - waterlogged: false, - facing: SandstoneStairsFacing::North, - } - } -} -impl Value for SandstoneStairsData { - fn value(&self) -> usize { - (self.half.value() * 40usize) - + (self.shape.value() * 8usize) - + (self.waterlogged.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let half = SandstoneStairsHalf::from_value(val / 40usize).unwrap(); - val -= (half.value() - 0usize) * 40usize; - let shape = SandstoneStairsShape::from_value(val / 8usize).unwrap(); - val -= (shape.value() - 0usize) * 8usize; - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = SandstoneStairsFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - half, - shape, - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct EnderChestData { - pub waterlogged: bool, - pub facing: EnderChestFacing, -} -impl EnderChestData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: EnderChestFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for EnderChestData { - fn default() -> Self { - Self { - waterlogged: false, - facing: EnderChestFacing::North, - } - } -} -impl Value for EnderChestData { - fn value(&self) -> usize { - (self.waterlogged.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = EnderChestFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TripwireHookData { - pub powered: bool, - pub attached: bool, - pub facing: TripwireHookFacing, -} -impl TripwireHookData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - attached: bool::from_snake_case(map.get("attached")?)?, - facing: TripwireHookFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("attached".to_string(), self.attached.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for TripwireHookData { - fn default() -> Self { - Self { - powered: false, - attached: false, - facing: TripwireHookFacing::North, - } - } -} -impl Value for TripwireHookData { - fn value(&self) -> usize { - (self.powered.value() * 8usize) - + (self.attached.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let powered = bool::from_value(val / 8usize).unwrap(); - val -= (powered.value() - 0usize) * 8usize; - let attached = bool::from_value(val / 4usize).unwrap(); - val -= (attached.value() - 0usize) * 4usize; - let facing = TripwireHookFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - powered, - attached, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TripwireData { - pub west: bool, - pub disarmed: bool, - pub east: bool, - pub attached: bool, - pub north: bool, - pub powered: bool, - pub south: bool, -} -impl TripwireData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - disarmed: bool::from_snake_case(map.get("disarmed")?)?, - east: bool::from_snake_case(map.get("east")?)?, - attached: bool::from_snake_case(map.get("attached")?)?, - north: bool::from_snake_case(map.get("north")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - south: bool::from_snake_case(map.get("south")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("disarmed".to_string(), self.disarmed.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("attached".to_string(), self.attached.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m - } -} -impl Default for TripwireData { - fn default() -> Self { - Self { - west: false, - disarmed: false, - east: false, - attached: false, - north: false, - powered: false, - south: false, - } - } -} -impl Value for TripwireData { - fn value(&self) -> usize { - (self.west.value() * 64usize) - + (self.disarmed.value() * 32usize) - + (self.east.value() * 16usize) - + (self.attached.value() * 8usize) - + (self.north.value() * 4usize) - + (self.powered.value() * 2usize) - + (self.south.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 128usize { - return None; - } - let west = bool::from_value(val / 64usize).unwrap(); - val -= (west.value() - 0usize) * 64usize; - let disarmed = bool::from_value(val / 32usize).unwrap(); - val -= (disarmed.value() - 0usize) * 32usize; - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let attached = bool::from_value(val / 8usize).unwrap(); - val -= (attached.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let powered = bool::from_value(val / 2usize).unwrap(); - val -= (powered.value() - 0usize) * 2usize; - let south = bool::from_value(val / 1usize).unwrap(); - val -= (south.value() - 0usize) * 1usize; - Some(Self { - west, - disarmed, - east, - attached, - north, - powered, - south, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceStairsData { - pub half: SpruceStairsHalf, - pub shape: SpruceStairsShape, - pub facing: SpruceStairsFacing, - pub waterlogged: bool, -} -impl SpruceStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: SpruceStairsHalf::from_snake_case(map.get("half")?)?, - shape: SpruceStairsShape::from_snake_case(map.get("shape")?)?, - facing: SpruceStairsFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for SpruceStairsData { - fn default() -> Self { - Self { - half: SpruceStairsHalf::Bottom, - shape: SpruceStairsShape::Straight, - facing: SpruceStairsFacing::North, - waterlogged: false, - } - } -} -impl Value for SpruceStairsData { - fn value(&self) -> usize { - (self.half.value() * 40usize) - + (self.shape.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let half = SpruceStairsHalf::from_value(val / 40usize).unwrap(); - val -= (half.value() - 0usize) * 40usize; - let shape = SpruceStairsShape::from_value(val / 8usize).unwrap(); - val -= (shape.value() - 0usize) * 8usize; - let facing = SpruceStairsFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - half, - shape, - facing, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchStairsData { - pub facing: BirchStairsFacing, - pub shape: BirchStairsShape, - pub waterlogged: bool, - pub half: BirchStairsHalf, -} -impl BirchStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BirchStairsFacing::from_snake_case(map.get("facing")?)?, - shape: BirchStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: BirchStairsHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for BirchStairsData { - fn default() -> Self { - Self { - facing: BirchStairsFacing::North, - shape: BirchStairsShape::Straight, - waterlogged: false, - half: BirchStairsHalf::Bottom, - } - } -} -impl Value for BirchStairsData { - fn value(&self) -> usize { - (self.facing.value() * 20usize) - + (self.shape.value() * 4usize) - + (self.waterlogged.value() * 2usize) - + (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let facing = BirchStairsFacing::from_value(val / 20usize).unwrap(); - val -= (facing.value() - 0usize) * 20usize; - let shape = BirchStairsShape::from_value(val / 4usize).unwrap(); - val -= (shape.value() - 0usize) * 4usize; - let waterlogged = bool::from_value(val / 2usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 2usize; - let half = BirchStairsHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { - facing, - shape, - waterlogged, - half, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleStairsData { - pub facing: JungleStairsFacing, - pub waterlogged: bool, - pub shape: JungleStairsShape, - pub half: JungleStairsHalf, -} -impl JungleStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: JungleStairsFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - shape: JungleStairsShape::from_snake_case(map.get("shape")?)?, - half: JungleStairsHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for JungleStairsData { - fn default() -> Self { - Self { - facing: JungleStairsFacing::North, - waterlogged: false, - shape: JungleStairsShape::Straight, - half: JungleStairsHalf::Bottom, - } - } -} -impl Value for JungleStairsData { - fn value(&self) -> usize { - (self.facing.value() * 20usize) - + (self.waterlogged.value() * 10usize) - + (self.shape.value() * 2usize) - + (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let facing = JungleStairsFacing::from_value(val / 20usize).unwrap(); - val -= (facing.value() - 0usize) * 20usize; - let waterlogged = bool::from_value(val / 10usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 10usize; - let shape = JungleStairsShape::from_value(val / 2usize).unwrap(); - val -= (shape.value() - 0usize) * 2usize; - let half = JungleStairsHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { - facing, - waterlogged, - shape, - half, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CommandBlockData { - pub conditional: bool, - pub facing: CommandBlockFacing, -} -impl CommandBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - conditional: bool::from_snake_case(map.get("conditional")?)?, - facing: CommandBlockFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("conditional".to_string(), self.conditional.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for CommandBlockData { - fn default() -> Self { - Self { - conditional: false, - facing: CommandBlockFacing::North, - } - } -} -impl Value for CommandBlockData { - fn value(&self) -> usize { - (self.conditional.value() * 6usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let conditional = bool::from_value(val / 6usize).unwrap(); - val -= (conditional.value() - 0usize) * 6usize; - let facing = CommandBlockFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - conditional, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CobblestoneWallData { - pub south: bool, - pub west: bool, - pub north: bool, - pub east: bool, - pub up: bool, - pub waterlogged: bool, -} -impl CobblestoneWallData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - south: bool::from_snake_case(map.get("south")?)?, - west: bool::from_snake_case(map.get("west")?)?, - north: bool::from_snake_case(map.get("north")?)?, - east: bool::from_snake_case(map.get("east")?)?, - up: bool::from_snake_case(map.get("up")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("up".to_string(), self.up.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for CobblestoneWallData { - fn default() -> Self { - Self { - south: false, - west: false, - north: false, - east: false, - up: true, - waterlogged: false, - } - } -} -impl Value for CobblestoneWallData { - fn value(&self) -> usize { - (self.south.value() * 32usize) - + (self.west.value() * 16usize) - + (self.north.value() * 8usize) - + (self.east.value() * 4usize) - + (self.up.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let south = bool::from_value(val / 32usize).unwrap(); - val -= (south.value() - 0usize) * 32usize; - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let east = bool::from_value(val / 4usize).unwrap(); - val -= (east.value() - 0usize) * 4usize; - let up = bool::from_value(val / 2usize).unwrap(); - val -= (up.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - south, - west, - north, - east, - up, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MossyCobblestoneWallData { - pub up: bool, - pub west: bool, - pub east: bool, - pub north: bool, - pub south: bool, - pub waterlogged: bool, -} -impl MossyCobblestoneWallData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - up: bool::from_snake_case(map.get("up")?)?, - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("up".to_string(), self.up.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for MossyCobblestoneWallData { - fn default() -> Self { - Self { - up: true, - west: false, - east: false, - north: false, - south: false, - waterlogged: false, - } - } -} -impl Value for MossyCobblestoneWallData { - fn value(&self) -> usize { - (self.up.value() * 32usize) - + (self.west.value() * 16usize) - + (self.east.value() * 8usize) - + (self.north.value() * 4usize) - + (self.south.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let up = bool::from_value(val / 32usize).unwrap(); - val -= (up.value() - 0usize) * 32usize; - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let east = bool::from_value(val / 8usize).unwrap(); - val -= (east.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let south = bool::from_value(val / 2usize).unwrap(); - val -= (south.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - up, - west, - east, - north, - south, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CarrotsData { - pub age: i32, -} -impl CarrotsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for CarrotsData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for CarrotsData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PotatoesData { - pub age: i32, -} -impl PotatoesData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for PotatoesData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for PotatoesData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakButtonData { - pub face: OakButtonFace, - pub facing: OakButtonFacing, - pub powered: bool, -} -impl OakButtonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - face: OakButtonFace::from_snake_case(map.get("face")?)?, - facing: OakButtonFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("face".to_string(), self.face.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for OakButtonData { - fn default() -> Self { - Self { - face: OakButtonFace::Wall, - facing: OakButtonFacing::North, - powered: false, - } - } -} -impl Value for OakButtonData { - fn value(&self) -> usize { - (self.face.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let face = OakButtonFace::from_value(val / 8usize).unwrap(); - val -= (face.value() - 0usize) * 8usize; - let facing = OakButtonFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - face, - facing, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceButtonData { - pub powered: bool, - pub face: SpruceButtonFace, - pub facing: SpruceButtonFacing, -} -impl SpruceButtonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - face: SpruceButtonFace::from_snake_case(map.get("face")?)?, - facing: SpruceButtonFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("face".to_string(), self.face.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for SpruceButtonData { - fn default() -> Self { - Self { - powered: false, - face: SpruceButtonFace::Wall, - facing: SpruceButtonFacing::North, - } - } -} -impl Value for SpruceButtonData { - fn value(&self) -> usize { - (self.powered.value() * 12usize) - + (self.face.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let powered = bool::from_value(val / 12usize).unwrap(); - val -= (powered.value() - 0usize) * 12usize; - let face = SpruceButtonFace::from_value(val / 4usize).unwrap(); - val -= (face.value() - 0usize) * 4usize; - let facing = SpruceButtonFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - powered, - face, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchButtonData { - pub facing: BirchButtonFacing, - pub powered: bool, - pub face: BirchButtonFace, -} -impl BirchButtonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BirchButtonFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - face: BirchButtonFace::from_snake_case(map.get("face")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("face".to_string(), self.face.to_snake_case()); - m - } -} -impl Default for BirchButtonData { - fn default() -> Self { - Self { - facing: BirchButtonFacing::North, - powered: false, - face: BirchButtonFace::Wall, - } - } -} -impl Value for BirchButtonData { - fn value(&self) -> usize { - (self.facing.value() * 6usize) - + (self.powered.value() * 3usize) - + (self.face.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let facing = BirchButtonFacing::from_value(val / 6usize).unwrap(); - val -= (facing.value() - 0usize) * 6usize; - let powered = bool::from_value(val / 3usize).unwrap(); - val -= (powered.value() - 0usize) * 3usize; - let face = BirchButtonFace::from_value(val / 1usize).unwrap(); - val -= (face.value() - 0usize) * 1usize; - Some(Self { - facing, - powered, - face, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleButtonData { - pub facing: JungleButtonFacing, - pub face: JungleButtonFace, - pub powered: bool, -} -impl JungleButtonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: JungleButtonFacing::from_snake_case(map.get("facing")?)?, - face: JungleButtonFace::from_snake_case(map.get("face")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("face".to_string(), self.face.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for JungleButtonData { - fn default() -> Self { - Self { - facing: JungleButtonFacing::North, - face: JungleButtonFace::Wall, - powered: false, - } - } -} -impl Value for JungleButtonData { - fn value(&self) -> usize { - (self.facing.value() * 6usize) - + (self.face.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let facing = JungleButtonFacing::from_value(val / 6usize).unwrap(); - val -= (facing.value() - 0usize) * 6usize; - let face = JungleButtonFace::from_value(val / 2usize).unwrap(); - val -= (face.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - facing, - face, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaButtonData { - pub face: AcaciaButtonFace, - pub powered: bool, - pub facing: AcaciaButtonFacing, -} -impl AcaciaButtonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - face: AcaciaButtonFace::from_snake_case(map.get("face")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - facing: AcaciaButtonFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("face".to_string(), self.face.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for AcaciaButtonData { - fn default() -> Self { - Self { - face: AcaciaButtonFace::Wall, - powered: false, - facing: AcaciaButtonFacing::North, - } - } -} -impl Value for AcaciaButtonData { - fn value(&self) -> usize { - (self.face.value() * 8usize) - + (self.powered.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let face = AcaciaButtonFace::from_value(val / 8usize).unwrap(); - val -= (face.value() - 0usize) * 8usize; - let powered = bool::from_value(val / 4usize).unwrap(); - val -= (powered.value() - 0usize) * 4usize; - let facing = AcaciaButtonFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - face, - powered, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakButtonData { - pub face: DarkOakButtonFace, - pub powered: bool, - pub facing: DarkOakButtonFacing, -} -impl DarkOakButtonData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - face: DarkOakButtonFace::from_snake_case(map.get("face")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - facing: DarkOakButtonFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("face".to_string(), self.face.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for DarkOakButtonData { - fn default() -> Self { - Self { - face: DarkOakButtonFace::Wall, - powered: false, - facing: DarkOakButtonFacing::North, - } - } -} -impl Value for DarkOakButtonData { - fn value(&self) -> usize { - (self.face.value() * 8usize) - + (self.powered.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let face = DarkOakButtonFace::from_value(val / 8usize).unwrap(); - val -= (face.value() - 0usize) * 8usize; - let powered = bool::from_value(val / 4usize).unwrap(); - val -= (powered.value() - 0usize) * 4usize; - let facing = DarkOakButtonFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - face, - powered, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SkeletonWallSkullData { - pub facing: SkeletonWallSkullFacing, -} -impl SkeletonWallSkullData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: SkeletonWallSkullFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for SkeletonWallSkullData { - fn default() -> Self { - Self { - facing: SkeletonWallSkullFacing::North, - } - } -} -impl Value for SkeletonWallSkullData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = SkeletonWallSkullFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SkeletonSkullData { - pub rotation: i32, -} -impl SkeletonSkullData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for SkeletonSkullData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for SkeletonSkullData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WitherSkeletonWallSkullData { - pub facing: WitherSkeletonWallSkullFacing, -} -impl WitherSkeletonWallSkullData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: WitherSkeletonWallSkullFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for WitherSkeletonWallSkullData { - fn default() -> Self { - Self { - facing: WitherSkeletonWallSkullFacing::North, - } - } -} -impl Value for WitherSkeletonWallSkullData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = WitherSkeletonWallSkullFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WitherSkeletonSkullData { - pub rotation: i32, -} -impl WitherSkeletonSkullData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for WitherSkeletonSkullData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for WitherSkeletonSkullData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ZombieWallHeadData { - pub facing: ZombieWallHeadFacing, -} -impl ZombieWallHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: ZombieWallHeadFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for ZombieWallHeadData { - fn default() -> Self { - Self { - facing: ZombieWallHeadFacing::North, - } - } -} -impl Value for ZombieWallHeadData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = ZombieWallHeadFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ZombieHeadData { - pub rotation: i32, -} -impl ZombieHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for ZombieHeadData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for ZombieHeadData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PlayerWallHeadData { - pub facing: PlayerWallHeadFacing, -} -impl PlayerWallHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: PlayerWallHeadFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PlayerWallHeadData { - fn default() -> Self { - Self { - facing: PlayerWallHeadFacing::North, - } - } -} -impl Value for PlayerWallHeadData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = PlayerWallHeadFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PlayerHeadData { - pub rotation: i32, -} -impl PlayerHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for PlayerHeadData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for PlayerHeadData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CreeperWallHeadData { - pub facing: CreeperWallHeadFacing, -} -impl CreeperWallHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: CreeperWallHeadFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for CreeperWallHeadData { - fn default() -> Self { - Self { - facing: CreeperWallHeadFacing::North, - } - } -} -impl Value for CreeperWallHeadData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = CreeperWallHeadFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CreeperHeadData { - pub rotation: i32, -} -impl CreeperHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for CreeperHeadData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for CreeperHeadData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DragonWallHeadData { - pub facing: DragonWallHeadFacing, -} -impl DragonWallHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: DragonWallHeadFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for DragonWallHeadData { - fn default() -> Self { - Self { - facing: DragonWallHeadFacing::North, - } - } -} -impl Value for DragonWallHeadData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = DragonWallHeadFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DragonHeadData { - pub rotation: i32, -} -impl DragonHeadData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for DragonHeadData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for DragonHeadData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AnvilData { - pub facing: AnvilFacing, -} -impl AnvilData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: AnvilFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for AnvilData { - fn default() -> Self { - Self { - facing: AnvilFacing::North, - } - } -} -impl Value for AnvilData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = AnvilFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ChippedAnvilData { - pub facing: ChippedAnvilFacing, -} -impl ChippedAnvilData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: ChippedAnvilFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for ChippedAnvilData { - fn default() -> Self { - Self { - facing: ChippedAnvilFacing::North, - } - } -} -impl Value for ChippedAnvilData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = ChippedAnvilFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DamagedAnvilData { - pub facing: DamagedAnvilFacing, -} -impl DamagedAnvilData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: DamagedAnvilFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for DamagedAnvilData { - fn default() -> Self { - Self { - facing: DamagedAnvilFacing::North, - } - } -} -impl Value for DamagedAnvilData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = DamagedAnvilFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TrappedChestData { - pub ty: TrappedChestType, - pub waterlogged: bool, - pub facing: TrappedChestFacing, -} -impl TrappedChestData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: TrappedChestType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: TrappedChestFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for TrappedChestData { - fn default() -> Self { - Self { - ty: TrappedChestType::Single, - waterlogged: false, - facing: TrappedChestFacing::North, - } - } -} -impl Value for TrappedChestData { - fn value(&self) -> usize { - (self.ty.value() * 8usize) - + (self.waterlogged.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 24usize { - return None; - } - let ty = TrappedChestType::from_value(val / 8usize).unwrap(); - val -= (ty.value() - 0usize) * 8usize; - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = TrappedChestFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - ty, - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightWeightedPressurePlateData { - pub power: i32, -} -impl LightWeightedPressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - power: i32::from_snake_case(map.get("power")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("power".to_string(), self.power.to_snake_case()); - m - } -} -impl Default for LightWeightedPressurePlateData { - fn default() -> Self { - Self { power: 0 } - } -} -impl Value for LightWeightedPressurePlateData { - fn value(&self) -> usize { - (self.power.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let power = i32::from_value(val / 1usize).unwrap(); - val -= (power.value() - 0usize) * 1usize; - Some(Self { power }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct HeavyWeightedPressurePlateData { - pub power: i32, -} -impl HeavyWeightedPressurePlateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - power: i32::from_snake_case(map.get("power")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("power".to_string(), self.power.to_snake_case()); - m - } -} -impl Default for HeavyWeightedPressurePlateData { - fn default() -> Self { - Self { power: 0 } - } -} -impl Value for HeavyWeightedPressurePlateData { - fn value(&self) -> usize { - (self.power.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let power = i32::from_value(val / 1usize).unwrap(); - val -= (power.value() - 0usize) * 1usize; - Some(Self { power }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ComparatorData { - pub mode: ComparatorMode, - pub facing: ComparatorFacing, - pub powered: bool, -} -impl ComparatorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - mode: ComparatorMode::from_snake_case(map.get("mode")?)?, - facing: ComparatorFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("mode".to_string(), self.mode.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for ComparatorData { - fn default() -> Self { - Self { - mode: ComparatorMode::Compare, - facing: ComparatorFacing::North, - powered: false, - } - } -} -impl Value for ComparatorData { - fn value(&self) -> usize { - (self.mode.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let mode = ComparatorMode::from_value(val / 8usize).unwrap(); - val -= (mode.value() - 0usize) * 8usize; - let facing = ComparatorFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - mode, - facing, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DaylightDetectorData { - pub inverted: bool, - pub power: i32, -} -impl DaylightDetectorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - inverted: bool::from_snake_case(map.get("inverted")?)?, - power: i32::from_snake_case(map.get("power")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("inverted".to_string(), self.inverted.to_snake_case()); - m.insert("power".to_string(), self.power.to_snake_case()); - m - } -} -impl Default for DaylightDetectorData { - fn default() -> Self { - Self { - inverted: false, - power: 0, - } - } -} -impl Value for DaylightDetectorData { - fn value(&self) -> usize { - (self.inverted.value() * 16usize) + (self.power.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let inverted = bool::from_value(val / 16usize).unwrap(); - val -= (inverted.value() - 0usize) * 16usize; - let power = i32::from_value(val / 1usize).unwrap(); - val -= (power.value() - 0usize) * 1usize; - Some(Self { inverted, power }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct HopperData { - pub enabled: bool, - pub facing: HopperFacing, -} -impl HopperData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - enabled: bool::from_snake_case(map.get("enabled")?)?, - facing: HopperFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("enabled".to_string(), self.enabled.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for HopperData { - fn default() -> Self { - Self { - enabled: true, - facing: HopperFacing::Down, - } - } -} -impl Value for HopperData { - fn value(&self) -> usize { - (self.enabled.value() * 5usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 10usize { - return None; - } - let enabled = bool::from_value(val / 5usize).unwrap(); - val -= (enabled.value() - 0usize) * 5usize; - let facing = HopperFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { enabled, facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct QuartzPillarData { - pub axis: QuartzPillarAxis, -} -impl QuartzPillarData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: QuartzPillarAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for QuartzPillarData { - fn default() -> Self { - Self { - axis: QuartzPillarAxis::Y, - } - } -} -impl Value for QuartzPillarData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = QuartzPillarAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct QuartzStairsData { - pub facing: QuartzStairsFacing, - pub waterlogged: bool, - pub half: QuartzStairsHalf, - pub shape: QuartzStairsShape, -} -impl QuartzStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: QuartzStairsFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: QuartzStairsHalf::from_snake_case(map.get("half")?)?, - shape: QuartzStairsShape::from_snake_case(map.get("shape")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m - } -} -impl Default for QuartzStairsData { - fn default() -> Self { - Self { - facing: QuartzStairsFacing::North, - waterlogged: false, - half: QuartzStairsHalf::Bottom, - shape: QuartzStairsShape::Straight, - } - } -} -impl Value for QuartzStairsData { - fn value(&self) -> usize { - (self.facing.value() * 20usize) - + (self.waterlogged.value() * 10usize) - + (self.half.value() * 5usize) - + (self.shape.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let facing = QuartzStairsFacing::from_value(val / 20usize).unwrap(); - val -= (facing.value() - 0usize) * 20usize; - let waterlogged = bool::from_value(val / 10usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 10usize; - let half = QuartzStairsHalf::from_value(val / 5usize).unwrap(); - val -= (half.value() - 0usize) * 5usize; - let shape = QuartzStairsShape::from_value(val / 1usize).unwrap(); - val -= (shape.value() - 0usize) * 1usize; - Some(Self { - facing, - waterlogged, - half, - shape, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ActivatorRailData { - pub powered: bool, - pub shape: ActivatorRailShape, -} -impl ActivatorRailData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - shape: ActivatorRailShape::from_snake_case(map.get("shape")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m - } -} -impl Default for ActivatorRailData { - fn default() -> Self { - Self { - powered: false, - shape: ActivatorRailShape::NorthSouth, - } - } -} -impl Value for ActivatorRailData { - fn value(&self) -> usize { - (self.powered.value() * 6usize) + (self.shape.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let powered = bool::from_value(val / 6usize).unwrap(); - val -= (powered.value() - 0usize) * 6usize; - let shape = ActivatorRailShape::from_value(val / 1usize).unwrap(); - val -= (shape.value() - 0usize) * 1usize; - Some(Self { powered, shape }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DropperData { - pub facing: DropperFacing, - pub triggered: bool, -} -impl DropperData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: DropperFacing::from_snake_case(map.get("facing")?)?, - triggered: bool::from_snake_case(map.get("triggered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("triggered".to_string(), self.triggered.to_snake_case()); - m - } -} -impl Default for DropperData { - fn default() -> Self { - Self { - facing: DropperFacing::North, - triggered: false, - } - } -} -impl Value for DropperData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.triggered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let facing = DropperFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let triggered = bool::from_value(val / 1usize).unwrap(); - val -= (triggered.value() - 0usize) * 1usize; - Some(Self { facing, triggered }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WhiteStainedGlassPaneData { - pub waterlogged: bool, - pub west: bool, - pub south: bool, - pub east: bool, - pub north: bool, -} -impl WhiteStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m - } -} -impl Default for WhiteStainedGlassPaneData { - fn default() -> Self { - Self { - waterlogged: false, - west: false, - south: false, - east: false, - north: false, - } - } -} -impl Value for WhiteStainedGlassPaneData { - fn value(&self) -> usize { - (self.waterlogged.value() * 16usize) - + (self.west.value() * 8usize) - + (self.south.value() * 4usize) - + (self.east.value() * 2usize) - + (self.north.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let waterlogged = bool::from_value(val / 16usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 16usize; - let west = bool::from_value(val / 8usize).unwrap(); - val -= (west.value() - 0usize) * 8usize; - let south = bool::from_value(val / 4usize).unwrap(); - val -= (south.value() - 0usize) * 4usize; - let east = bool::from_value(val / 2usize).unwrap(); - val -= (east.value() - 0usize) * 2usize; - let north = bool::from_value(val / 1usize).unwrap(); - val -= (north.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - west, - south, - east, - north, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OrangeStainedGlassPaneData { - pub east: bool, - pub south: bool, - pub north: bool, - pub waterlogged: bool, - pub west: bool, -} -impl OrangeStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - south: bool::from_snake_case(map.get("south")?)?, - north: bool::from_snake_case(map.get("north")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for OrangeStainedGlassPaneData { - fn default() -> Self { - Self { - east: false, - south: false, - north: false, - waterlogged: false, - west: false, - } - } -} -impl Value for OrangeStainedGlassPaneData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.south.value() * 8usize) - + (self.north.value() * 4usize) - + (self.waterlogged.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let south = bool::from_value(val / 8usize).unwrap(); - val -= (south.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let waterlogged = bool::from_value(val / 2usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - east, - south, - north, - waterlogged, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MagentaStainedGlassPaneData { - pub west: bool, - pub north: bool, - pub south: bool, - pub east: bool, - pub waterlogged: bool, -} -impl MagentaStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - east: bool::from_snake_case(map.get("east")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for MagentaStainedGlassPaneData { - fn default() -> Self { - Self { - west: false, - north: false, - south: false, - east: false, - waterlogged: false, - } - } -} -impl Value for MagentaStainedGlassPaneData { - fn value(&self) -> usize { - (self.west.value() * 16usize) - + (self.north.value() * 8usize) - + (self.south.value() * 4usize) - + (self.east.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let south = bool::from_value(val / 4usize).unwrap(); - val -= (south.value() - 0usize) * 4usize; - let east = bool::from_value(val / 2usize).unwrap(); - val -= (east.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - west, - north, - south, - east, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightBlueStainedGlassPaneData { - pub south: bool, - pub waterlogged: bool, - pub east: bool, - pub north: bool, - pub west: bool, -} -impl LightBlueStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for LightBlueStainedGlassPaneData { - fn default() -> Self { - Self { - south: false, - waterlogged: false, - east: false, - north: false, - west: false, - } - } -} -impl Value for LightBlueStainedGlassPaneData { - fn value(&self) -> usize { - (self.south.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.east.value() * 4usize) - + (self.north.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let south = bool::from_value(val / 16usize).unwrap(); - val -= (south.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let east = bool::from_value(val / 4usize).unwrap(); - val -= (east.value() - 0usize) * 4usize; - let north = bool::from_value(val / 2usize).unwrap(); - val -= (north.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - south, - waterlogged, - east, - north, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct YellowStainedGlassPaneData { - pub east: bool, - pub waterlogged: bool, - pub north: bool, - pub south: bool, - pub west: bool, -} -impl YellowStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for YellowStainedGlassPaneData { - fn default() -> Self { - Self { - east: false, - waterlogged: false, - north: false, - south: false, - west: false, - } - } -} -impl Value for YellowStainedGlassPaneData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.north.value() * 4usize) - + (self.south.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let south = bool::from_value(val / 2usize).unwrap(); - val -= (south.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - east, - waterlogged, - north, - south, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LimeStainedGlassPaneData { - pub east: bool, - pub south: bool, - pub north: bool, - pub west: bool, - pub waterlogged: bool, -} -impl LimeStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - south: bool::from_snake_case(map.get("south")?)?, - north: bool::from_snake_case(map.get("north")?)?, - west: bool::from_snake_case(map.get("west")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for LimeStainedGlassPaneData { - fn default() -> Self { - Self { - east: false, - south: false, - north: false, - west: false, - waterlogged: false, - } - } -} -impl Value for LimeStainedGlassPaneData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.south.value() * 8usize) - + (self.north.value() * 4usize) - + (self.west.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let south = bool::from_value(val / 8usize).unwrap(); - val -= (south.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let west = bool::from_value(val / 2usize).unwrap(); - val -= (west.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - east, - south, - north, - west, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PinkStainedGlassPaneData { - pub west: bool, - pub east: bool, - pub south: bool, - pub waterlogged: bool, - pub north: bool, -} -impl PinkStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - north: bool::from_snake_case(map.get("north")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m - } -} -impl Default for PinkStainedGlassPaneData { - fn default() -> Self { - Self { - west: false, - east: false, - south: false, - waterlogged: false, - north: false, - } - } -} -impl Value for PinkStainedGlassPaneData { - fn value(&self) -> usize { - (self.west.value() * 16usize) - + (self.east.value() * 8usize) - + (self.south.value() * 4usize) - + (self.waterlogged.value() * 2usize) - + (self.north.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let east = bool::from_value(val / 8usize).unwrap(); - val -= (east.value() - 0usize) * 8usize; - let south = bool::from_value(val / 4usize).unwrap(); - val -= (south.value() - 0usize) * 4usize; - let waterlogged = bool::from_value(val / 2usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 2usize; - let north = bool::from_value(val / 1usize).unwrap(); - val -= (north.value() - 0usize) * 1usize; - Some(Self { - west, - east, - south, - waterlogged, - north, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GrayStainedGlassPaneData { - pub east: bool, - pub north: bool, - pub south: bool, - pub waterlogged: bool, - pub west: bool, -} -impl GrayStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for GrayStainedGlassPaneData { - fn default() -> Self { - Self { - east: false, - north: false, - south: false, - waterlogged: false, - west: false, - } - } -} -impl Value for GrayStainedGlassPaneData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.north.value() * 8usize) - + (self.south.value() * 4usize) - + (self.waterlogged.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let south = bool::from_value(val / 4usize).unwrap(); - val -= (south.value() - 0usize) * 4usize; - let waterlogged = bool::from_value(val / 2usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - east, - north, - south, - waterlogged, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightGrayStainedGlassPaneData { - pub south: bool, - pub waterlogged: bool, - pub north: bool, - pub west: bool, - pub east: bool, -} -impl LightGrayStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - north: bool::from_snake_case(map.get("north")?)?, - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m - } -} -impl Default for LightGrayStainedGlassPaneData { - fn default() -> Self { - Self { - south: false, - waterlogged: false, - north: false, - west: false, - east: false, - } - } -} -impl Value for LightGrayStainedGlassPaneData { - fn value(&self) -> usize { - (self.south.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.north.value() * 4usize) - + (self.west.value() * 2usize) - + (self.east.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let south = bool::from_value(val / 16usize).unwrap(); - val -= (south.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let west = bool::from_value(val / 2usize).unwrap(); - val -= (west.value() - 0usize) * 2usize; - let east = bool::from_value(val / 1usize).unwrap(); - val -= (east.value() - 0usize) * 1usize; - Some(Self { - south, - waterlogged, - north, - west, - east, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CyanStainedGlassPaneData { - pub east: bool, - pub north: bool, - pub south: bool, - pub waterlogged: bool, - pub west: bool, -} -impl CyanStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for CyanStainedGlassPaneData { - fn default() -> Self { - Self { - east: false, - north: false, - south: false, - waterlogged: false, - west: false, - } - } -} -impl Value for CyanStainedGlassPaneData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.north.value() * 8usize) - + (self.south.value() * 4usize) - + (self.waterlogged.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let south = bool::from_value(val / 4usize).unwrap(); - val -= (south.value() - 0usize) * 4usize; - let waterlogged = bool::from_value(val / 2usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - east, - north, - south, - waterlogged, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpleStainedGlassPaneData { - pub west: bool, - pub south: bool, - pub north: bool, - pub east: bool, - pub waterlogged: bool, -} -impl PurpleStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - north: bool::from_snake_case(map.get("north")?)?, - east: bool::from_snake_case(map.get("east")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for PurpleStainedGlassPaneData { - fn default() -> Self { - Self { - west: false, - south: false, - north: false, - east: false, - waterlogged: false, - } - } -} -impl Value for PurpleStainedGlassPaneData { - fn value(&self) -> usize { - (self.west.value() * 16usize) - + (self.south.value() * 8usize) - + (self.north.value() * 4usize) - + (self.east.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let south = bool::from_value(val / 8usize).unwrap(); - val -= (south.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let east = bool::from_value(val / 2usize).unwrap(); - val -= (east.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - west, - south, - north, - east, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlueStainedGlassPaneData { - pub waterlogged: bool, - pub west: bool, - pub south: bool, - pub east: bool, - pub north: bool, -} -impl BlueStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m - } -} -impl Default for BlueStainedGlassPaneData { - fn default() -> Self { - Self { - waterlogged: false, - west: false, - south: false, - east: false, - north: false, - } - } -} -impl Value for BlueStainedGlassPaneData { - fn value(&self) -> usize { - (self.waterlogged.value() * 16usize) - + (self.west.value() * 8usize) - + (self.south.value() * 4usize) - + (self.east.value() * 2usize) - + (self.north.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let waterlogged = bool::from_value(val / 16usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 16usize; - let west = bool::from_value(val / 8usize).unwrap(); - val -= (west.value() - 0usize) * 8usize; - let south = bool::from_value(val / 4usize).unwrap(); - val -= (south.value() - 0usize) * 4usize; - let east = bool::from_value(val / 2usize).unwrap(); - val -= (east.value() - 0usize) * 2usize; - let north = bool::from_value(val / 1usize).unwrap(); - val -= (north.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - west, - south, - east, - north, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrownStainedGlassPaneData { - pub west: bool, - pub east: bool, - pub north: bool, - pub waterlogged: bool, - pub south: bool, -} -impl BrownStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - south: bool::from_snake_case(map.get("south")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m - } -} -impl Default for BrownStainedGlassPaneData { - fn default() -> Self { - Self { - west: false, - east: false, - north: false, - waterlogged: false, - south: false, - } - } -} -impl Value for BrownStainedGlassPaneData { - fn value(&self) -> usize { - (self.west.value() * 16usize) - + (self.east.value() * 8usize) - + (self.north.value() * 4usize) - + (self.waterlogged.value() * 2usize) - + (self.south.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let east = bool::from_value(val / 8usize).unwrap(); - val -= (east.value() - 0usize) * 8usize; - let north = bool::from_value(val / 4usize).unwrap(); - val -= (north.value() - 0usize) * 4usize; - let waterlogged = bool::from_value(val / 2usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 2usize; - let south = bool::from_value(val / 1usize).unwrap(); - val -= (south.value() - 0usize) * 1usize; - Some(Self { - west, - east, - north, - waterlogged, - south, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GreenStainedGlassPaneData { - pub east: bool, - pub north: bool, - pub waterlogged: bool, - pub west: bool, - pub south: bool, -} -impl GreenStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m - } -} -impl Default for GreenStainedGlassPaneData { - fn default() -> Self { - Self { - east: false, - north: false, - waterlogged: false, - west: false, - south: false, - } - } -} -impl Value for GreenStainedGlassPaneData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.north.value() * 8usize) - + (self.waterlogged.value() * 4usize) - + (self.west.value() * 2usize) - + (self.south.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let west = bool::from_value(val / 2usize).unwrap(); - val -= (west.value() - 0usize) * 2usize; - let south = bool::from_value(val / 1usize).unwrap(); - val -= (south.value() - 0usize) * 1usize; - Some(Self { - east, - north, - waterlogged, - west, - south, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedStainedGlassPaneData { - pub east: bool, - pub south: bool, - pub waterlogged: bool, - pub north: bool, - pub west: bool, -} -impl RedStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - north: bool::from_snake_case(map.get("north")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for RedStainedGlassPaneData { - fn default() -> Self { - Self { - east: false, - south: false, - waterlogged: false, - north: false, - west: false, - } - } -} -impl Value for RedStainedGlassPaneData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.south.value() * 8usize) - + (self.waterlogged.value() * 4usize) - + (self.north.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let south = bool::from_value(val / 8usize).unwrap(); - val -= (south.value() - 0usize) * 8usize; - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let north = bool::from_value(val / 2usize).unwrap(); - val -= (north.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - east, - south, - waterlogged, - north, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlackStainedGlassPaneData { - pub north: bool, - pub south: bool, - pub waterlogged: bool, - pub east: bool, - pub west: bool, -} -impl BlackStainedGlassPaneData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - east: bool::from_snake_case(map.get("east")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for BlackStainedGlassPaneData { - fn default() -> Self { - Self { - north: false, - south: false, - waterlogged: false, - east: false, - west: false, - } - } -} -impl Value for BlackStainedGlassPaneData { - fn value(&self) -> usize { - (self.north.value() * 16usize) - + (self.south.value() * 8usize) - + (self.waterlogged.value() * 4usize) - + (self.east.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let north = bool::from_value(val / 16usize).unwrap(); - val -= (north.value() - 0usize) * 16usize; - let south = bool::from_value(val / 8usize).unwrap(); - val -= (south.value() - 0usize) * 8usize; - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let east = bool::from_value(val / 2usize).unwrap(); - val -= (east.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - north, - south, - waterlogged, - east, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaStairsData { - pub half: AcaciaStairsHalf, - pub facing: AcaciaStairsFacing, - pub shape: AcaciaStairsShape, - pub waterlogged: bool, -} -impl AcaciaStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: AcaciaStairsHalf::from_snake_case(map.get("half")?)?, - facing: AcaciaStairsFacing::from_snake_case(map.get("facing")?)?, - shape: AcaciaStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for AcaciaStairsData { - fn default() -> Self { - Self { - half: AcaciaStairsHalf::Bottom, - facing: AcaciaStairsFacing::North, - shape: AcaciaStairsShape::Straight, - waterlogged: false, - } - } -} -impl Value for AcaciaStairsData { - fn value(&self) -> usize { - (self.half.value() * 40usize) - + (self.facing.value() * 10usize) - + (self.shape.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let half = AcaciaStairsHalf::from_value(val / 40usize).unwrap(); - val -= (half.value() - 0usize) * 40usize; - let facing = AcaciaStairsFacing::from_value(val / 10usize).unwrap(); - val -= (facing.value() - 0usize) * 10usize; - let shape = AcaciaStairsShape::from_value(val / 2usize).unwrap(); - val -= (shape.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - half, - facing, - shape, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakStairsData { - pub shape: DarkOakStairsShape, - pub waterlogged: bool, - pub half: DarkOakStairsHalf, - pub facing: DarkOakStairsFacing, -} -impl DarkOakStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - shape: DarkOakStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: DarkOakStairsHalf::from_snake_case(map.get("half")?)?, - facing: DarkOakStairsFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for DarkOakStairsData { - fn default() -> Self { - Self { - shape: DarkOakStairsShape::Straight, - waterlogged: false, - half: DarkOakStairsHalf::Bottom, - facing: DarkOakStairsFacing::North, - } - } -} -impl Value for DarkOakStairsData { - fn value(&self) -> usize { - (self.shape.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.half.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let shape = DarkOakStairsShape::from_value(val / 16usize).unwrap(); - val -= (shape.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let half = DarkOakStairsHalf::from_value(val / 4usize).unwrap(); - val -= (half.value() - 0usize) * 4usize; - let facing = DarkOakStairsFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - shape, - waterlogged, - half, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct IronTrapdoorData { - pub waterlogged: bool, - pub open: bool, - pub facing: IronTrapdoorFacing, - pub half: IronTrapdoorHalf, - pub powered: bool, -} -impl IronTrapdoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - open: bool::from_snake_case(map.get("open")?)?, - facing: IronTrapdoorFacing::from_snake_case(map.get("facing")?)?, - half: IronTrapdoorHalf::from_snake_case(map.get("half")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for IronTrapdoorData { - fn default() -> Self { - Self { - waterlogged: false, - open: false, - facing: IronTrapdoorFacing::North, - half: IronTrapdoorHalf::Bottom, - powered: false, - } - } -} -impl Value for IronTrapdoorData { - fn value(&self) -> usize { - (self.waterlogged.value() * 32usize) - + (self.open.value() * 16usize) - + (self.facing.value() * 4usize) - + (self.half.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let waterlogged = bool::from_value(val / 32usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 32usize; - let open = bool::from_value(val / 16usize).unwrap(); - val -= (open.value() - 0usize) * 16usize; - let facing = IronTrapdoorFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let half = IronTrapdoorHalf::from_value(val / 2usize).unwrap(); - val -= (half.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - open, - facing, - half, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PrismarineStairsData { - pub shape: PrismarineStairsShape, - pub facing: PrismarineStairsFacing, - pub half: PrismarineStairsHalf, - pub waterlogged: bool, -} -impl PrismarineStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - shape: PrismarineStairsShape::from_snake_case(map.get("shape")?)?, - facing: PrismarineStairsFacing::from_snake_case(map.get("facing")?)?, - half: PrismarineStairsHalf::from_snake_case(map.get("half")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for PrismarineStairsData { - fn default() -> Self { - Self { - shape: PrismarineStairsShape::Straight, - facing: PrismarineStairsFacing::North, - half: PrismarineStairsHalf::Bottom, - waterlogged: false, - } - } -} -impl Value for PrismarineStairsData { - fn value(&self) -> usize { - (self.shape.value() * 16usize) - + (self.facing.value() * 4usize) - + (self.half.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let shape = PrismarineStairsShape::from_value(val / 16usize).unwrap(); - val -= (shape.value() - 0usize) * 16usize; - let facing = PrismarineStairsFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let half = PrismarineStairsHalf::from_value(val / 2usize).unwrap(); - val -= (half.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - shape, - facing, - half, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PrismarineBrickStairsData { - pub half: PrismarineBrickStairsHalf, - pub facing: PrismarineBrickStairsFacing, - pub waterlogged: bool, - pub shape: PrismarineBrickStairsShape, -} -impl PrismarineBrickStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: PrismarineBrickStairsHalf::from_snake_case(map.get("half")?)?, - facing: PrismarineBrickStairsFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - shape: PrismarineBrickStairsShape::from_snake_case(map.get("shape")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m - } -} -impl Default for PrismarineBrickStairsData { - fn default() -> Self { - Self { - half: PrismarineBrickStairsHalf::Bottom, - facing: PrismarineBrickStairsFacing::North, - waterlogged: false, - shape: PrismarineBrickStairsShape::Straight, - } - } -} -impl Value for PrismarineBrickStairsData { - fn value(&self) -> usize { - (self.half.value() * 40usize) - + (self.facing.value() * 10usize) - + (self.waterlogged.value() * 5usize) - + (self.shape.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let half = PrismarineBrickStairsHalf::from_value(val / 40usize).unwrap(); - val -= (half.value() - 0usize) * 40usize; - let facing = PrismarineBrickStairsFacing::from_value(val / 10usize).unwrap(); - val -= (facing.value() - 0usize) * 10usize; - let waterlogged = bool::from_value(val / 5usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 5usize; - let shape = PrismarineBrickStairsShape::from_value(val / 1usize).unwrap(); - val -= (shape.value() - 0usize) * 1usize; - Some(Self { - half, - facing, - waterlogged, - shape, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkPrismarineStairsData { - pub facing: DarkPrismarineStairsFacing, - pub half: DarkPrismarineStairsHalf, - pub shape: DarkPrismarineStairsShape, - pub waterlogged: bool, -} -impl DarkPrismarineStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: DarkPrismarineStairsFacing::from_snake_case(map.get("facing")?)?, - half: DarkPrismarineStairsHalf::from_snake_case(map.get("half")?)?, - shape: DarkPrismarineStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DarkPrismarineStairsData { - fn default() -> Self { - Self { - facing: DarkPrismarineStairsFacing::North, - half: DarkPrismarineStairsHalf::Bottom, - shape: DarkPrismarineStairsShape::Straight, - waterlogged: false, - } - } -} -impl Value for DarkPrismarineStairsData { - fn value(&self) -> usize { - (self.facing.value() * 20usize) - + (self.half.value() * 10usize) - + (self.shape.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let facing = DarkPrismarineStairsFacing::from_value(val / 20usize).unwrap(); - val -= (facing.value() - 0usize) * 20usize; - let half = DarkPrismarineStairsHalf::from_value(val / 10usize).unwrap(); - val -= (half.value() - 0usize) * 10usize; - let shape = DarkPrismarineStairsShape::from_value(val / 2usize).unwrap(); - val -= (shape.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - half, - shape, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PrismarineSlabData { - pub ty: PrismarineSlabType, - pub waterlogged: bool, -} -impl PrismarineSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: PrismarineSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for PrismarineSlabData { - fn default() -> Self { - Self { - ty: PrismarineSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for PrismarineSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = PrismarineSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PrismarineBrickSlabData { - pub ty: PrismarineBrickSlabType, - pub waterlogged: bool, -} -impl PrismarineBrickSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: PrismarineBrickSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for PrismarineBrickSlabData { - fn default() -> Self { - Self { - ty: PrismarineBrickSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for PrismarineBrickSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = PrismarineBrickSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkPrismarineSlabData { - pub ty: DarkPrismarineSlabType, - pub waterlogged: bool, -} -impl DarkPrismarineSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: DarkPrismarineSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DarkPrismarineSlabData { - fn default() -> Self { - Self { - ty: DarkPrismarineSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for DarkPrismarineSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = DarkPrismarineSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct HayBlockData { - pub axis: HayBlockAxis, -} -impl HayBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: HayBlockAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for HayBlockData { - fn default() -> Self { - Self { - axis: HayBlockAxis::Y, - } - } -} -impl Value for HayBlockData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = HayBlockAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SunflowerData { - pub half: SunflowerHalf, -} -impl SunflowerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: SunflowerHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for SunflowerData { - fn default() -> Self { - Self { - half: SunflowerHalf::Lower, - } - } -} -impl Value for SunflowerData { - fn value(&self) -> usize { - (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let half = SunflowerHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { half }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LilacData { - pub half: LilacHalf, -} -impl LilacData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: LilacHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for LilacData { - fn default() -> Self { - Self { - half: LilacHalf::Lower, - } - } -} -impl Value for LilacData { - fn value(&self) -> usize { - (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let half = LilacHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { half }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RoseBushData { - pub half: RoseBushHalf, -} -impl RoseBushData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: RoseBushHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for RoseBushData { - fn default() -> Self { - Self { - half: RoseBushHalf::Lower, - } - } -} -impl Value for RoseBushData { - fn value(&self) -> usize { - (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let half = RoseBushHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { half }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PeonyData { - pub half: PeonyHalf, -} -impl PeonyData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: PeonyHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for PeonyData { - fn default() -> Self { - Self { - half: PeonyHalf::Lower, - } - } -} -impl Value for PeonyData { - fn value(&self) -> usize { - (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let half = PeonyHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { half }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TallGrassData { - pub half: TallGrassHalf, -} -impl TallGrassData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: TallGrassHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for TallGrassData { - fn default() -> Self { - Self { - half: TallGrassHalf::Lower, - } - } -} -impl Value for TallGrassData { - fn value(&self) -> usize { - (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let half = TallGrassHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { half }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LargeFernData { - pub half: LargeFernHalf, -} -impl LargeFernData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: LargeFernHalf::from_snake_case(map.get("half")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m - } -} -impl Default for LargeFernData { - fn default() -> Self { - Self { - half: LargeFernHalf::Lower, - } - } -} -impl Value for LargeFernData { - fn value(&self) -> usize { - (self.half.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let half = LargeFernHalf::from_value(val / 1usize).unwrap(); - val -= (half.value() - 0usize) * 1usize; - Some(Self { half }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WhiteBannerData { - pub rotation: i32, -} -impl WhiteBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for WhiteBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for WhiteBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OrangeBannerData { - pub rotation: i32, -} -impl OrangeBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for OrangeBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for OrangeBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MagentaBannerData { - pub rotation: i32, -} -impl MagentaBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for MagentaBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for MagentaBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightBlueBannerData { - pub rotation: i32, -} -impl LightBlueBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for LightBlueBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for LightBlueBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct YellowBannerData { - pub rotation: i32, -} -impl YellowBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for YellowBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for YellowBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LimeBannerData { - pub rotation: i32, -} -impl LimeBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for LimeBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for LimeBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PinkBannerData { - pub rotation: i32, -} -impl PinkBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for PinkBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for PinkBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GrayBannerData { - pub rotation: i32, -} -impl GrayBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for GrayBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for GrayBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightGrayBannerData { - pub rotation: i32, -} -impl LightGrayBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for LightGrayBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for LightGrayBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CyanBannerData { - pub rotation: i32, -} -impl CyanBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for CyanBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for CyanBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpleBannerData { - pub rotation: i32, -} -impl PurpleBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for PurpleBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for PurpleBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlueBannerData { - pub rotation: i32, -} -impl BlueBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for BlueBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for BlueBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrownBannerData { - pub rotation: i32, -} -impl BrownBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for BrownBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for BrownBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GreenBannerData { - pub rotation: i32, -} -impl GreenBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for GreenBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for GreenBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedBannerData { - pub rotation: i32, -} -impl RedBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for RedBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for RedBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlackBannerData { - pub rotation: i32, -} -impl BlackBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - rotation: i32::from_snake_case(map.get("rotation")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("rotation".to_string(), self.rotation.to_snake_case()); - m - } -} -impl Default for BlackBannerData { - fn default() -> Self { - Self { rotation: 0 } - } -} -impl Value for BlackBannerData { - fn value(&self) -> usize { - (self.rotation.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 16usize { - return None; - } - let rotation = i32::from_value(val / 1usize).unwrap(); - val -= (rotation.value() - 0usize) * 1usize; - Some(Self { rotation }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WhiteWallBannerData { - pub facing: WhiteWallBannerFacing, -} -impl WhiteWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: WhiteWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for WhiteWallBannerData { - fn default() -> Self { - Self { - facing: WhiteWallBannerFacing::North, - } - } -} -impl Value for WhiteWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = WhiteWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OrangeWallBannerData { - pub facing: OrangeWallBannerFacing, -} -impl OrangeWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: OrangeWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for OrangeWallBannerData { - fn default() -> Self { - Self { - facing: OrangeWallBannerFacing::North, - } - } -} -impl Value for OrangeWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = OrangeWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MagentaWallBannerData { - pub facing: MagentaWallBannerFacing, -} -impl MagentaWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: MagentaWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for MagentaWallBannerData { - fn default() -> Self { - Self { - facing: MagentaWallBannerFacing::North, - } - } -} -impl Value for MagentaWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = MagentaWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightBlueWallBannerData { - pub facing: LightBlueWallBannerFacing, -} -impl LightBlueWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LightBlueWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LightBlueWallBannerData { - fn default() -> Self { - Self { - facing: LightBlueWallBannerFacing::North, - } - } -} -impl Value for LightBlueWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = LightBlueWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct YellowWallBannerData { - pub facing: YellowWallBannerFacing, -} -impl YellowWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: YellowWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for YellowWallBannerData { - fn default() -> Self { - Self { - facing: YellowWallBannerFacing::North, - } - } -} -impl Value for YellowWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = YellowWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LimeWallBannerData { - pub facing: LimeWallBannerFacing, -} -impl LimeWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LimeWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LimeWallBannerData { - fn default() -> Self { - Self { - facing: LimeWallBannerFacing::North, - } - } -} -impl Value for LimeWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = LimeWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PinkWallBannerData { - pub facing: PinkWallBannerFacing, -} -impl PinkWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: PinkWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PinkWallBannerData { - fn default() -> Self { - Self { - facing: PinkWallBannerFacing::North, - } - } -} -impl Value for PinkWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = PinkWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GrayWallBannerData { - pub facing: GrayWallBannerFacing, -} -impl GrayWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: GrayWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for GrayWallBannerData { - fn default() -> Self { - Self { - facing: GrayWallBannerFacing::North, - } - } -} -impl Value for GrayWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = GrayWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightGrayWallBannerData { - pub facing: LightGrayWallBannerFacing, -} -impl LightGrayWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LightGrayWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LightGrayWallBannerData { - fn default() -> Self { - Self { - facing: LightGrayWallBannerFacing::North, - } - } -} -impl Value for LightGrayWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = LightGrayWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CyanWallBannerData { - pub facing: CyanWallBannerFacing, -} -impl CyanWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: CyanWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for CyanWallBannerData { - fn default() -> Self { - Self { - facing: CyanWallBannerFacing::North, - } - } -} -impl Value for CyanWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = CyanWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpleWallBannerData { - pub facing: PurpleWallBannerFacing, -} -impl PurpleWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: PurpleWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PurpleWallBannerData { - fn default() -> Self { - Self { - facing: PurpleWallBannerFacing::North, - } - } -} -impl Value for PurpleWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = PurpleWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlueWallBannerData { - pub facing: BlueWallBannerFacing, -} -impl BlueWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BlueWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BlueWallBannerData { - fn default() -> Self { - Self { - facing: BlueWallBannerFacing::North, - } - } -} -impl Value for BlueWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = BlueWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrownWallBannerData { - pub facing: BrownWallBannerFacing, -} -impl BrownWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BrownWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BrownWallBannerData { - fn default() -> Self { - Self { - facing: BrownWallBannerFacing::North, - } - } -} -impl Value for BrownWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = BrownWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GreenWallBannerData { - pub facing: GreenWallBannerFacing, -} -impl GreenWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: GreenWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for GreenWallBannerData { - fn default() -> Self { - Self { - facing: GreenWallBannerFacing::North, - } - } -} -impl Value for GreenWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = GreenWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedWallBannerData { - pub facing: RedWallBannerFacing, -} -impl RedWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: RedWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for RedWallBannerData { - fn default() -> Self { - Self { - facing: RedWallBannerFacing::North, - } - } -} -impl Value for RedWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = RedWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlackWallBannerData { - pub facing: BlackWallBannerFacing, -} -impl BlackWallBannerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BlackWallBannerFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BlackWallBannerData { - fn default() -> Self { - Self { - facing: BlackWallBannerFacing::North, - } - } -} -impl Value for BlackWallBannerData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = BlackWallBannerFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedSandstoneStairsData { - pub facing: RedSandstoneStairsFacing, - pub shape: RedSandstoneStairsShape, - pub half: RedSandstoneStairsHalf, - pub waterlogged: bool, -} -impl RedSandstoneStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: RedSandstoneStairsFacing::from_snake_case(map.get("facing")?)?, - shape: RedSandstoneStairsShape::from_snake_case(map.get("shape")?)?, - half: RedSandstoneStairsHalf::from_snake_case(map.get("half")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for RedSandstoneStairsData { - fn default() -> Self { - Self { - facing: RedSandstoneStairsFacing::North, - shape: RedSandstoneStairsShape::Straight, - half: RedSandstoneStairsHalf::Bottom, - waterlogged: false, - } - } -} -impl Value for RedSandstoneStairsData { - fn value(&self) -> usize { - (self.facing.value() * 20usize) - + (self.shape.value() * 4usize) - + (self.half.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let facing = RedSandstoneStairsFacing::from_value(val / 20usize).unwrap(); - val -= (facing.value() - 0usize) * 20usize; - let shape = RedSandstoneStairsShape::from_value(val / 4usize).unwrap(); - val -= (shape.value() - 0usize) * 4usize; - let half = RedSandstoneStairsHalf::from_value(val / 2usize).unwrap(); - val -= (half.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - shape, - half, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OakSlabData { - pub ty: OakSlabType, - pub waterlogged: bool, -} -impl OakSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: OakSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for OakSlabData { - fn default() -> Self { - Self { - ty: OakSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for OakSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = OakSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceSlabData { - pub waterlogged: bool, - pub ty: SpruceSlabType, -} -impl SpruceSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: SpruceSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for SpruceSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: SpruceSlabType::Bottom, - } - } -} -impl Value for SpruceSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = SpruceSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchSlabData { - pub ty: BirchSlabType, - pub waterlogged: bool, -} -impl BirchSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: BirchSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for BirchSlabData { - fn default() -> Self { - Self { - ty: BirchSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for BirchSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = BirchSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleSlabData { - pub waterlogged: bool, - pub ty: JungleSlabType, -} -impl JungleSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: JungleSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for JungleSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: JungleSlabType::Bottom, - } - } -} -impl Value for JungleSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = JungleSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaSlabData { - pub waterlogged: bool, - pub ty: AcaciaSlabType, -} -impl AcaciaSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: AcaciaSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for AcaciaSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: AcaciaSlabType::Bottom, - } - } -} -impl Value for AcaciaSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = AcaciaSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakSlabData { - pub ty: DarkOakSlabType, - pub waterlogged: bool, -} -impl DarkOakSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: DarkOakSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DarkOakSlabData { - fn default() -> Self { - Self { - ty: DarkOakSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for DarkOakSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = DarkOakSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StoneSlabData { - pub ty: StoneSlabType, - pub waterlogged: bool, -} -impl StoneSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: StoneSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for StoneSlabData { - fn default() -> Self { - Self { - ty: StoneSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for StoneSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = StoneSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SandstoneSlabData { - pub waterlogged: bool, - pub ty: SandstoneSlabType, -} -impl SandstoneSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: SandstoneSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for SandstoneSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: SandstoneSlabType::Bottom, - } - } -} -impl Value for SandstoneSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = SandstoneSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PetrifiedOakSlabData { - pub waterlogged: bool, - pub ty: PetrifiedOakSlabType, -} -impl PetrifiedOakSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: PetrifiedOakSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for PetrifiedOakSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: PetrifiedOakSlabType::Bottom, - } - } -} -impl Value for PetrifiedOakSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = PetrifiedOakSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CobblestoneSlabData { - pub waterlogged: bool, - pub ty: CobblestoneSlabType, -} -impl CobblestoneSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: CobblestoneSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for CobblestoneSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: CobblestoneSlabType::Bottom, - } - } -} -impl Value for CobblestoneSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = CobblestoneSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrickSlabData { - pub waterlogged: bool, - pub ty: BrickSlabType, -} -impl BrickSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: BrickSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for BrickSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: BrickSlabType::Bottom, - } - } -} -impl Value for BrickSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = BrickSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StoneBrickSlabData { - pub ty: StoneBrickSlabType, - pub waterlogged: bool, -} -impl StoneBrickSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: StoneBrickSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for StoneBrickSlabData { - fn default() -> Self { - Self { - ty: StoneBrickSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for StoneBrickSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = StoneBrickSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct NetherBrickSlabData { - pub waterlogged: bool, - pub ty: NetherBrickSlabType, -} -impl NetherBrickSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: NetherBrickSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for NetherBrickSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: NetherBrickSlabType::Bottom, - } - } -} -impl Value for NetherBrickSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = NetherBrickSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct QuartzSlabData { - pub waterlogged: bool, - pub ty: QuartzSlabType, -} -impl QuartzSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: QuartzSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for QuartzSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: QuartzSlabType::Bottom, - } - } -} -impl Value for QuartzSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = QuartzSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedSandstoneSlabData { - pub ty: RedSandstoneSlabType, - pub waterlogged: bool, -} -impl RedSandstoneSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - ty: RedSandstoneSlabType::from_snake_case(map.get("type")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("type".to_string(), self.ty.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for RedSandstoneSlabData { - fn default() -> Self { - Self { - ty: RedSandstoneSlabType::Bottom, - waterlogged: false, - } - } -} -impl Value for RedSandstoneSlabData { - fn value(&self) -> usize { - (self.ty.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let ty = RedSandstoneSlabType::from_value(val / 2usize).unwrap(); - val -= (ty.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { ty, waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpurSlabData { - pub waterlogged: bool, - pub ty: PurpurSlabType, -} -impl PurpurSlabData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - ty: PurpurSlabType::from_snake_case(map.get("type")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("type".to_string(), self.ty.to_snake_case()); - m - } -} -impl Default for PurpurSlabData { - fn default() -> Self { - Self { - waterlogged: false, - ty: PurpurSlabType::Bottom, - } - } -} -impl Value for PurpurSlabData { - fn value(&self) -> usize { - (self.waterlogged.value() * 3usize) + (self.ty.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let waterlogged = bool::from_value(val / 3usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 3usize; - let ty = PurpurSlabType::from_value(val / 1usize).unwrap(); - val -= (ty.value() - 0usize) * 1usize; - Some(Self { waterlogged, ty }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceFenceGateData { - pub facing: SpruceFenceGateFacing, - pub powered: bool, - pub open: bool, - pub in_wall: bool, -} -impl SpruceFenceGateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: SpruceFenceGateFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - open: bool::from_snake_case(map.get("open")?)?, - in_wall: bool::from_snake_case(map.get("in_wall")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("in_wall".to_string(), self.in_wall.to_snake_case()); - m - } -} -impl Default for SpruceFenceGateData { - fn default() -> Self { - Self { - facing: SpruceFenceGateFacing::North, - powered: false, - open: false, - in_wall: false, - } - } -} -impl Value for SpruceFenceGateData { - fn value(&self) -> usize { - (self.facing.value() * 8usize) - + (self.powered.value() * 4usize) - + (self.open.value() * 2usize) - + (self.in_wall.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let facing = SpruceFenceGateFacing::from_value(val / 8usize).unwrap(); - val -= (facing.value() - 0usize) * 8usize; - let powered = bool::from_value(val / 4usize).unwrap(); - val -= (powered.value() - 0usize) * 4usize; - let open = bool::from_value(val / 2usize).unwrap(); - val -= (open.value() - 0usize) * 2usize; - let in_wall = bool::from_value(val / 1usize).unwrap(); - val -= (in_wall.value() - 0usize) * 1usize; - Some(Self { - facing, - powered, - open, - in_wall, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchFenceGateData { - pub in_wall: bool, - pub open: bool, - pub facing: BirchFenceGateFacing, - pub powered: bool, -} -impl BirchFenceGateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - in_wall: bool::from_snake_case(map.get("in_wall")?)?, - open: bool::from_snake_case(map.get("open")?)?, - facing: BirchFenceGateFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("in_wall".to_string(), self.in_wall.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for BirchFenceGateData { - fn default() -> Self { - Self { - in_wall: false, - open: false, - facing: BirchFenceGateFacing::North, - powered: false, - } - } -} -impl Value for BirchFenceGateData { - fn value(&self) -> usize { - (self.in_wall.value() * 16usize) - + (self.open.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let in_wall = bool::from_value(val / 16usize).unwrap(); - val -= (in_wall.value() - 0usize) * 16usize; - let open = bool::from_value(val / 8usize).unwrap(); - val -= (open.value() - 0usize) * 8usize; - let facing = BirchFenceGateFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - in_wall, - open, - facing, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleFenceGateData { - pub facing: JungleFenceGateFacing, - pub powered: bool, - pub open: bool, - pub in_wall: bool, -} -impl JungleFenceGateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: JungleFenceGateFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - open: bool::from_snake_case(map.get("open")?)?, - in_wall: bool::from_snake_case(map.get("in_wall")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("in_wall".to_string(), self.in_wall.to_snake_case()); - m - } -} -impl Default for JungleFenceGateData { - fn default() -> Self { - Self { - facing: JungleFenceGateFacing::North, - powered: false, - open: false, - in_wall: false, - } - } -} -impl Value for JungleFenceGateData { - fn value(&self) -> usize { - (self.facing.value() * 8usize) - + (self.powered.value() * 4usize) - + (self.open.value() * 2usize) - + (self.in_wall.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let facing = JungleFenceGateFacing::from_value(val / 8usize).unwrap(); - val -= (facing.value() - 0usize) * 8usize; - let powered = bool::from_value(val / 4usize).unwrap(); - val -= (powered.value() - 0usize) * 4usize; - let open = bool::from_value(val / 2usize).unwrap(); - val -= (open.value() - 0usize) * 2usize; - let in_wall = bool::from_value(val / 1usize).unwrap(); - val -= (in_wall.value() - 0usize) * 1usize; - Some(Self { - facing, - powered, - open, - in_wall, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaFenceGateData { - pub powered: bool, - pub facing: AcaciaFenceGateFacing, - pub in_wall: bool, - pub open: bool, -} -impl AcaciaFenceGateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - facing: AcaciaFenceGateFacing::from_snake_case(map.get("facing")?)?, - in_wall: bool::from_snake_case(map.get("in_wall")?)?, - open: bool::from_snake_case(map.get("open")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("in_wall".to_string(), self.in_wall.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m - } -} -impl Default for AcaciaFenceGateData { - fn default() -> Self { - Self { - powered: false, - facing: AcaciaFenceGateFacing::North, - in_wall: false, - open: false, - } - } -} -impl Value for AcaciaFenceGateData { - fn value(&self) -> usize { - (self.powered.value() * 16usize) - + (self.facing.value() * 4usize) - + (self.in_wall.value() * 2usize) - + (self.open.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let powered = bool::from_value(val / 16usize).unwrap(); - val -= (powered.value() - 0usize) * 16usize; - let facing = AcaciaFenceGateFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let in_wall = bool::from_value(val / 2usize).unwrap(); - val -= (in_wall.value() - 0usize) * 2usize; - let open = bool::from_value(val / 1usize).unwrap(); - val -= (open.value() - 0usize) * 1usize; - Some(Self { - powered, - facing, - in_wall, - open, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakFenceGateData { - pub in_wall: bool, - pub open: bool, - pub powered: bool, - pub facing: DarkOakFenceGateFacing, -} -impl DarkOakFenceGateData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - in_wall: bool::from_snake_case(map.get("in_wall")?)?, - open: bool::from_snake_case(map.get("open")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - facing: DarkOakFenceGateFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("in_wall".to_string(), self.in_wall.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for DarkOakFenceGateData { - fn default() -> Self { - Self { - in_wall: false, - open: false, - powered: false, - facing: DarkOakFenceGateFacing::North, - } - } -} -impl Value for DarkOakFenceGateData { - fn value(&self) -> usize { - (self.in_wall.value() * 16usize) - + (self.open.value() * 8usize) - + (self.powered.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let in_wall = bool::from_value(val / 16usize).unwrap(); - val -= (in_wall.value() - 0usize) * 16usize; - let open = bool::from_value(val / 8usize).unwrap(); - val -= (open.value() - 0usize) * 8usize; - let powered = bool::from_value(val / 4usize).unwrap(); - val -= (powered.value() - 0usize) * 4usize; - let facing = DarkOakFenceGateFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - in_wall, - open, - powered, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceFenceData { - pub north: bool, - pub waterlogged: bool, - pub west: bool, - pub east: bool, - pub south: bool, -} -impl SpruceFenceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - north: bool::from_snake_case(map.get("north")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - south: bool::from_snake_case(map.get("south")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m - } -} -impl Default for SpruceFenceData { - fn default() -> Self { - Self { - north: false, - waterlogged: false, - west: false, - east: false, - south: false, - } - } -} -impl Value for SpruceFenceData { - fn value(&self) -> usize { - (self.north.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.west.value() * 4usize) - + (self.east.value() * 2usize) - + (self.south.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let north = bool::from_value(val / 16usize).unwrap(); - val -= (north.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let west = bool::from_value(val / 4usize).unwrap(); - val -= (west.value() - 0usize) * 4usize; - let east = bool::from_value(val / 2usize).unwrap(); - val -= (east.value() - 0usize) * 2usize; - let south = bool::from_value(val / 1usize).unwrap(); - val -= (south.value() - 0usize) * 1usize; - Some(Self { - north, - waterlogged, - west, - east, - south, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchFenceData { - pub waterlogged: bool, - pub east: bool, - pub west: bool, - pub south: bool, - pub north: bool, -} -impl BirchFenceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - east: bool::from_snake_case(map.get("east")?)?, - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - north: bool::from_snake_case(map.get("north")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m - } -} -impl Default for BirchFenceData { - fn default() -> Self { - Self { - waterlogged: false, - east: false, - west: false, - south: false, - north: false, - } - } -} -impl Value for BirchFenceData { - fn value(&self) -> usize { - (self.waterlogged.value() * 16usize) - + (self.east.value() * 8usize) - + (self.west.value() * 4usize) - + (self.south.value() * 2usize) - + (self.north.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let waterlogged = bool::from_value(val / 16usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 16usize; - let east = bool::from_value(val / 8usize).unwrap(); - val -= (east.value() - 0usize) * 8usize; - let west = bool::from_value(val / 4usize).unwrap(); - val -= (west.value() - 0usize) * 4usize; - let south = bool::from_value(val / 2usize).unwrap(); - val -= (south.value() - 0usize) * 2usize; - let north = bool::from_value(val / 1usize).unwrap(); - val -= (north.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - east, - west, - south, - north, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleFenceData { - pub west: bool, - pub south: bool, - pub east: bool, - pub north: bool, - pub waterlogged: bool, -} -impl JungleFenceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for JungleFenceData { - fn default() -> Self { - Self { - west: false, - south: false, - east: false, - north: false, - waterlogged: false, - } - } -} -impl Value for JungleFenceData { - fn value(&self) -> usize { - (self.west.value() * 16usize) - + (self.south.value() * 8usize) - + (self.east.value() * 4usize) - + (self.north.value() * 2usize) - + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let west = bool::from_value(val / 16usize).unwrap(); - val -= (west.value() - 0usize) * 16usize; - let south = bool::from_value(val / 8usize).unwrap(); - val -= (south.value() - 0usize) * 8usize; - let east = bool::from_value(val / 4usize).unwrap(); - val -= (east.value() - 0usize) * 4usize; - let north = bool::from_value(val / 2usize).unwrap(); - val -= (north.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - west, - south, - east, - north, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaFenceData { - pub east: bool, - pub north: bool, - pub south: bool, - pub waterlogged: bool, - pub west: bool, -} -impl AcaciaFenceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m - } -} -impl Default for AcaciaFenceData { - fn default() -> Self { - Self { - east: false, - north: false, - south: false, - waterlogged: false, - west: false, - } - } -} -impl Value for AcaciaFenceData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.north.value() * 8usize) - + (self.south.value() * 4usize) - + (self.waterlogged.value() * 2usize) - + (self.west.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let south = bool::from_value(val / 4usize).unwrap(); - val -= (south.value() - 0usize) * 4usize; - let waterlogged = bool::from_value(val / 2usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 2usize; - let west = bool::from_value(val / 1usize).unwrap(); - val -= (west.value() - 0usize) * 1usize; - Some(Self { - east, - north, - south, - waterlogged, - west, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakFenceData { - pub east: bool, - pub north: bool, - pub waterlogged: bool, - pub west: bool, - pub south: bool, -} -impl DarkOakFenceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - east: bool::from_snake_case(map.get("east")?)?, - north: bool::from_snake_case(map.get("north")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - west: bool::from_snake_case(map.get("west")?)?, - south: bool::from_snake_case(map.get("south")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m - } -} -impl Default for DarkOakFenceData { - fn default() -> Self { - Self { - east: false, - north: false, - waterlogged: false, - west: false, - south: false, - } - } -} -impl Value for DarkOakFenceData { - fn value(&self) -> usize { - (self.east.value() * 16usize) - + (self.north.value() * 8usize) - + (self.waterlogged.value() * 4usize) - + (self.west.value() * 2usize) - + (self.south.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 32usize { - return None; - } - let east = bool::from_value(val / 16usize).unwrap(); - val -= (east.value() - 0usize) * 16usize; - let north = bool::from_value(val / 8usize).unwrap(); - val -= (north.value() - 0usize) * 8usize; - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let west = bool::from_value(val / 2usize).unwrap(); - val -= (west.value() - 0usize) * 2usize; - let south = bool::from_value(val / 1usize).unwrap(); - val -= (south.value() - 0usize) * 1usize; - Some(Self { - east, - north, - waterlogged, - west, - south, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SpruceDoorData { - pub powered: bool, - pub hinge: SpruceDoorHinge, - pub facing: SpruceDoorFacing, - pub half: SpruceDoorHalf, - pub open: bool, -} -impl SpruceDoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - hinge: SpruceDoorHinge::from_snake_case(map.get("hinge")?)?, - facing: SpruceDoorFacing::from_snake_case(map.get("facing")?)?, - half: SpruceDoorHalf::from_snake_case(map.get("half")?)?, - open: bool::from_snake_case(map.get("open")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("hinge".to_string(), self.hinge.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m - } -} -impl Default for SpruceDoorData { - fn default() -> Self { - Self { - powered: false, - hinge: SpruceDoorHinge::Left, - facing: SpruceDoorFacing::North, - half: SpruceDoorHalf::Lower, - open: false, - } - } -} -impl Value for SpruceDoorData { - fn value(&self) -> usize { - (self.powered.value() * 32usize) - + (self.hinge.value() * 16usize) - + (self.facing.value() * 4usize) - + (self.half.value() * 2usize) - + (self.open.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let powered = bool::from_value(val / 32usize).unwrap(); - val -= (powered.value() - 0usize) * 32usize; - let hinge = SpruceDoorHinge::from_value(val / 16usize).unwrap(); - val -= (hinge.value() - 0usize) * 16usize; - let facing = SpruceDoorFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let half = SpruceDoorHalf::from_value(val / 2usize).unwrap(); - val -= (half.value() - 0usize) * 2usize; - let open = bool::from_value(val / 1usize).unwrap(); - val -= (open.value() - 0usize) * 1usize; - Some(Self { - powered, - hinge, - facing, - half, - open, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BirchDoorData { - pub facing: BirchDoorFacing, - pub half: BirchDoorHalf, - pub open: bool, - pub powered: bool, - pub hinge: BirchDoorHinge, -} -impl BirchDoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BirchDoorFacing::from_snake_case(map.get("facing")?)?, - half: BirchDoorHalf::from_snake_case(map.get("half")?)?, - open: bool::from_snake_case(map.get("open")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - hinge: BirchDoorHinge::from_snake_case(map.get("hinge")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("hinge".to_string(), self.hinge.to_snake_case()); - m - } -} -impl Default for BirchDoorData { - fn default() -> Self { - Self { - facing: BirchDoorFacing::North, - half: BirchDoorHalf::Lower, - open: false, - powered: false, - hinge: BirchDoorHinge::Left, - } - } -} -impl Value for BirchDoorData { - fn value(&self) -> usize { - (self.facing.value() * 16usize) - + (self.half.value() * 8usize) - + (self.open.value() * 4usize) - + (self.powered.value() * 2usize) - + (self.hinge.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let facing = BirchDoorFacing::from_value(val / 16usize).unwrap(); - val -= (facing.value() - 0usize) * 16usize; - let half = BirchDoorHalf::from_value(val / 8usize).unwrap(); - val -= (half.value() - 0usize) * 8usize; - let open = bool::from_value(val / 4usize).unwrap(); - val -= (open.value() - 0usize) * 4usize; - let powered = bool::from_value(val / 2usize).unwrap(); - val -= (powered.value() - 0usize) * 2usize; - let hinge = BirchDoorHinge::from_value(val / 1usize).unwrap(); - val -= (hinge.value() - 0usize) * 1usize; - Some(Self { - facing, - half, - open, - powered, - hinge, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct JungleDoorData { - pub half: JungleDoorHalf, - pub powered: bool, - pub hinge: JungleDoorHinge, - pub open: bool, - pub facing: JungleDoorFacing, -} -impl JungleDoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: JungleDoorHalf::from_snake_case(map.get("half")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - hinge: JungleDoorHinge::from_snake_case(map.get("hinge")?)?, - open: bool::from_snake_case(map.get("open")?)?, - facing: JungleDoorFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("hinge".to_string(), self.hinge.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for JungleDoorData { - fn default() -> Self { - Self { - half: JungleDoorHalf::Lower, - powered: false, - hinge: JungleDoorHinge::Left, - open: false, - facing: JungleDoorFacing::North, - } - } -} -impl Value for JungleDoorData { - fn value(&self) -> usize { - (self.half.value() * 32usize) - + (self.powered.value() * 16usize) - + (self.hinge.value() * 8usize) - + (self.open.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let half = JungleDoorHalf::from_value(val / 32usize).unwrap(); - val -= (half.value() - 0usize) * 32usize; - let powered = bool::from_value(val / 16usize).unwrap(); - val -= (powered.value() - 0usize) * 16usize; - let hinge = JungleDoorHinge::from_value(val / 8usize).unwrap(); - val -= (hinge.value() - 0usize) * 8usize; - let open = bool::from_value(val / 4usize).unwrap(); - val -= (open.value() - 0usize) * 4usize; - let facing = JungleDoorFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - half, - powered, - hinge, - open, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct AcaciaDoorData { - pub powered: bool, - pub open: bool, - pub facing: AcaciaDoorFacing, - pub half: AcaciaDoorHalf, - pub hinge: AcaciaDoorHinge, -} -impl AcaciaDoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - open: bool::from_snake_case(map.get("open")?)?, - facing: AcaciaDoorFacing::from_snake_case(map.get("facing")?)?, - half: AcaciaDoorHalf::from_snake_case(map.get("half")?)?, - hinge: AcaciaDoorHinge::from_snake_case(map.get("hinge")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("hinge".to_string(), self.hinge.to_snake_case()); - m - } -} -impl Default for AcaciaDoorData { - fn default() -> Self { - Self { - powered: false, - open: false, - facing: AcaciaDoorFacing::North, - half: AcaciaDoorHalf::Lower, - hinge: AcaciaDoorHinge::Left, - } - } -} -impl Value for AcaciaDoorData { - fn value(&self) -> usize { - (self.powered.value() * 32usize) - + (self.open.value() * 16usize) - + (self.facing.value() * 4usize) - + (self.half.value() * 2usize) - + (self.hinge.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let powered = bool::from_value(val / 32usize).unwrap(); - val -= (powered.value() - 0usize) * 32usize; - let open = bool::from_value(val / 16usize).unwrap(); - val -= (open.value() - 0usize) * 16usize; - let facing = AcaciaDoorFacing::from_value(val / 4usize).unwrap(); - val -= (facing.value() - 0usize) * 4usize; - let half = AcaciaDoorHalf::from_value(val / 2usize).unwrap(); - val -= (half.value() - 0usize) * 2usize; - let hinge = AcaciaDoorHinge::from_value(val / 1usize).unwrap(); - val -= (hinge.value() - 0usize) * 1usize; - Some(Self { - powered, - open, - facing, - half, - hinge, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DarkOakDoorData { - pub half: DarkOakDoorHalf, - pub hinge: DarkOakDoorHinge, - pub open: bool, - pub facing: DarkOakDoorFacing, - pub powered: bool, -} -impl DarkOakDoorData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - half: DarkOakDoorHalf::from_snake_case(map.get("half")?)?, - hinge: DarkOakDoorHinge::from_snake_case(map.get("hinge")?)?, - open: bool::from_snake_case(map.get("open")?)?, - facing: DarkOakDoorFacing::from_snake_case(map.get("facing")?)?, - powered: bool::from_snake_case(map.get("powered")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("hinge".to_string(), self.hinge.to_snake_case()); - m.insert("open".to_string(), self.open.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m - } -} -impl Default for DarkOakDoorData { - fn default() -> Self { - Self { - half: DarkOakDoorHalf::Lower, - hinge: DarkOakDoorHinge::Left, - open: false, - facing: DarkOakDoorFacing::North, - powered: false, - } - } -} -impl Value for DarkOakDoorData { - fn value(&self) -> usize { - (self.half.value() * 32usize) - + (self.hinge.value() * 16usize) - + (self.open.value() * 8usize) - + (self.facing.value() * 2usize) - + (self.powered.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let half = DarkOakDoorHalf::from_value(val / 32usize).unwrap(); - val -= (half.value() - 0usize) * 32usize; - let hinge = DarkOakDoorHinge::from_value(val / 16usize).unwrap(); - val -= (hinge.value() - 0usize) * 16usize; - let open = bool::from_value(val / 8usize).unwrap(); - val -= (open.value() - 0usize) * 8usize; - let facing = DarkOakDoorFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let powered = bool::from_value(val / 1usize).unwrap(); - val -= (powered.value() - 0usize) * 1usize; - Some(Self { - half, - hinge, - open, - facing, - powered, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct EndRodData { - pub facing: EndRodFacing, -} -impl EndRodData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: EndRodFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for EndRodData { - fn default() -> Self { - Self { - facing: EndRodFacing::Up, - } - } -} -impl Value for EndRodData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = EndRodFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ChorusPlantData { - pub down: bool, - pub north: bool, - pub south: bool, - pub west: bool, - pub east: bool, - pub up: bool, -} -impl ChorusPlantData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - down: bool::from_snake_case(map.get("down")?)?, - north: bool::from_snake_case(map.get("north")?)?, - south: bool::from_snake_case(map.get("south")?)?, - west: bool::from_snake_case(map.get("west")?)?, - east: bool::from_snake_case(map.get("east")?)?, - up: bool::from_snake_case(map.get("up")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("down".to_string(), self.down.to_snake_case()); - m.insert("north".to_string(), self.north.to_snake_case()); - m.insert("south".to_string(), self.south.to_snake_case()); - m.insert("west".to_string(), self.west.to_snake_case()); - m.insert("east".to_string(), self.east.to_snake_case()); - m.insert("up".to_string(), self.up.to_snake_case()); - m - } -} -impl Default for ChorusPlantData { - fn default() -> Self { - Self { - down: false, - north: false, - south: false, - west: false, - east: false, - up: false, - } - } -} -impl Value for ChorusPlantData { - fn value(&self) -> usize { - (self.down.value() * 32usize) - + (self.north.value() * 16usize) - + (self.south.value() * 8usize) - + (self.west.value() * 4usize) - + (self.east.value() * 2usize) - + (self.up.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 64usize { - return None; - } - let down = bool::from_value(val / 32usize).unwrap(); - val -= (down.value() - 0usize) * 32usize; - let north = bool::from_value(val / 16usize).unwrap(); - val -= (north.value() - 0usize) * 16usize; - let south = bool::from_value(val / 8usize).unwrap(); - val -= (south.value() - 0usize) * 8usize; - let west = bool::from_value(val / 4usize).unwrap(); - val -= (west.value() - 0usize) * 4usize; - let east = bool::from_value(val / 2usize).unwrap(); - val -= (east.value() - 0usize) * 2usize; - let up = bool::from_value(val / 1usize).unwrap(); - val -= (up.value() - 0usize) * 1usize; - Some(Self { - down, - north, - south, - west, - east, - up, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ChorusFlowerData { - pub age: i32, -} -impl ChorusFlowerData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for ChorusFlowerData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for ChorusFlowerData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpurPillarData { - pub axis: PurpurPillarAxis, -} -impl PurpurPillarData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: PurpurPillarAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for PurpurPillarData { - fn default() -> Self { - Self { - axis: PurpurPillarAxis::Y, - } - } -} -impl Value for PurpurPillarData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = PurpurPillarAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpurStairsData { - pub shape: PurpurStairsShape, - pub waterlogged: bool, - pub half: PurpurStairsHalf, - pub facing: PurpurStairsFacing, -} -impl PurpurStairsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - shape: PurpurStairsShape::from_snake_case(map.get("shape")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - half: PurpurStairsHalf::from_snake_case(map.get("half")?)?, - facing: PurpurStairsFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("shape".to_string(), self.shape.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("half".to_string(), self.half.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PurpurStairsData { - fn default() -> Self { - Self { - shape: PurpurStairsShape::Straight, - waterlogged: false, - half: PurpurStairsHalf::Bottom, - facing: PurpurStairsFacing::North, - } - } -} -impl Value for PurpurStairsData { - fn value(&self) -> usize { - (self.shape.value() * 16usize) - + (self.waterlogged.value() * 8usize) - + (self.half.value() * 4usize) - + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 80usize { - return None; - } - let shape = PurpurStairsShape::from_value(val / 16usize).unwrap(); - val -= (shape.value() - 0usize) * 16usize; - let waterlogged = bool::from_value(val / 8usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 8usize; - let half = PurpurStairsHalf::from_value(val / 4usize).unwrap(); - val -= (half.value() - 0usize) * 4usize; - let facing = PurpurStairsFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - shape, - waterlogged, - half, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BeetrootsData { - pub age: i32, -} -impl BeetrootsData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for BeetrootsData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for BeetrootsData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RepeatingCommandBlockData { - pub conditional: bool, - pub facing: RepeatingCommandBlockFacing, -} -impl RepeatingCommandBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - conditional: bool::from_snake_case(map.get("conditional")?)?, - facing: RepeatingCommandBlockFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("conditional".to_string(), self.conditional.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for RepeatingCommandBlockData { - fn default() -> Self { - Self { - conditional: false, - facing: RepeatingCommandBlockFacing::North, - } - } -} -impl Value for RepeatingCommandBlockData { - fn value(&self) -> usize { - (self.conditional.value() * 6usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let conditional = bool::from_value(val / 6usize).unwrap(); - val -= (conditional.value() - 0usize) * 6usize; - let facing = RepeatingCommandBlockFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - conditional, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ChainCommandBlockData { - pub conditional: bool, - pub facing: ChainCommandBlockFacing, -} -impl ChainCommandBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - conditional: bool::from_snake_case(map.get("conditional")?)?, - facing: ChainCommandBlockFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("conditional".to_string(), self.conditional.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for ChainCommandBlockData { - fn default() -> Self { - Self { - conditional: false, - facing: ChainCommandBlockFacing::North, - } - } -} -impl Value for ChainCommandBlockData { - fn value(&self) -> usize { - (self.conditional.value() * 6usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let conditional = bool::from_value(val / 6usize).unwrap(); - val -= (conditional.value() - 0usize) * 6usize; - let facing = ChainCommandBlockFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - conditional, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct FrostedIceData { - pub age: i32, -} -impl FrostedIceData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for FrostedIceData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for FrostedIceData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BoneBlockData { - pub axis: BoneBlockAxis, -} -impl BoneBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - axis: BoneBlockAxis::from_snake_case(map.get("axis")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("axis".to_string(), self.axis.to_snake_case()); - m - } -} -impl Default for BoneBlockData { - fn default() -> Self { - Self { - axis: BoneBlockAxis::Y, - } - } -} -impl Value for BoneBlockData { - fn value(&self) -> usize { - (self.axis.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 3usize { - return None; - } - let axis = BoneBlockAxis::from_value(val / 1usize).unwrap(); - val -= (axis.value() - 0usize) * 1usize; - Some(Self { axis }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ObserverData { - pub powered: bool, - pub facing: ObserverFacing, -} -impl ObserverData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - powered: bool::from_snake_case(map.get("powered")?)?, - facing: ObserverFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("powered".to_string(), self.powered.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for ObserverData { - fn default() -> Self { - Self { - powered: false, - facing: ObserverFacing::South, - } - } -} -impl Value for ObserverData { - fn value(&self) -> usize { - (self.powered.value() * 6usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let powered = bool::from_value(val / 6usize).unwrap(); - val -= (powered.value() - 0usize) * 6usize; - let facing = ObserverFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { powered, facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ShulkerBoxData { - pub facing: ShulkerBoxFacing, -} -impl ShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: ShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for ShulkerBoxData { - fn default() -> Self { - Self { - facing: ShulkerBoxFacing::Up, - } - } -} -impl Value for ShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = ShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WhiteShulkerBoxData { - pub facing: WhiteShulkerBoxFacing, -} -impl WhiteShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: WhiteShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for WhiteShulkerBoxData { - fn default() -> Self { - Self { - facing: WhiteShulkerBoxFacing::Up, - } - } -} -impl Value for WhiteShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = WhiteShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OrangeShulkerBoxData { - pub facing: OrangeShulkerBoxFacing, -} -impl OrangeShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: OrangeShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for OrangeShulkerBoxData { - fn default() -> Self { - Self { - facing: OrangeShulkerBoxFacing::Up, - } - } -} -impl Value for OrangeShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = OrangeShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MagentaShulkerBoxData { - pub facing: MagentaShulkerBoxFacing, -} -impl MagentaShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: MagentaShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for MagentaShulkerBoxData { - fn default() -> Self { - Self { - facing: MagentaShulkerBoxFacing::Up, - } - } -} -impl Value for MagentaShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = MagentaShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightBlueShulkerBoxData { - pub facing: LightBlueShulkerBoxFacing, -} -impl LightBlueShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LightBlueShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LightBlueShulkerBoxData { - fn default() -> Self { - Self { - facing: LightBlueShulkerBoxFacing::Up, - } - } -} -impl Value for LightBlueShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = LightBlueShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct YellowShulkerBoxData { - pub facing: YellowShulkerBoxFacing, -} -impl YellowShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: YellowShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for YellowShulkerBoxData { - fn default() -> Self { - Self { - facing: YellowShulkerBoxFacing::Up, - } - } -} -impl Value for YellowShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = YellowShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LimeShulkerBoxData { - pub facing: LimeShulkerBoxFacing, -} -impl LimeShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LimeShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LimeShulkerBoxData { - fn default() -> Self { - Self { - facing: LimeShulkerBoxFacing::Up, - } - } -} -impl Value for LimeShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = LimeShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PinkShulkerBoxData { - pub facing: PinkShulkerBoxFacing, -} -impl PinkShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: PinkShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PinkShulkerBoxData { - fn default() -> Self { - Self { - facing: PinkShulkerBoxFacing::Up, - } - } -} -impl Value for PinkShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = PinkShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GrayShulkerBoxData { - pub facing: GrayShulkerBoxFacing, -} -impl GrayShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: GrayShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for GrayShulkerBoxData { - fn default() -> Self { - Self { - facing: GrayShulkerBoxFacing::Up, - } - } -} -impl Value for GrayShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = GrayShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightGrayShulkerBoxData { - pub facing: LightGrayShulkerBoxFacing, -} -impl LightGrayShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LightGrayShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LightGrayShulkerBoxData { - fn default() -> Self { - Self { - facing: LightGrayShulkerBoxFacing::Up, - } - } -} -impl Value for LightGrayShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = LightGrayShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CyanShulkerBoxData { - pub facing: CyanShulkerBoxFacing, -} -impl CyanShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: CyanShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for CyanShulkerBoxData { - fn default() -> Self { - Self { - facing: CyanShulkerBoxFacing::Up, - } - } -} -impl Value for CyanShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = CyanShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpleShulkerBoxData { - pub facing: PurpleShulkerBoxFacing, -} -impl PurpleShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: PurpleShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PurpleShulkerBoxData { - fn default() -> Self { - Self { - facing: PurpleShulkerBoxFacing::Up, - } - } -} -impl Value for PurpleShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = PurpleShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlueShulkerBoxData { - pub facing: BlueShulkerBoxFacing, -} -impl BlueShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BlueShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BlueShulkerBoxData { - fn default() -> Self { - Self { - facing: BlueShulkerBoxFacing::Up, - } - } -} -impl Value for BlueShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = BlueShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrownShulkerBoxData { - pub facing: BrownShulkerBoxFacing, -} -impl BrownShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BrownShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BrownShulkerBoxData { - fn default() -> Self { - Self { - facing: BrownShulkerBoxFacing::Up, - } - } -} -impl Value for BrownShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = BrownShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GreenShulkerBoxData { - pub facing: GreenShulkerBoxFacing, -} -impl GreenShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: GreenShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for GreenShulkerBoxData { - fn default() -> Self { - Self { - facing: GreenShulkerBoxFacing::Up, - } - } -} -impl Value for GreenShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = GreenShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedShulkerBoxData { - pub facing: RedShulkerBoxFacing, -} -impl RedShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: RedShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for RedShulkerBoxData { - fn default() -> Self { - Self { - facing: RedShulkerBoxFacing::Up, - } - } -} -impl Value for RedShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = RedShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlackShulkerBoxData { - pub facing: BlackShulkerBoxFacing, -} -impl BlackShulkerBoxData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BlackShulkerBoxFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BlackShulkerBoxData { - fn default() -> Self { - Self { - facing: BlackShulkerBoxFacing::Up, - } - } -} -impl Value for BlackShulkerBoxData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 6usize { - return None; - } - let facing = BlackShulkerBoxFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct WhiteGlazedTerracottaData { - pub facing: WhiteGlazedTerracottaFacing, -} -impl WhiteGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: WhiteGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for WhiteGlazedTerracottaData { - fn default() -> Self { - Self { - facing: WhiteGlazedTerracottaFacing::North, - } - } -} -impl Value for WhiteGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = WhiteGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct OrangeGlazedTerracottaData { - pub facing: OrangeGlazedTerracottaFacing, -} -impl OrangeGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: OrangeGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for OrangeGlazedTerracottaData { - fn default() -> Self { - Self { - facing: OrangeGlazedTerracottaFacing::North, - } - } -} -impl Value for OrangeGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = OrangeGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct MagentaGlazedTerracottaData { - pub facing: MagentaGlazedTerracottaFacing, -} -impl MagentaGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: MagentaGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for MagentaGlazedTerracottaData { - fn default() -> Self { - Self { - facing: MagentaGlazedTerracottaFacing::North, - } - } -} -impl Value for MagentaGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = MagentaGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightBlueGlazedTerracottaData { - pub facing: LightBlueGlazedTerracottaFacing, -} -impl LightBlueGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LightBlueGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LightBlueGlazedTerracottaData { - fn default() -> Self { - Self { - facing: LightBlueGlazedTerracottaFacing::North, - } - } -} -impl Value for LightBlueGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = LightBlueGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct YellowGlazedTerracottaData { - pub facing: YellowGlazedTerracottaFacing, -} -impl YellowGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: YellowGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for YellowGlazedTerracottaData { - fn default() -> Self { - Self { - facing: YellowGlazedTerracottaFacing::North, - } - } -} -impl Value for YellowGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = YellowGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LimeGlazedTerracottaData { - pub facing: LimeGlazedTerracottaFacing, -} -impl LimeGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LimeGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LimeGlazedTerracottaData { - fn default() -> Self { - Self { - facing: LimeGlazedTerracottaFacing::North, - } - } -} -impl Value for LimeGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = LimeGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PinkGlazedTerracottaData { - pub facing: PinkGlazedTerracottaFacing, -} -impl PinkGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: PinkGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PinkGlazedTerracottaData { - fn default() -> Self { - Self { - facing: PinkGlazedTerracottaFacing::North, - } - } -} -impl Value for PinkGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = PinkGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GrayGlazedTerracottaData { - pub facing: GrayGlazedTerracottaFacing, -} -impl GrayGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: GrayGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for GrayGlazedTerracottaData { - fn default() -> Self { - Self { - facing: GrayGlazedTerracottaFacing::North, - } - } -} -impl Value for GrayGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = GrayGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LightGrayGlazedTerracottaData { - pub facing: LightGrayGlazedTerracottaFacing, -} -impl LightGrayGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: LightGrayGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for LightGrayGlazedTerracottaData { - fn default() -> Self { - Self { - facing: LightGrayGlazedTerracottaFacing::North, - } - } -} -impl Value for LightGrayGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = LightGrayGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CyanGlazedTerracottaData { - pub facing: CyanGlazedTerracottaFacing, -} -impl CyanGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: CyanGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for CyanGlazedTerracottaData { - fn default() -> Self { - Self { - facing: CyanGlazedTerracottaFacing::North, - } - } -} -impl Value for CyanGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = CyanGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct PurpleGlazedTerracottaData { - pub facing: PurpleGlazedTerracottaFacing, -} -impl PurpleGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: PurpleGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for PurpleGlazedTerracottaData { - fn default() -> Self { - Self { - facing: PurpleGlazedTerracottaFacing::North, - } - } -} -impl Value for PurpleGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = PurpleGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlueGlazedTerracottaData { - pub facing: BlueGlazedTerracottaFacing, -} -impl BlueGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BlueGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BlueGlazedTerracottaData { - fn default() -> Self { - Self { - facing: BlueGlazedTerracottaFacing::North, - } - } -} -impl Value for BlueGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = BlueGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrownGlazedTerracottaData { - pub facing: BrownGlazedTerracottaFacing, -} -impl BrownGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BrownGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BrownGlazedTerracottaData { - fn default() -> Self { - Self { - facing: BrownGlazedTerracottaFacing::North, - } - } -} -impl Value for BrownGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = BrownGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct GreenGlazedTerracottaData { - pub facing: GreenGlazedTerracottaFacing, -} -impl GreenGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: GreenGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for GreenGlazedTerracottaData { - fn default() -> Self { - Self { - facing: GreenGlazedTerracottaFacing::North, - } - } -} -impl Value for GreenGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = GreenGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RedGlazedTerracottaData { - pub facing: RedGlazedTerracottaFacing, -} -impl RedGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: RedGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for RedGlazedTerracottaData { - fn default() -> Self { - Self { - facing: RedGlazedTerracottaFacing::North, - } - } -} -impl Value for RedGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = RedGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BlackGlazedTerracottaData { - pub facing: BlackGlazedTerracottaFacing, -} -impl BlackGlazedTerracottaData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BlackGlazedTerracottaFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BlackGlazedTerracottaData { - fn default() -> Self { - Self { - facing: BlackGlazedTerracottaFacing::North, - } - } -} -impl Value for BlackGlazedTerracottaData { - fn value(&self) -> usize { - (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let facing = BlackGlazedTerracottaFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { facing }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct KelpData { - pub age: i32, -} -impl KelpData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - age: i32::from_snake_case(map.get("age")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("age".to_string(), self.age.to_snake_case()); - m - } -} -impl Default for KelpData { - fn default() -> Self { - Self { age: 0 } - } -} -impl Value for KelpData { - fn value(&self) -> usize { - (self.age.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 26usize { - return None; - } - let age = i32::from_value(val / 1usize).unwrap(); - val -= (age.value() - 0usize) * 1usize; - Some(Self { age }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TurtleEggData { - pub eggs: i32, - pub hatch: i32, -} -impl TurtleEggData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - eggs: i32::from_snake_case(map.get("eggs")?)?, - hatch: i32::from_snake_case(map.get("hatch")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("eggs".to_string(), self.eggs.to_snake_case()); - m.insert("hatch".to_string(), self.hatch.to_snake_case()); - m - } -} -impl Default for TurtleEggData { - fn default() -> Self { - Self { eggs: 1, hatch: 0 } - } -} -impl Value for TurtleEggData { - fn value(&self) -> usize { - ((self.eggs.value() - 1) * 3usize) + (self.hatch.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 12usize { - return None; - } - let eggs = i32::from_value(val / 3usize).unwrap() + 1i32; - val -= (eggs.value() - 1usize) * 3usize; - let hatch = i32::from_value(val / 1usize).unwrap(); - val -= (hatch.value() - 0usize) * 1usize; - Some(Self { eggs, hatch }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadTubeCoralData { - pub waterlogged: bool, -} -impl DeadTubeCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadTubeCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadTubeCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadBrainCoralData { - pub waterlogged: bool, -} -impl DeadBrainCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadBrainCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadBrainCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadBubbleCoralData { - pub waterlogged: bool, -} -impl DeadBubbleCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadBubbleCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadBubbleCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadFireCoralData { - pub waterlogged: bool, -} -impl DeadFireCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadFireCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadFireCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadHornCoralData { - pub waterlogged: bool, -} -impl DeadHornCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadHornCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadHornCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TubeCoralData { - pub waterlogged: bool, -} -impl TubeCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for TubeCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for TubeCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrainCoralData { - pub waterlogged: bool, -} -impl BrainCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for BrainCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for BrainCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BubbleCoralData { - pub waterlogged: bool, -} -impl BubbleCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for BubbleCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for BubbleCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct FireCoralData { - pub waterlogged: bool, -} -impl FireCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for FireCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for FireCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct HornCoralData { - pub waterlogged: bool, -} -impl HornCoralData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for HornCoralData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for HornCoralData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadTubeCoralWallFanData { - pub facing: DeadTubeCoralWallFanFacing, - pub waterlogged: bool, -} -impl DeadTubeCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: DeadTubeCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadTubeCoralWallFanData { - fn default() -> Self { - Self { - facing: DeadTubeCoralWallFanFacing::North, - waterlogged: true, - } - } -} -impl Value for DeadTubeCoralWallFanData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let facing = DeadTubeCoralWallFanFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadBrainCoralWallFanData { - pub waterlogged: bool, - pub facing: DeadBrainCoralWallFanFacing, -} -impl DeadBrainCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: DeadBrainCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for DeadBrainCoralWallFanData { - fn default() -> Self { - Self { - waterlogged: true, - facing: DeadBrainCoralWallFanFacing::North, - } - } -} -impl Value for DeadBrainCoralWallFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = DeadBrainCoralWallFanFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadBubbleCoralWallFanData { - pub waterlogged: bool, - pub facing: DeadBubbleCoralWallFanFacing, -} -impl DeadBubbleCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: DeadBubbleCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for DeadBubbleCoralWallFanData { - fn default() -> Self { - Self { - waterlogged: true, - facing: DeadBubbleCoralWallFanFacing::North, - } - } -} -impl Value for DeadBubbleCoralWallFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = DeadBubbleCoralWallFanFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadFireCoralWallFanData { - pub facing: DeadFireCoralWallFanFacing, - pub waterlogged: bool, -} -impl DeadFireCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: DeadFireCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadFireCoralWallFanData { - fn default() -> Self { - Self { - facing: DeadFireCoralWallFanFacing::North, - waterlogged: true, - } - } -} -impl Value for DeadFireCoralWallFanData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let facing = DeadFireCoralWallFanFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadHornCoralWallFanData { - pub facing: DeadHornCoralWallFanFacing, - pub waterlogged: bool, -} -impl DeadHornCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: DeadHornCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadHornCoralWallFanData { - fn default() -> Self { - Self { - facing: DeadHornCoralWallFanFacing::North, - waterlogged: true, - } - } -} -impl Value for DeadHornCoralWallFanData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let facing = DeadHornCoralWallFanFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TubeCoralWallFanData { - pub facing: TubeCoralWallFanFacing, - pub waterlogged: bool, -} -impl TubeCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: TubeCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for TubeCoralWallFanData { - fn default() -> Self { - Self { - facing: TubeCoralWallFanFacing::North, - waterlogged: true, - } - } -} -impl Value for TubeCoralWallFanData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let facing = TubeCoralWallFanFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrainCoralWallFanData { - pub waterlogged: bool, - pub facing: BrainCoralWallFanFacing, -} -impl BrainCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: BrainCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for BrainCoralWallFanData { - fn default() -> Self { - Self { - waterlogged: true, - facing: BrainCoralWallFanFacing::North, - } - } -} -impl Value for BrainCoralWallFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = BrainCoralWallFanFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BubbleCoralWallFanData { - pub facing: BubbleCoralWallFanFacing, - pub waterlogged: bool, -} -impl BubbleCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - facing: BubbleCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for BubbleCoralWallFanData { - fn default() -> Self { - Self { - facing: BubbleCoralWallFanFacing::North, - waterlogged: true, - } - } -} -impl Value for BubbleCoralWallFanData { - fn value(&self) -> usize { - (self.facing.value() * 2usize) + (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let facing = BubbleCoralWallFanFacing::from_value(val / 2usize).unwrap(); - val -= (facing.value() - 0usize) * 2usize; - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { - facing, - waterlogged, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct FireCoralWallFanData { - pub waterlogged: bool, - pub facing: FireCoralWallFanFacing, -} -impl FireCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: FireCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for FireCoralWallFanData { - fn default() -> Self { - Self { - waterlogged: true, - facing: FireCoralWallFanFacing::North, - } - } -} -impl Value for FireCoralWallFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = FireCoralWallFanFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct HornCoralWallFanData { - pub waterlogged: bool, - pub facing: HornCoralWallFanFacing, -} -impl HornCoralWallFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - facing: HornCoralWallFanFacing::from_snake_case(map.get("facing")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("facing".to_string(), self.facing.to_snake_case()); - m - } -} -impl Default for HornCoralWallFanData { - fn default() -> Self { - Self { - waterlogged: true, - facing: HornCoralWallFanFacing::North, - } - } -} -impl Value for HornCoralWallFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 4usize) + (self.facing.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let facing = HornCoralWallFanFacing::from_value(val / 1usize).unwrap(); - val -= (facing.value() - 0usize) * 1usize; - Some(Self { - waterlogged, - facing, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadTubeCoralFanData { - pub waterlogged: bool, -} -impl DeadTubeCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadTubeCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadTubeCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadBrainCoralFanData { - pub waterlogged: bool, -} -impl DeadBrainCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadBrainCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadBrainCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadBubbleCoralFanData { - pub waterlogged: bool, -} -impl DeadBubbleCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadBubbleCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadBubbleCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadFireCoralFanData { - pub waterlogged: bool, -} -impl DeadFireCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadFireCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadFireCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct DeadHornCoralFanData { - pub waterlogged: bool, -} -impl DeadHornCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for DeadHornCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for DeadHornCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct TubeCoralFanData { - pub waterlogged: bool, -} -impl TubeCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for TubeCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for TubeCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BrainCoralFanData { - pub waterlogged: bool, -} -impl BrainCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for BrainCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for BrainCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BubbleCoralFanData { - pub waterlogged: bool, -} -impl BubbleCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for BubbleCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for BubbleCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct FireCoralFanData { - pub waterlogged: bool, -} -impl FireCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for FireCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for FireCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct HornCoralFanData { - pub waterlogged: bool, -} -impl HornCoralFanData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for HornCoralFanData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for HornCoralFanData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SeaPickleData { - pub waterlogged: bool, - pub pickles: i32, -} -impl SeaPickleData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - pickles: i32::from_snake_case(map.get("pickles")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m.insert("pickles".to_string(), self.pickles.to_snake_case()); - m - } -} -impl Default for SeaPickleData { - fn default() -> Self { - Self { - waterlogged: true, - pickles: 1, - } - } -} -impl Value for SeaPickleData { - fn value(&self) -> usize { - (self.waterlogged.value() * 4usize) + ((self.pickles.value() - 1) * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 8usize { - return None; - } - let waterlogged = bool::from_value(val / 4usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 4usize; - let pickles = i32::from_value(val / 1usize).unwrap() + 1i32; - val -= (pickles.value() - 1usize) * 1usize; - Some(Self { - waterlogged, - pickles, - }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct ConduitData { - pub waterlogged: bool, -} -impl ConduitData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - waterlogged: bool::from_snake_case(map.get("waterlogged")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("waterlogged".to_string(), self.waterlogged.to_snake_case()); - m - } -} -impl Default for ConduitData { - fn default() -> Self { - Self { waterlogged: true } - } -} -impl Value for ConduitData { - fn value(&self) -> usize { - (self.waterlogged.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let waterlogged = bool::from_value(val / 1usize).unwrap(); - val -= (waterlogged.value() - 0usize) * 1usize; - Some(Self { waterlogged }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct BubbleColumnData { - pub drag: bool, -} -impl BubbleColumnData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - drag: bool::from_snake_case(map.get("drag")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("drag".to_string(), self.drag.to_snake_case()); - m - } -} -impl Default for BubbleColumnData { - fn default() -> Self { - Self { drag: true } - } -} -impl Value for BubbleColumnData { - fn value(&self) -> usize { - (self.drag.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 2usize { - return None; - } - let drag = bool::from_value(val / 1usize).unwrap(); - val -= (drag.value() - 0usize) * 1usize; - Some(Self { drag }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct StructureBlockData { - pub mode: StructureBlockMode, -} -impl StructureBlockData { - pub fn from_map(map: &HashMap) -> Option { - Some(Self { - mode: StructureBlockMode::from_snake_case(map.get("mode")?)?, - }) - } - pub fn to_map(&self) -> HashMap { - let mut m = HashMap::new(); - m.insert("mode".to_string(), self.mode.to_snake_case()); - m - } -} -impl Default for StructureBlockData { - fn default() -> Self { - Self { - mode: StructureBlockMode::Save, - } - } -} -impl Value for StructureBlockData { - fn value(&self) -> usize { - (self.mode.value() * 1usize) - } - #[allow(warnings)] - fn from_value(mut val: usize) -> Option { - if val >= 4usize { - return None; - } - let mode = StructureBlockMode::from_value(val / 1usize).unwrap(); - val -= (mode.value() - 0usize) * 1usize; - Some(Self { mode }) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakLogAxis { - X, - Y, - Z, -} -impl Value for OakLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceLogAxis { - X, - Y, - Z, -} -impl Value for SpruceLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchLogAxis { - X, - Y, - Z, -} -impl Value for BirchLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleLogAxis { - X, - Y, - Z, -} -impl Value for JungleLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaLogAxis { - X, - Y, - Z, -} -impl Value for AcaciaLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakLogAxis { - X, - Y, - Z, -} -impl Value for DarkOakLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedSpruceLogAxis { - X, - Y, - Z, -} -impl Value for StrippedSpruceLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedBirchLogAxis { - X, - Y, - Z, -} -impl Value for StrippedBirchLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedJungleLogAxis { - X, - Y, - Z, -} -impl Value for StrippedJungleLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedAcaciaLogAxis { - X, - Y, - Z, -} -impl Value for StrippedAcaciaLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedDarkOakLogAxis { - X, - Y, - Z, -} -impl Value for StrippedDarkOakLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedOakLogAxis { - X, - Y, - Z, -} -impl Value for StrippedOakLogAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakWoodAxis { - X, - Y, - Z, -} -impl Value for OakWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceWoodAxis { - X, - Y, - Z, -} -impl Value for SpruceWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchWoodAxis { - X, - Y, - Z, -} -impl Value for BirchWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleWoodAxis { - X, - Y, - Z, -} -impl Value for JungleWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaWoodAxis { - X, - Y, - Z, -} -impl Value for AcaciaWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakWoodAxis { - X, - Y, - Z, -} -impl Value for DarkOakWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedOakWoodAxis { - X, - Y, - Z, -} -impl Value for StrippedOakWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedSpruceWoodAxis { - X, - Y, - Z, -} -impl Value for StrippedSpruceWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedBirchWoodAxis { - X, - Y, - Z, -} -impl Value for StrippedBirchWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedJungleWoodAxis { - X, - Y, - Z, -} -impl Value for StrippedJungleWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedAcaciaWoodAxis { - X, - Y, - Z, -} -impl Value for StrippedAcaciaWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StrippedDarkOakWoodAxis { - X, - Y, - Z, -} -impl Value for StrippedDarkOakWoodAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DispenserFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for DispenserFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum NoteBlockInstrument { - Harp, - Basedrum, - Snare, - Hat, - Bass, - Flute, - Bell, - Guitar, - Chime, - Xylophone, -} -impl Value for NoteBlockInstrument { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum WhiteBedPart { - Head, - Foot, -} -impl Value for WhiteBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum WhiteBedFacing { - North, - South, - West, - East, -} -impl Value for WhiteBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OrangeBedFacing { - North, - South, - West, - East, -} -impl Value for OrangeBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OrangeBedPart { - Head, - Foot, -} -impl Value for OrangeBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum MagentaBedFacing { - North, - South, - West, - East, -} -impl Value for MagentaBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum MagentaBedPart { - Head, - Foot, -} -impl Value for MagentaBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightBlueBedPart { - Head, - Foot, -} -impl Value for LightBlueBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightBlueBedFacing { - North, - South, - West, - East, -} -impl Value for LightBlueBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum YellowBedFacing { - North, - South, - West, - East, -} -impl Value for YellowBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum YellowBedPart { - Head, - Foot, -} -impl Value for YellowBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LimeBedFacing { - North, - South, - West, - East, -} -impl Value for LimeBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LimeBedPart { - Head, - Foot, -} -impl Value for LimeBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PinkBedPart { - Head, - Foot, -} -impl Value for PinkBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PinkBedFacing { - North, - South, - West, - East, -} -impl Value for PinkBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GrayBedFacing { - North, - South, - West, - East, -} -impl Value for GrayBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GrayBedPart { - Head, - Foot, -} -impl Value for GrayBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightGrayBedPart { - Head, - Foot, -} -impl Value for LightGrayBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightGrayBedFacing { - North, - South, - West, - East, -} -impl Value for LightGrayBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CyanBedFacing { - North, - South, - West, - East, -} -impl Value for CyanBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CyanBedPart { - Head, - Foot, -} -impl Value for CyanBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpleBedPart { - Head, - Foot, -} -impl Value for PurpleBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpleBedFacing { - North, - South, - West, - East, -} -impl Value for PurpleBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlueBedPart { - Head, - Foot, -} -impl Value for BlueBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlueBedFacing { - North, - South, - West, - East, -} -impl Value for BlueBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrownBedPart { - Head, - Foot, -} -impl Value for BrownBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrownBedFacing { - North, - South, - West, - East, -} -impl Value for BrownBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GreenBedFacing { - North, - South, - West, - East, -} -impl Value for GreenBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GreenBedPart { - Head, - Foot, -} -impl Value for GreenBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedBedPart { - Head, - Foot, -} -impl Value for RedBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedBedFacing { - North, - South, - West, - East, -} -impl Value for RedBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlackBedPart { - Head, - Foot, -} -impl Value for BlackBedPart { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlackBedFacing { - North, - South, - West, - East, -} -impl Value for BlackBedFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PoweredRailShape { - NorthSouth, - EastWest, - AscendingEast, - AscendingWest, - AscendingNorth, - AscendingSouth, -} -impl Value for PoweredRailShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DetectorRailShape { - NorthSouth, - EastWest, - AscendingEast, - AscendingWest, - AscendingNorth, - AscendingSouth, -} -impl Value for DetectorRailShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StickyPistonFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for StickyPistonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum TallSeagrassHalf { - Upper, - Lower, -} -impl Value for TallSeagrassHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PistonFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for PistonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PistonHeadFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for PistonHeadFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PistonHeadType { - Normal, - Sticky, -} -impl Value for PistonHeadType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum MovingPistonFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for MovingPistonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum MovingPistonType { - Normal, - Sticky, -} -impl Value for MovingPistonType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum WallTorchFacing { - North, - South, - West, - East, -} -impl Value for WallTorchFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for OakStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakStairsHalf { - Top, - Bottom, -} -impl Value for OakStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakStairsFacing { - North, - South, - West, - East, -} -impl Value for OakStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ChestFacing { - North, - South, - West, - East, -} -impl Value for ChestFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ChestType { - Single, - Left, - Right, -} -impl Value for ChestType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedstoneWireEast { - Up, - Side, - None, -} -impl Value for RedstoneWireEast { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedstoneWireNorth { - Up, - Side, - None, -} -impl Value for RedstoneWireNorth { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedstoneWireSouth { - Up, - Side, - None, -} -impl Value for RedstoneWireSouth { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedstoneWireWest { - Up, - Side, - None, -} -impl Value for RedstoneWireWest { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum FurnaceFacing { - North, - South, - West, - East, -} -impl Value for FurnaceFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakDoorFacing { - North, - South, - West, - East, -} -impl Value for OakDoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakDoorHinge { - Left, - Right, -} -impl Value for OakDoorHinge { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakDoorHalf { - Upper, - Lower, -} -impl Value for OakDoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LadderFacing { - North, - South, - West, - East, -} -impl Value for LadderFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RailShape { - NorthSouth, - EastWest, - AscendingEast, - AscendingWest, - AscendingNorth, - AscendingSouth, - SouthEast, - SouthWest, - NorthWest, - NorthEast, -} -impl Value for RailShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CobblestoneStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for CobblestoneStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CobblestoneStairsHalf { - Top, - Bottom, -} -impl Value for CobblestoneStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CobblestoneStairsFacing { - North, - South, - West, - East, -} -impl Value for CobblestoneStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum WallSignFacing { - North, - South, - West, - East, -} -impl Value for WallSignFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LeverFacing { - North, - South, - West, - East, -} -impl Value for LeverFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LeverFace { - Floor, - Wall, - Ceiling, -} -impl Value for LeverFace { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum IronDoorFacing { - North, - South, - West, - East, -} -impl Value for IronDoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum IronDoorHalf { - Upper, - Lower, -} -impl Value for IronDoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum IronDoorHinge { - Left, - Right, -} -impl Value for IronDoorHinge { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedstoneWallTorchFacing { - North, - South, - West, - East, -} -impl Value for RedstoneWallTorchFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StoneButtonFacing { - North, - South, - West, - East, -} -impl Value for StoneButtonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StoneButtonFace { - Floor, - Wall, - Ceiling, -} -impl Value for StoneButtonFace { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum NetherPortalAxis { - X, - Z, -} -impl Value for NetherPortalAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CarvedPumpkinFacing { - North, - South, - West, - East, -} -impl Value for CarvedPumpkinFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JackOLanternFacing { - North, - South, - West, - East, -} -impl Value for JackOLanternFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RepeaterFacing { - North, - South, - West, - East, -} -impl Value for RepeaterFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakTrapdoorHalf { - Top, - Bottom, -} -impl Value for OakTrapdoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakTrapdoorFacing { - North, - South, - West, - East, -} -impl Value for OakTrapdoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceTrapdoorHalf { - Top, - Bottom, -} -impl Value for SpruceTrapdoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceTrapdoorFacing { - North, - South, - West, - East, -} -impl Value for SpruceTrapdoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchTrapdoorHalf { - Top, - Bottom, -} -impl Value for BirchTrapdoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchTrapdoorFacing { - North, - South, - West, - East, -} -impl Value for BirchTrapdoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleTrapdoorFacing { - North, - South, - West, - East, -} -impl Value for JungleTrapdoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleTrapdoorHalf { - Top, - Bottom, -} -impl Value for JungleTrapdoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaTrapdoorFacing { - North, - South, - West, - East, -} -impl Value for AcaciaTrapdoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaTrapdoorHalf { - Top, - Bottom, -} -impl Value for AcaciaTrapdoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakTrapdoorHalf { - Top, - Bottom, -} -impl Value for DarkOakTrapdoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakTrapdoorFacing { - North, - South, - West, - East, -} -impl Value for DarkOakTrapdoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AttachedPumpkinStemFacing { - North, - South, - West, - East, -} -impl Value for AttachedPumpkinStemFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AttachedMelonStemFacing { - North, - South, - West, - East, -} -impl Value for AttachedMelonStemFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakFenceGateFacing { - North, - South, - West, - East, -} -impl Value for OakFenceGateFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrickStairsFacing { - North, - South, - West, - East, -} -impl Value for BrickStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrickStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for BrickStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrickStairsHalf { - Top, - Bottom, -} -impl Value for BrickStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StoneBrickStairsHalf { - Top, - Bottom, -} -impl Value for StoneBrickStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StoneBrickStairsFacing { - North, - South, - West, - East, -} -impl Value for StoneBrickStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StoneBrickStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for StoneBrickStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum NetherBrickStairsHalf { - Top, - Bottom, -} -impl Value for NetherBrickStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum NetherBrickStairsFacing { - North, - South, - West, - East, -} -impl Value for NetherBrickStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum NetherBrickStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for NetherBrickStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum EndPortalFrameFacing { - North, - South, - West, - East, -} -impl Value for EndPortalFrameFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CocoaFacing { - North, - South, - West, - East, -} -impl Value for CocoaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SandstoneStairsHalf { - Top, - Bottom, -} -impl Value for SandstoneStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SandstoneStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for SandstoneStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SandstoneStairsFacing { - North, - South, - West, - East, -} -impl Value for SandstoneStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum EnderChestFacing { - North, - South, - West, - East, -} -impl Value for EnderChestFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum TripwireHookFacing { - North, - South, - West, - East, -} -impl Value for TripwireHookFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceStairsHalf { - Top, - Bottom, -} -impl Value for SpruceStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for SpruceStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceStairsFacing { - North, - South, - West, - East, -} -impl Value for SpruceStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchStairsFacing { - North, - South, - West, - East, -} -impl Value for BirchStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for BirchStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchStairsHalf { - Top, - Bottom, -} -impl Value for BirchStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleStairsFacing { - North, - South, - West, - East, -} -impl Value for JungleStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for JungleStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleStairsHalf { - Top, - Bottom, -} -impl Value for JungleStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CommandBlockFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for CommandBlockFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakButtonFace { - Floor, - Wall, - Ceiling, -} -impl Value for OakButtonFace { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakButtonFacing { - North, - South, - West, - East, -} -impl Value for OakButtonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceButtonFace { - Floor, - Wall, - Ceiling, -} -impl Value for SpruceButtonFace { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceButtonFacing { - North, - South, - West, - East, -} -impl Value for SpruceButtonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchButtonFacing { - North, - South, - West, - East, -} -impl Value for BirchButtonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchButtonFace { - Floor, - Wall, - Ceiling, -} -impl Value for BirchButtonFace { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleButtonFacing { - North, - South, - West, - East, -} -impl Value for JungleButtonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleButtonFace { - Floor, - Wall, - Ceiling, -} -impl Value for JungleButtonFace { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaButtonFace { - Floor, - Wall, - Ceiling, -} -impl Value for AcaciaButtonFace { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaButtonFacing { - North, - South, - West, - East, -} -impl Value for AcaciaButtonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakButtonFace { - Floor, - Wall, - Ceiling, -} -impl Value for DarkOakButtonFace { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakButtonFacing { - North, - South, - West, - East, -} -impl Value for DarkOakButtonFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SkeletonWallSkullFacing { - North, - South, - West, - East, -} -impl Value for SkeletonWallSkullFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum WitherSkeletonWallSkullFacing { - North, - South, - West, - East, -} -impl Value for WitherSkeletonWallSkullFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ZombieWallHeadFacing { - North, - South, - West, - East, -} -impl Value for ZombieWallHeadFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PlayerWallHeadFacing { - North, - South, - West, - East, -} -impl Value for PlayerWallHeadFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CreeperWallHeadFacing { - North, - South, - West, - East, -} -impl Value for CreeperWallHeadFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DragonWallHeadFacing { - North, - South, - West, - East, -} -impl Value for DragonWallHeadFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AnvilFacing { - North, - South, - West, - East, -} -impl Value for AnvilFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ChippedAnvilFacing { - North, - South, - West, - East, -} -impl Value for ChippedAnvilFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DamagedAnvilFacing { - North, - South, - West, - East, -} -impl Value for DamagedAnvilFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum TrappedChestType { - Single, - Left, - Right, -} -impl Value for TrappedChestType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum TrappedChestFacing { - North, - South, - West, - East, -} -impl Value for TrappedChestFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ComparatorMode { - Compare, - Subtract, -} -impl Value for ComparatorMode { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ComparatorFacing { - North, - South, - West, - East, -} -impl Value for ComparatorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum HopperFacing { - Down, - North, - South, - West, - East, -} -impl Value for HopperFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum QuartzPillarAxis { - X, - Y, - Z, -} -impl Value for QuartzPillarAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum QuartzStairsFacing { - North, - South, - West, - East, -} -impl Value for QuartzStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum QuartzStairsHalf { - Top, - Bottom, -} -impl Value for QuartzStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum QuartzStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for QuartzStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ActivatorRailShape { - NorthSouth, - EastWest, - AscendingEast, - AscendingWest, - AscendingNorth, - AscendingSouth, -} -impl Value for ActivatorRailShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DropperFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for DropperFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaStairsHalf { - Top, - Bottom, -} -impl Value for AcaciaStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaStairsFacing { - North, - South, - West, - East, -} -impl Value for AcaciaStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for AcaciaStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for DarkOakStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakStairsHalf { - Top, - Bottom, -} -impl Value for DarkOakStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakStairsFacing { - North, - South, - West, - East, -} -impl Value for DarkOakStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum IronTrapdoorFacing { - North, - South, - West, - East, -} -impl Value for IronTrapdoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum IronTrapdoorHalf { - Top, - Bottom, -} -impl Value for IronTrapdoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PrismarineStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for PrismarineStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PrismarineStairsFacing { - North, - South, - West, - East, -} -impl Value for PrismarineStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PrismarineStairsHalf { - Top, - Bottom, -} -impl Value for PrismarineStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PrismarineBrickStairsHalf { - Top, - Bottom, -} -impl Value for PrismarineBrickStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PrismarineBrickStairsFacing { - North, - South, - West, - East, -} -impl Value for PrismarineBrickStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PrismarineBrickStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for PrismarineBrickStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkPrismarineStairsFacing { - North, - South, - West, - East, -} -impl Value for DarkPrismarineStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkPrismarineStairsHalf { - Top, - Bottom, -} -impl Value for DarkPrismarineStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkPrismarineStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for DarkPrismarineStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PrismarineSlabType { - Top, - Bottom, - Double, -} -impl Value for PrismarineSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PrismarineBrickSlabType { - Top, - Bottom, - Double, -} -impl Value for PrismarineBrickSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkPrismarineSlabType { - Top, - Bottom, - Double, -} -impl Value for DarkPrismarineSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum HayBlockAxis { - X, - Y, - Z, -} -impl Value for HayBlockAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SunflowerHalf { - Upper, - Lower, -} -impl Value for SunflowerHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LilacHalf { - Upper, - Lower, -} -impl Value for LilacHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RoseBushHalf { - Upper, - Lower, -} -impl Value for RoseBushHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PeonyHalf { - Upper, - Lower, -} -impl Value for PeonyHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum TallGrassHalf { - Upper, - Lower, -} -impl Value for TallGrassHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LargeFernHalf { - Upper, - Lower, -} -impl Value for LargeFernHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum WhiteWallBannerFacing { - North, - South, - West, - East, -} -impl Value for WhiteWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OrangeWallBannerFacing { - North, - South, - West, - East, -} -impl Value for OrangeWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum MagentaWallBannerFacing { - North, - South, - West, - East, -} -impl Value for MagentaWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightBlueWallBannerFacing { - North, - South, - West, - East, -} -impl Value for LightBlueWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum YellowWallBannerFacing { - North, - South, - West, - East, -} -impl Value for YellowWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LimeWallBannerFacing { - North, - South, - West, - East, -} -impl Value for LimeWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PinkWallBannerFacing { - North, - South, - West, - East, -} -impl Value for PinkWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GrayWallBannerFacing { - North, - South, - West, - East, -} -impl Value for GrayWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightGrayWallBannerFacing { - North, - South, - West, - East, -} -impl Value for LightGrayWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CyanWallBannerFacing { - North, - South, - West, - East, -} -impl Value for CyanWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpleWallBannerFacing { - North, - South, - West, - East, -} -impl Value for PurpleWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlueWallBannerFacing { - North, - South, - West, - East, -} -impl Value for BlueWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrownWallBannerFacing { - North, - South, - West, - East, -} -impl Value for BrownWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GreenWallBannerFacing { - North, - South, - West, - East, -} -impl Value for GreenWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedWallBannerFacing { - North, - South, - West, - East, -} -impl Value for RedWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlackWallBannerFacing { - North, - South, - West, - East, -} -impl Value for BlackWallBannerFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedSandstoneStairsFacing { - North, - South, - West, - East, -} -impl Value for RedSandstoneStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedSandstoneStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for RedSandstoneStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedSandstoneStairsHalf { - Top, - Bottom, -} -impl Value for RedSandstoneStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OakSlabType { - Top, - Bottom, - Double, -} -impl Value for OakSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceSlabType { - Top, - Bottom, - Double, -} -impl Value for SpruceSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchSlabType { - Top, - Bottom, - Double, -} -impl Value for BirchSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleSlabType { - Top, - Bottom, - Double, -} -impl Value for JungleSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaSlabType { - Top, - Bottom, - Double, -} -impl Value for AcaciaSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakSlabType { - Top, - Bottom, - Double, -} -impl Value for DarkOakSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StoneSlabType { - Top, - Bottom, - Double, -} -impl Value for StoneSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SandstoneSlabType { - Top, - Bottom, - Double, -} -impl Value for SandstoneSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PetrifiedOakSlabType { - Top, - Bottom, - Double, -} -impl Value for PetrifiedOakSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CobblestoneSlabType { - Top, - Bottom, - Double, -} -impl Value for CobblestoneSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrickSlabType { - Top, - Bottom, - Double, -} -impl Value for BrickSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StoneBrickSlabType { - Top, - Bottom, - Double, -} -impl Value for StoneBrickSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum NetherBrickSlabType { - Top, - Bottom, - Double, -} -impl Value for NetherBrickSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum QuartzSlabType { - Top, - Bottom, - Double, -} -impl Value for QuartzSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedSandstoneSlabType { - Top, - Bottom, - Double, -} -impl Value for RedSandstoneSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpurSlabType { - Top, - Bottom, - Double, -} -impl Value for PurpurSlabType { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceFenceGateFacing { - North, - South, - West, - East, -} -impl Value for SpruceFenceGateFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchFenceGateFacing { - North, - South, - West, - East, -} -impl Value for BirchFenceGateFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleFenceGateFacing { - North, - South, - West, - East, -} -impl Value for JungleFenceGateFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaFenceGateFacing { - North, - South, - West, - East, -} -impl Value for AcaciaFenceGateFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakFenceGateFacing { - North, - South, - West, - East, -} -impl Value for DarkOakFenceGateFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceDoorHinge { - Left, - Right, -} -impl Value for SpruceDoorHinge { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceDoorFacing { - North, - South, - West, - East, -} -impl Value for SpruceDoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum SpruceDoorHalf { - Upper, - Lower, -} -impl Value for SpruceDoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchDoorFacing { - North, - South, - West, - East, -} -impl Value for BirchDoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchDoorHalf { - Upper, - Lower, -} -impl Value for BirchDoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BirchDoorHinge { - Left, - Right, -} -impl Value for BirchDoorHinge { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleDoorHalf { - Upper, - Lower, -} -impl Value for JungleDoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleDoorHinge { - Left, - Right, -} -impl Value for JungleDoorHinge { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum JungleDoorFacing { - North, - South, - West, - East, -} -impl Value for JungleDoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaDoorFacing { - North, - South, - West, - East, -} -impl Value for AcaciaDoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaDoorHalf { - Upper, - Lower, -} -impl Value for AcaciaDoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum AcaciaDoorHinge { - Left, - Right, -} -impl Value for AcaciaDoorHinge { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakDoorHalf { - Upper, - Lower, -} -impl Value for DarkOakDoorHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakDoorHinge { - Left, - Right, -} -impl Value for DarkOakDoorHinge { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DarkOakDoorFacing { - North, - South, - West, - East, -} -impl Value for DarkOakDoorFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum EndRodFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for EndRodFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpurPillarAxis { - X, - Y, - Z, -} -impl Value for PurpurPillarAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpurStairsShape { - Straight, - InnerLeft, - InnerRight, - OuterLeft, - OuterRight, -} -impl Value for PurpurStairsShape { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpurStairsHalf { - Top, - Bottom, -} -impl Value for PurpurStairsHalf { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpurStairsFacing { - North, - South, - West, - East, -} -impl Value for PurpurStairsFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RepeatingCommandBlockFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for RepeatingCommandBlockFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ChainCommandBlockFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for ChainCommandBlockFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BoneBlockAxis { - X, - Y, - Z, -} -impl Value for BoneBlockAxis { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ObserverFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for ObserverFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum ShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for ShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum WhiteShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for WhiteShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OrangeShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for OrangeShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum MagentaShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for MagentaShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightBlueShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for LightBlueShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum YellowShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for YellowShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LimeShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for LimeShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PinkShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for PinkShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GrayShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for GrayShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightGrayShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for LightGrayShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CyanShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for CyanShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpleShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for PurpleShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlueShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for BlueShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrownShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for BrownShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GreenShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for GreenShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for RedShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlackShulkerBoxFacing { - North, - East, - South, - West, - Up, - Down, -} -impl Value for BlackShulkerBoxFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum WhiteGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for WhiteGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum OrangeGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for OrangeGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum MagentaGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for MagentaGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightBlueGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for LightBlueGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum YellowGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for YellowGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LimeGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for LimeGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PinkGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for PinkGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GrayGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for GrayGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum LightGrayGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for LightGrayGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum CyanGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for CyanGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum PurpleGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for PurpleGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlueGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for BlueGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrownGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for BrownGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum GreenGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for GreenGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum RedGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for RedGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BlackGlazedTerracottaFacing { - North, - South, - West, - East, -} -impl Value for BlackGlazedTerracottaFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DeadTubeCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for DeadTubeCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DeadBrainCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for DeadBrainCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DeadBubbleCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for DeadBubbleCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DeadFireCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for DeadFireCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum DeadHornCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for DeadHornCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum TubeCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for TubeCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BrainCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for BrainCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum BubbleCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for BubbleCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum FireCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for FireCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum HornCoralWallFanFacing { - North, - South, - West, - East, -} -impl Value for HornCoralWallFanFacing { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] -pub enum StructureBlockMode { - Save, - Load, - Corner, - Data, -} -impl Value for StructureBlockMode { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option { - Self::from_usize(val) - } -} diff --git a/blocks/src/lib.rs b/blocks/src/lib.rs deleted file mode 100644 index 4f893625a..000000000 --- a/blocks/src/lib.rs +++ /dev/null @@ -1,338 +0,0 @@ -//! The block system used by Feather is a rather -//! complex topic. -//! -//! There are three different sets of block state IDs, -//! native IDs, internal IDs, and versioned IDs. -//! -//! Native IDs are the block state IDs used by the Minecraft -//! version corresponding to Feather's "native" version, 1.13.2. -//! Native IDs are used across the codebase—for example, the `Chunk` -//! struct in `feather_core` uses native IDs to store blocks. -//! -//! "Internal" IDs are only used inside the `feather_blocks` crate. -//! The benefit of internal IDs is that they are calculated based on -//! the block's data in constant time - there is no need for any sort -//! of lookup. As a result, these internal IDs are used to find versioned and native IDs -//! in a vector. (The internal ID is used as an index into the vector, allowing -//! for efficient constant-time lookup). -//! -//! Versioned IDs mean any set of block state IDs used by Minecraft versions -//! other than the native version (1.13.2). For example, when a Chunk Data packet -//! is sent to a non-native client (e.g. a client on 1.14.4), the block state IDs -//! in the chunk need to be converted to 1.14.4 block state IDs, which may differ -//! from those in the native version. As a result, `feather_blocks` also provides -//! functions to efficiently convert native IDs to versioned IDs. - -#![forbid(unsafe_code)] - -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate failure; -#[macro_use] -extern crate num_derive; - -#[allow(clippy::all)] // No, generated code isn't idiomatic. Too bad -mod blocks; -mod mappings; - -use crate::mappings::NativeMappings; -pub use blocks::*; -use std::collections::HashMap; -use std::hash::Hash; - -const MAPPINGS_1_13_2: &[u8] = include_bytes!("../data/1.13.2.dat"); -//const MAPPINGS_1_14_4: &[u8] = include_bytes!("../data/1.14.4.dat"); - -const P1_13_2: u32 = 404; -//const P1_14_4: u32 = 498; - -lazy_static! { - static ref NATIVE_MAPPINGS: NativeMappings = - { mappings::load_native(MAPPINGS_1_13_2).unwrap() }; - static ref INTERNAL_TO_NATIVE: Vec = { init_native_id_mappings(&NATIVE_MAPPINGS).0 }; - static ref NATIVE_TO_INTERNAL: Vec = { init_native_id_mappings(&NATIVE_MAPPINGS).1 }; -} - -pub trait BlockExt { - fn from_state_id(id: u16, proto_version: u32) -> Option - where - Self: Sized; - fn from_native_state_id(id: u16) -> Option - where - Self: Sized; - fn state_id(&self, proto_version: u32) -> u16; - - fn native_state_id(&self) -> u16; - - /// Returns whether this block is "solid." - fn is_solid(&self) -> bool; - - /// Returns whether this block is opaque; i.e., whether - /// light will be stopped by this block. - fn is_opaque(&self) -> bool; - - /// Returns the light level emitted by this block. - fn light_emission(&self) -> u8; -} - -impl BlockExt for Block { - fn from_state_id(_id: u16, _proto_version: u32) -> Option { - unimplemented!() - } - - fn from_native_state_id(id: u16) -> Option { - if id as usize >= NATIVE_TO_INTERNAL.len() { - return None; - } - - let internal = NATIVE_TO_INTERNAL[id as usize]; - Block::from_internal_state_id(internal as usize) - } - - fn state_id(&self, proto_version: u32) -> u16 { - let internal = self.internal_state_id(); - match proto_version { - P1_13_2 => INTERNAL_TO_NATIVE[internal], - _ => panic!("Invalid protocol version {}", proto_version), - } - } - - fn native_state_id(&self) -> u16 { - let internal = self.internal_state_id(); - INTERNAL_TO_NATIVE[internal] - } - - fn is_solid(&self) -> bool { - // TODO: there are likely a few missing in this list - match self { - Block::Air - | Block::OakSapling(_) - | Block::SpruceSapling(_) - | Block::BirchSapling(_) - | Block::JungleSapling(_) - | Block::AcaciaSapling(_) - | Block::DarkOakSapling(_) - | Block::Water(_) - | Block::Lava(_) - | Block::Grass - | Block::Fern - | Block::DeadBush - | Block::Seagrass - | Block::TallSeagrass(_) - | Block::Dandelion - | Block::Poppy - | Block::BlueOrchid - | Block::Allium - | Block::AzureBluet - | Block::RedTulip - | Block::OrangeTulip - | Block::WhiteTulip - | Block::PinkTulip - | Block::OxeyeDaisy - | Block::BrownMushroom - | Block::RedMushroom - | Block::Torch - | Block::WallTorch(_) - | Block::Fire(_) - | Block::Wheat(_) - | Block::Sign(_) - | Block::Ladder(_) - | Block::Rail(_) - | Block::WallSign(_) - | Block::Lever(_) - | Block::StonePressurePlate(_) - | Block::OakPressurePlate(_) - | Block::SprucePressurePlate(_) - | Block::BirchPressurePlate(_) - | Block::JunglePressurePlate(_) - | Block::AcaciaPressurePlate(_) - | Block::DarkOakPressurePlate(_) - | Block::RedstoneTorch(_) - | Block::RedstoneWallTorch(_) - | Block::StoneButton(_) - | Block::Snow(_) - | Block::SugarCane(_) - | Block::Repeater(_) - | Block::AttachedMelonStem(_) - | Block::AttachedPumpkinStem(_) - | Block::MelonStem(_) - | Block::PumpkinStem(_) - | Block::Vine(_) - | Block::Carrots(_) - | Block::Potatoes(_) - | Block::OakButton(_) - | Block::SpruceButton(_) - | Block::BirchButton(_) - | Block::JungleButton(_) - | Block::AcaciaButton(_) - | Block::DarkOakButton(_) - | Block::LightWeightedPressurePlate(_) - | Block::HeavyWeightedPressurePlate(_) - | Block::Comparator(_) - | Block::WhiteCarpet - | Block::OrangeCarpet - | Block::MagentaCarpet - | Block::LightBlueCarpet - | Block::YellowCarpet - | Block::LimeCarpet - | Block::PinkCarpet - | Block::GrayCarpet - | Block::LightGrayCarpet - | Block::CyanCarpet - | Block::PurpleCarpet - | Block::BlueCarpet - | Block::BrownCarpet - | Block::GreenCarpet - | Block::RedCarpet - | Block::BlackCarpet - | Block::Sunflower(_) - | Block::Lilac(_) - | Block::RoseBush(_) - | Block::Peony(_) - | Block::TallGrass(_) - | Block::LargeFern(_) - | Block::Kelp(_) - | Block::KelpPlant - | Block::DriedKelpBlock - | Block::VoidAir - | Block::CaveAir => false, - _ => true, - } - } - - fn is_opaque(&self) -> bool { - if !self.is_solid() { - return false; - } - - // TODO - match self { - Block::Air | Block::Glass | Block::GlassPane(_) | Block::IronBars(_) => false, - _ => true, - } - } - - fn light_emission(&self) -> u8 { - match self { - Block::Beacon - | Block::EndGateway - | Block::EndPortal - | Block::Fire(_) - | Block::Glowstone - | Block::JackOLantern(_) - | Block::Lava(_) - | Block::RedstoneLamp(RedstoneLampData { lit: true }) - | Block::SeaLantern - | Block::SeaPickle(SeaPickleData { - waterlogged: true, - pickles: 4, - }) - | Block::Conduit(_) => 15, - Block::EndRod(_) | Block::Torch => 14, - Block::Furnace(_) => 13, - Block::SeaPickle(SeaPickleData { - waterlogged: true, - pickles: 3, - }) => 12, - Block::NetherPortal(_) => 11, - Block::SeaPickle(SeaPickleData { - waterlogged: true, - pickles: 2, - }) => 9, - Block::EnderChest(_) | Block::RedstoneTorch(_) => 7, - Block::SeaPickle(SeaPickleData { - waterlogged: true, - pickles: 1, - }) => 6, - Block::MagmaBlock => 3, - Block::BrewingStand(_) - | Block::BrownMushroom - | Block::DragonEgg - | Block::EndPortalFrame(_) => 1, - _ => 0, - } - } -} - -/// Creates the internal ID -> native ID -/// mappings vector, where indices into the -/// vector are internal IDs and the values in the vector -/// are native IDs. -/// -/// Also creates the opposite vector - native IDs -> internal IDs. -fn init_native_id_mappings(mappings: &NativeMappings) -> (Vec, Vec) { - let mut internal_to_native = vec![1; mappings.blocks.len()]; - let mut native_to_internal = vec![1; mappings.blocks.len()]; - - for ((name, props), native_id) in mappings.blocks.clone() { - let block = Block::from_name_and_props(&name, &vec_to_hash_map(props)).unwrap(); - let internal_id = block.internal_state_id() as u16; - - // Confirm we're not overwriting - assert_eq!(internal_to_native[internal_id as usize], 1); - assert_eq!(native_to_internal[native_id as usize], 1); - - internal_to_native[internal_id as usize] = native_id; - native_to_internal[native_id as usize] = internal_id; - } - - (internal_to_native, native_to_internal) -} - -fn vec_to_hash_map(vec: Vec<(K, V)>) -> HashMap -where - K: Eq + Hash, -{ - let mut result = HashMap::new(); - for entry in vec { - result.insert(entry.0, entry.1); - } - - result -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::blocks::GrassBlockData; - - #[test] - fn test_native_state_id() { - let block = Block::Stone; - assert_eq!(block.native_state_id(), 1); - - let block = Block::GrassBlock(GrassBlockData { snowy: true }); - assert_eq!(block.native_state_id(), 8); - } - - #[test] - fn test_lots_of_blocks() { - for id in 0..8595 { - let block = Block::from_native_state_id(id).unwrap(); - assert_eq!(block.native_state_id(), id); - } - } - - #[test] - fn test_default_props() { - assert_eq!( - Block::from_name_and_default_props("minecraft:grass_block").unwrap(), - Block::GrassBlock(GrassBlockData { snowy: false }) - ); - } - - #[test] - fn test_to_name_and_props() { - let block = Block::GrassBlock(GrassBlockData { snowy: true }); - - let (name, props) = block.to_name_and_props(); - - assert_eq!(name, "minecraft:grass_block"); - assert_eq!(props.len(), 1); - let (prop_name, prop_value) = props.first().unwrap(); - - assert_eq!(*prop_name, "snowy"); - assert_eq!(prop_value, "true"); - } -} diff --git a/blocks/src/mappings.rs b/blocks/src/mappings.rs deleted file mode 100644 index 7ceeb73f4..000000000 --- a/blocks/src/mappings.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! Module for reading from block mappings files. -use byteorder::{LittleEndian, ReadBytesExt}; -use failure::Error; -use std::collections::HashMap; -use std::io::{Cursor, Read}; - -pub type NativeBlockIdentifier = (String, Vec<(String, String)>); - -#[derive(Debug, Fail)] -pub enum MappingsError { - #[fail(display = "file did not start with magic string")] - BadHeader, - #[fail(display = "invalid boolean value")] - InvalidBoolean, - #[fail(display = "mismatched header - wrong native field")] - MismatchedHeader, -} - -#[derive(Clone, Debug)] -pub struct NativeMappings { - pub version: String, - pub proto: u32, - pub blocks: HashMap, -} - -/// Loads a native mappings file. -pub fn load_native(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - - let header = read_header(&mut cursor)?; - - if !header.is_native { - return Err(MappingsError::MismatchedHeader.into()); - } - - // Read number of mappings - let len = cursor.read_u32::()?; - - let mut blocks = HashMap::with_capacity(len as usize); - - // Read mappings - for _ in 0..len { - // Read mapping - let block_name = cursor.read_string()?; - - // Read properties - let num_props = cursor.read_u32::()?; - let mut props = vec![]; - - for _ in 0..num_props { - let key = cursor.read_string()?; - let value = cursor.read_string()?; - props.push((key, value)); - } - - let identifier = (block_name, props); - blocks.insert(identifier, cursor.read_u16::()?); - } - - Ok(NativeMappings { - version: header.version, - proto: header.proto, - blocks, - }) -} - -#[derive(Clone, Debug)] -pub struct VersionedMappings { - pub version: String, - pub proto: u32, - pub blocks: HashMap, -} - -/// Loads a versioned mappings file. -pub fn _load_versioned(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - - let header = read_header(&mut cursor)?; - - if header.is_native { - return Err(MappingsError::MismatchedHeader.into()); - } - - // Load blocks - let len = cursor.read_u32::()?; - let mut blocks = HashMap::new(); - - for _ in 0..len { - let native_id = cursor.read_u16::()?; - let versioned_id = cursor.read_u16::()?; - blocks.insert(native_id, versioned_id); - } - - Ok(VersionedMappings { - version: header.version, - proto: header.proto, - blocks, - }) -} - -#[derive(Clone, Debug)] -struct Header { - version: String, - proto: u32, - is_native: bool, -} - -const MAGIC_STRING: &str = "FEATHER_BLOCK_DATA_FILE"; - -fn read_header(cursor: &mut Cursor<&[u8]>) -> Result { - let mut buf = vec![0; MAGIC_STRING.len()]; - cursor.read_exact(&mut buf)?; - - let magic = String::from_utf8(buf)?; - if magic != MAGIC_STRING { - return Err(MappingsError::BadHeader.into()); - } - - let version = cursor.read_string()?; - let proto = cursor.read_u32::()?; - let is_native = match cursor.read_u8()? { - 0 => false, - 1 => true, - _ => return Err(MappingsError::InvalidBoolean.into()), - }; - - Ok(Header { - version, - proto, - is_native, - }) -} - -trait ReadExt { - fn read_string(&mut self) -> Result; -} - -impl ReadExt for R { - fn read_string(&mut self) -> Result { - let len = self.read_u32::()?; - let mut buf = vec![0; len as usize]; - - self.read_exact(&mut buf)?; - - Ok(String::from_utf8(buf)?) - } -} diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml deleted file mode 100644 index 3e516584f..000000000 --- a/codegen/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "feather-codegen" -version = "0.5.0" -authors = ["caelunshun "] -edition = "2018" - -[lib] -proc-macro = true - -[dependencies] -syn = { version = "1.0", features = ["full", "extra-traits", "derive"] } -quote = "1.0" -proc-macro2 = "1.0" -lazy_static = "1.4" -heck = "0.3" -strum = "0.16" -strum_macros = "0.16" diff --git a/codegen/src/entity_metadata.rs b/codegen/src/entity_metadata.rs deleted file mode 100644 index 7ca93243e..000000000 --- a/codegen/src/entity_metadata.rs +++ /dev/null @@ -1,335 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro2::Ident; -use proc_macro2::Span; -use quote::quote; -use std::collections::HashMap; -use syn::braced; -use syn::parenthesized; -use syn::parse::{Parse, ParseBuffer}; -use syn::Error; -use syn::Lit; -use syn::Token; - -#[derive(Clone)] -struct EntityMetadata { - ident: Ident, - variants: HashMap, -} - -impl Parse for EntityMetadata { - fn parse(input: &ParseBuffer) -> Result { - let ident = input.parse()?; - - input.parse::()?; - - let mut variants = HashMap::new(); - while let Ok(variant) = input.parse::() { - variants.insert(variant.ident.clone(), variant); - - input.parse::()?; - } - - Ok(Self { ident, variants }) - } -} - -#[derive(Clone)] -struct Variant { - ident: Ident, - extends: Option, - entries: Vec, -} - -impl Parse for Variant { - fn parse(input: &ParseBuffer) -> Result { - let ident = input.parse()?; - - let extends = if input.parse::().is_ok() { - let ident = input.parse()?; - Some(ident) - } else { - None - }; - - let content; - braced!(content in input); - - let mut entries = vec![]; - - while let Ok(entry) = content.parse::() { - entries.push(entry); - } - - Ok(Self { - ident, - extends, - entries, - }) - } -} - -#[derive(Clone)] -struct Entry { - ty: EntryType, - name: Ident, - index: u8, - default: Option, -} - -impl Parse for Entry { - fn parse(input: &ParseBuffer) -> Result { - let name = input.parse()?; - let _ = input.parse::()?; - let ty = input.parse()?; - - let paren; - parenthesized!(paren in input); - let default = match paren.parse() { - Ok(val) => Some(val), - Err(_) => None, - }; - - let _ = input.parse::()?; - - let index = match input.parse::()? { - Lit::Int(val) => val.base10_parse()?, - _ => panic!("Index not a `u8`"), - }; - - let _ = input.parse::()?; - - Ok(Self { - ty, - name, - index, - default, - }) - } -} - -#[derive(PartialEq, Debug, Display, EnumString, Copy, Clone)] -enum EntryType { - Byte, - VarInt, - Float, - String, - Slot, - Boolean, - OptUuid, - Position, -} - -impl Parse for EntryType { - fn parse(input: &ParseBuffer) -> Result { - let ty = input.parse::()?; - - Ok(EntryType::from_rust_type(&ty.to_string())) - } -} - -impl EntryType { - fn rust_type(self) -> &'static str { - match self { - EntryType::Byte => "u8", - EntryType::VarInt => "i32", - EntryType::Float => "f32", - EntryType::String => "String", - EntryType::Slot => "Slot", - EntryType::Boolean => "bool", - EntryType::OptUuid => "OptUuid", - EntryType::Position => "BlockPosition", - } - } - - fn from_rust_type(ty: &str) -> Self { - match ty { - "u8" => EntryType::Byte, - "VarInt" => EntryType::VarInt, - "f32" => EntryType::Float, - "String" => EntryType::String, - "bool" => EntryType::Boolean, - "Slot" => EntryType::Slot, - "OptUuid" => EntryType::OptUuid, - "BlockPosition" => EntryType::Position, - _ => panic!("Invalid entry type {}", ty), - } - } -} - -#[allow(clippy::cognitive_complexity)] // FIXME: clean this function up -pub fn entity_metadata(input: TokenStream) -> TokenStream { - let input: EntityMetadata = syn::parse_macro_input!(input); - - let mut structs = vec![]; - let mut enum_variants = vec![]; - - let mut to_raw_metadata_arms = vec![]; - let mut to_full_raw_metadata_arms = vec![]; - - let enum_ident = input.ident.clone(); - - for variant in input.variants.values() { - let entries = get_metadata_entries(&input, variant.clone()); - - let variant_ident = &variant.ident; - - let mut struct_fields = vec![]; - let mut struct_impl = vec![]; - let mut to_raw_metadata = vec![]; - let mut to_full_raw_metadata = vec![]; - - let mut new_fn_parameters = vec![]; - let mut new_fn_contents = vec![]; - - let mut default_entries = vec![]; - - for entry in entries { - let entry_ident = entry.name; - let ty_enum = entry.ty; - let ty = ty_enum.rust_type(); - let ty_ident = Ident::new(ty, Span::call_site()); - - let is_dirty_name = format!("__is_dirty_{}", entry_ident); - let is_dirty_ident = Ident::new(&is_dirty_name, Span::call_site()); - - struct_fields.push(quote! { - #entry_ident: #ty_ident, - #is_dirty_ident: bool, - }); - - let set_fn_ident = Ident::new(&format!("set_{}", entry_ident), Span::call_site()); - let get_fn_ident = entry_ident.clone(); - - struct_impl.push(quote! { - pub fn #set_fn_ident(&mut self, val: #ty_ident) { - self.#entry_ident = val; - self.#is_dirty_ident = true; - } - - pub fn #get_fn_ident(&self) -> #ty_ident { - self.#entry_ident.clone() - } - }); - - let pass_reference = ty_enum == EntryType::Slot; - - let index = entry.index; - let set_expr = if pass_reference { - quote! { meta.set(#index, self.#entry_ident.clone()); } - } else { - quote! { meta.set(#index, self.#entry_ident); } - }; - to_raw_metadata.push(quote! { - if self.#is_dirty_ident { - #set_expr - self.#is_dirty_ident = false; - } - }); - to_full_raw_metadata.push(quote! { - #set_expr - }); - - new_fn_parameters.push(quote! { - #entry_ident: #ty_ident - }); - - new_fn_contents.push(quote! { - #entry_ident, - #is_dirty_ident: true, - }); - - to_raw_metadata_arms.push(quote! { - #enum_ident::#variant_ident(meta) => meta.to_raw_metadata(), - }); - - to_full_raw_metadata_arms.push(quote! { - #enum_ident::#variant_ident(meta) => meta.to_full_raw_metadata(), - }); - - default_entries.push(match entry.default { - Some(default) => quote! { #entry_ident: #default, #is_dirty_ident: false, }, - None => quote! { #entry_ident: Default::default(), #is_dirty_ident: false, }, - }); - } - - struct_impl.push(quote! { - pub fn new(#(#new_fn_parameters),*) -> Self { - Self { - #(#new_fn_contents)* - } - } - - fn to_raw_metadata(&mut self) -> EntityMetadata { - let mut meta = EntityMetadata::new(); - #(#to_raw_metadata)* - meta - } - - fn to_full_raw_metadata(&self) -> EntityMetadata { - let mut meta = EntityMetadata::new(); - #(#to_full_raw_metadata)* - meta - } - }); - - structs.push(quote! { - #[derive(Clone, Debug)] - pub struct #variant_ident { - #(#struct_fields)* - } - - impl #variant_ident { - #(#struct_impl)* - } - - impl Default for #variant_ident { - fn default() -> Self { - Self { - #(#default_entries)* - } - } - } - }); - - enum_variants.push(quote! { - #variant_ident(#variant_ident), - }) - } - - let result = quote! { - #[derive(Clone, Debug)] - pub enum #enum_ident { - #(#enum_variants)* - } - - impl #enum_ident { - pub fn to_raw_metadata(&mut self) -> EntityMetadata { - match self { - #(#to_raw_metadata_arms)* - } - } - - pub fn to_full_raw_metadata(&self) -> EntityMetadata { - match self { - #(#to_full_raw_metadata_arms)* - } - } - } - - #(#structs)* - }; - - result.into() -} - -fn get_metadata_entries(metadata: &EntityMetadata, variant: Variant) -> Vec { - let mut entries = vec![]; - - if let Some(inherits_from) = variant.extends.as_ref() { - let inherits_from = &metadata.variants[inherits_from]; - entries.extend(get_metadata_entries(metadata, inherits_from.clone()).into_iter()); - } - - entries.extend(variant.entries.into_iter()); - entries -} diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs deleted file mode 100644 index ab6f68331..000000000 --- a/codegen/src/lib.rs +++ /dev/null @@ -1,292 +0,0 @@ -extern crate proc_macro; - -#[macro_use] -extern crate strum_macros; - -mod entity_metadata; - -use heck::SnakeCase; -use lazy_static::lazy_static; -use proc_macro::TokenStream; -use quote::quote; -use std::collections::HashMap; -use syn::export::Span; -use syn::Data; -use syn::Ident; -use syn::Type; -use syn::{parse_macro_input, DeriveInput}; - -#[proc_macro_derive(AsAny)] -pub fn derive_as_any(_item: TokenStream) -> TokenStream { - let parsed: DeriveInput = parse_macro_input!(_item as DeriveInput); - - let name = &parsed.ident; - - let result = quote! { - impl AsAny for #name { - fn as_any(&self) -> &Any { - self - } - } - }; - - result.into() -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -enum PacketParameterType { - Varint, - Varlong, - String, - U64, - U32, - U16, - U8, - I64, - I32, - I16, - I8, - Position, - Boolean, - F32, - F64, - Uuid, - Nbt, - Slot, - EntityMetadata, -} - -lazy_static! { - static ref PARAMETER_MAPPINGS: HashMap<&'static str, PacketParameterType> = { - let mut m = HashMap::new(); - - m.insert("VarInt", PacketParameterType::Varint); - m.insert("VarLong", PacketParameterType::Varlong); - m.insert("String", PacketParameterType::String); - m.insert("u64", PacketParameterType::U64); - m.insert("u32", PacketParameterType::U32); - m.insert("u16", PacketParameterType::U16); - m.insert("u8", PacketParameterType::U8); - m.insert("i64", PacketParameterType::I64); - m.insert("i32", PacketParameterType::I32); - m.insert("i16", PacketParameterType::I16); - m.insert("i8", PacketParameterType::I8); - m.insert("BlockPosition", PacketParameterType::Position); - m.insert("bool", PacketParameterType::Boolean); - m.insert("f32", PacketParameterType::F32); - m.insert("f64", PacketParameterType::F64); - m.insert("Uuid", PacketParameterType::Uuid); - m.insert("NbtTag", PacketParameterType::Nbt); - m.insert("Slot", PacketParameterType::Slot); - m.insert("EntityMetadata", PacketParameterType::EntityMetadata); - - m - }; - - static ref FUNCTION_MAPPINGS: HashMap = { - let mut m = HashMap::new(); - - m.insert("var_int", PacketParameterType::Varint); - m.insert("var_long", PacketParameterType::Varlong); - m.insert("string", PacketParameterType::String); - m.insert("u64", PacketParameterType::U64); - m.insert("u32", PacketParameterType::U32); - m.insert("u16", PacketParameterType::U16); - m.insert("u8", PacketParameterType::U8); - m.insert("i64", PacketParameterType::I64); - m.insert("i32", PacketParameterType::I32); - m.insert("i16", PacketParameterType::I16); - m.insert("i8", PacketParameterType::I8); - m.insert("position", PacketParameterType::Position); - m.insert("bool", PacketParameterType::Boolean); - m.insert("f32", PacketParameterType::F32); - m.insert("f64", PacketParameterType::F64); - m.insert("uuid", PacketParameterType::Uuid); - m.insert("nbt", PacketParameterType::Nbt); - m.insert("slot", PacketParameterType::Slot); - m.insert("metadata", PacketParameterType::EntityMetadata); - - // I wrote them in the wrong order, so I'm just going to reverse - // the map. - let mut reversed = HashMap::new(); - - for (key, value) in m { - reversed.insert(value, key); - } - - reversed - }; -} - -#[proc_macro_derive(Packet)] -pub fn derive_packet(_item: TokenStream) -> TokenStream { - let item: DeriveInput = parse_macro_input!(_item as DeriveInput); - - let ident = item.ident.clone(); - - let fields = match &item.data { - Data::Struct(st) => &st.fields, - _ => panic!("Not a struct"), - }; - - let mut write_code = vec![]; - let mut read_code = vec![]; - - for field in fields { - let field_name = field.ident.as_ref().unwrap(); - let ty = match &field.ty { - Type::Path(path) => &path.path.segments, - _ => panic!("Not a path field"), - }; - - if ty.len() != 1 { - panic!("Must not use paths"); - } - - let ty_ident = &ty.first().unwrap().ident; - - let parameter_type = PARAMETER_MAPPINGS - .get(ty_ident.to_string().as_str()) - .unwrap_or_else(|| { - panic!( - "Couldn't find packet parameter type corresponding to {}", - ty_ident - ) - }); - let function_ident = Ident::new( - FUNCTION_MAPPINGS.get(parameter_type).unwrap(), - Span::call_site(), - ); - - let write_fn_ident = Ident::new(&format!("push_{}", function_ident), Span::call_site()); - let read_fn_ident = Ident::new(&format!("try_get_{}", function_ident), Span::call_site()); - - let use_ref = { - vec![ - PacketParameterType::Position, - PacketParameterType::String, - PacketParameterType::Uuid, - PacketParameterType::Nbt, - PacketParameterType::Slot, - PacketParameterType::EntityMetadata, - ] - .contains(parameter_type) - }; - - let write; - - if use_ref { - write = quote! { - buf.#write_fn_ident(&self.#field_name); - }; - } else { - write = quote! { - buf.#write_fn_ident(self.#field_name); - } - } - - let read; - - read = quote! { - self.#field_name = buf.#read_fn_ident()?; - }; - - write_code.push(write); - read_code.push(read); - } - - let r = quote! { - impl Packet for #ident { - fn read_from(&mut self, mut buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - #(#read_code)* - Ok(()) - } - - fn write_to(&self, buf: &mut BytesMut) { - #(#write_code)* - } - - fn ty(&self) -> PacketType { - PacketType::#ident - } - - fn box_clone(&self) -> Box { - Box::new((*self).clone()) - } - } - }; - - r.into() -} - -#[proc_macro_derive(FromSnakeCase)] -pub fn derive_from_snake_case(input: TokenStream) -> TokenStream { - let input: syn::DeriveInput = syn::parse(input).unwrap(); - let name = &input.ident; - - let mut match_arms = vec![]; - - match &input.data { - syn::Data::Enum(en) => { - for variant in &en.variants { - let snake_case = variant.ident.to_string().to_snake_case(); - let ident = &variant.ident; - match_arms.push(quote! { - #snake_case => Some(#name::#ident) - }); - } - } - _ => panic!("Can only derive `FromSnakeCase` on enums"), - } - - let result = quote! { - impl FromSnakeCase for #name { - fn from_snake_case(val: &str) -> Option { - match val { - #(#match_arms ,)* - _ => None, - } - } - } - }; - - result.into() -} - -#[proc_macro_derive(ToSnakeCase)] -pub fn derive_to_snake_case(input: TokenStream) -> TokenStream { - let input: syn::DeriveInput = syn::parse(input).unwrap(); - let name = &input.ident; - - let mut match_arms = vec![]; - - match &input.data { - syn::Data::Enum(en) => { - for variant in &en.variants { - let snake_case = variant.ident.to_string().to_snake_case(); - let ident = &variant.ident; - match_arms.push(quote! { - #name::#ident => #snake_case.to_string() - }); - } - } - _ => panic!("Can only derive `ToSnakeCase` on enums"), - } - - let result = quote! { - impl ToSnakeCase for #name { - fn to_snake_case(&self) -> String { - match self { - #(#match_arms),* - } - } - } - }; - - result.into() -} - -#[proc_macro] -pub fn entity_metadata(input: TokenStream) -> TokenStream { - entity_metadata::entity_metadata(input) -} diff --git a/core/Cargo.toml b/core/Cargo.toml deleted file mode 100644 index 1e0549076..000000000 --- a/core/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "feather-core" -version = "0.5.0" -authors = ["caelunshun "] -edition = "2018" -publish = false - -[dependencies] -feather-codegen = { path = "../codegen" } -feather-blocks = { path = "../blocks" } -feather-items = { path = "../items" } -lazy_static = "1.4" -derive-new = "0.5" -uuid = "0.7" -cfb8 = "0.3" -aes = "0.3" -flate2 = "1.0" -bytes = "0.4" -log = "0.4" -serde = { version = "1.0", features = ["derive"] } -num-traits = "0.2" -num-derive = "0.3" -hashbrown = { version = "0.6", features = ["serde"] } -hematite-nbt = "0.4" -byteorder = "1.3" -nalgebra-glm = "0.4" -derive_more = "0.15" -smallvec = "0.6" -hash32 = "0.1" -hash32-derive = "0.1" -strum = "0.16" -strum_macros = "0.16" -tokio = "=0.2.0-alpha.6" -failure = "0.1" -bitvec = "0.15" -multimap = "0.6" diff --git a/core/src/bytes_ext.rs b/core/src/bytes_ext.rs deleted file mode 100644 index ff2142d66..000000000 --- a/core/src/bytes_ext.rs +++ /dev/null @@ -1,157 +0,0 @@ -use bytes::{Buf, BufMut, BytesMut}; - -/// An error which occurred while attempting -/// to get a value from a `Buf.` -#[derive(Clone, Copy, Debug, PartialEq, Eq, Fail)] -pub enum TryGetError { - /// Indicates that there were not enough remaining - /// bytes in the buffer to read a value. - #[fail(display = "not enough bytes left in buffer")] - NotEnoughBytes, - #[fail(display = "value too large")] - ValueTooLarge, - #[fail(display = "invalid value")] - InvalidValue, -} - -type Result = std::result::Result; - -/// Ext trait for `Bytes` to allow `try_get` operations. -/// -/// All operations are big-endian. -pub trait BytesExt { - fn try_get_i8(&mut self) -> Result; - fn try_get_i16(&mut self) -> Result; - fn try_get_i32(&mut self) -> Result; - fn try_get_i64(&mut self) -> Result; - - fn try_get_f32(&mut self) -> Result; - fn try_get_f64(&mut self) -> Result; - - fn try_get_u8(&mut self) -> Result; - fn try_get_u16(&mut self) -> Result; - fn try_get_u32(&mut self) -> Result; - fn try_get_u64(&mut self) -> Result; -} - -macro_rules! try_get_impl { - ($this:ident, $size:expr, $method:ident) => {{ - if $this.remaining() < $size { - return Err(TryGetError::NotEnoughBytes); - } - - return Ok($this.$method()); - }}; -} - -impl BytesExt for B { - fn try_get_i8(&mut self) -> Result { - try_get_impl!(self, 1, get_i8); - } - - fn try_get_i16(&mut self) -> Result { - try_get_impl!(self, 2, get_i16_be); - } - - fn try_get_i32(&mut self) -> Result { - try_get_impl!(self, 4, get_i32_be); - } - - fn try_get_i64(&mut self) -> Result { - try_get_impl!(self, 8, get_i64_be); - } - - fn try_get_f32(&mut self) -> Result { - try_get_impl!(self, 4, get_f32_be); - } - - fn try_get_f64(&mut self) -> Result { - try_get_impl!(self, 8, get_f64_be); - } - - fn try_get_u8(&mut self) -> Result { - try_get_impl!(self, 1, get_u8); - } - - fn try_get_u16(&mut self) -> Result { - try_get_impl!(self, 2, get_u16_be); - } - - fn try_get_u32(&mut self) -> Result { - try_get_impl!(self, 4, get_u32_be); - } - - fn try_get_u64(&mut self) -> Result { - try_get_impl!(self, 8, get_u64_be); - } -} - -/// Ext trait to implement put operations -/// for `BytesMut` which reserve additional capacity -/// rather than panicking. -pub trait BytesMutExt { - fn push_i8(&mut self, x: i8); - fn push_i16(&mut self, x: i16); - fn push_i32(&mut self, x: i32); - fn push_i64(&mut self, x: i64); - - fn push_f32(&mut self, x: f32); - fn push_f64(&mut self, x: f64); - - fn push_u8(&mut self, x: u8); - fn push_u16(&mut self, x: u16); - fn push_u32(&mut self, x: u32); - fn push_u64(&mut self, x: u64); -} - -impl BytesMutExt for BytesMut { - fn push_i8(&mut self, x: i8) { - self.reserve(1); - self.put_i8(x); - } - - fn push_i16(&mut self, x: i16) { - self.reserve(2); - self.put_i16_be(x); - } - - fn push_i32(&mut self, x: i32) { - self.reserve(4); - self.put_i32_be(x); - } - - fn push_i64(&mut self, x: i64) { - self.reserve(8); - self.put_i64_be(x); - } - - fn push_f32(&mut self, x: f32) { - self.reserve(4); - self.put_f32_be(x); - } - - fn push_f64(&mut self, x: f64) { - self.reserve(8); - self.put_f64_be(x); - } - - fn push_u8(&mut self, x: u8) { - self.reserve(1); - self.put_u8(x); - } - - fn push_u16(&mut self, x: u16) { - self.reserve(2); - self.put_u16_be(x); - } - - fn push_u32(&mut self, x: u32) { - self.reserve(4); - self.put_u32_be(x); - } - - fn push_u64(&mut self, x: u64) { - self.reserve(8); - self.put_u64_be(x); - } -} diff --git a/core/src/entitymeta.rs b/core/src/entitymeta.rs deleted file mode 100644 index d7ff0321b..000000000 --- a/core/src/entitymeta.rs +++ /dev/null @@ -1,261 +0,0 @@ -//! This module implements handling of the entity -//! metadata format. See https://wiki.vg/Entity_metadata -//! for the specification. - -use crate::bytes_ext::{BytesMutExt, TryGetError}; -use crate::network::mctypes::McTypeWrite; -use crate::world::BlockPosition; -use crate::Slot; -use hashbrown::HashMap; -use std::io::Cursor; -use uuid::Uuid; - -type OptUuid = Option; - -#[derive(Clone, Debug, PartialEq)] -pub enum MetaEntry { - Byte(i8), - VarInt(i32), - Float(f32), - String(String), - Chat(String), - OptChat(Option), - Slot(Slot), - Boolean(bool), - Rotation(f32, f32, f32), - Position(BlockPosition), - OptPosition(Option), - Direction(Direction), - OptUuid(OptUuid), - OptBlockId(Option), - Nbt, // TODO - Particle, // TODO -} - -impl MetaEntry { - pub fn id(&self) -> i32 { - match self { - MetaEntry::Byte(_) => 0, - MetaEntry::VarInt(_) => 1, - MetaEntry::Float(_) => 2, - MetaEntry::String(_) => 3, - MetaEntry::Chat(_) => 4, - MetaEntry::OptChat(_) => 5, - MetaEntry::Slot(_) => 6, - MetaEntry::Boolean(_) => 7, - MetaEntry::Rotation(_, _, _) => 8, - MetaEntry::Position(_) => 9, - MetaEntry::OptPosition(_) => 10, - MetaEntry::Direction(_) => 11, - MetaEntry::OptUuid(_) => 12, - MetaEntry::OptBlockId(_) => 13, - MetaEntry::Nbt => 14, - MetaEntry::Particle => 15, - } - } -} - -pub trait IntoMetaEntry { - fn into_meta_entry(&self) -> MetaEntry; -} - -impl IntoMetaEntry for u8 { - fn into_meta_entry(&self) -> MetaEntry { - MetaEntry::Byte(*self as i8) - } -} - -impl IntoMetaEntry for i8 { - fn into_meta_entry(&self) -> MetaEntry { - MetaEntry::Byte(*self) - } -} - -impl IntoMetaEntry for i32 { - fn into_meta_entry(&self) -> MetaEntry { - MetaEntry::VarInt(*self) - } -} - -impl IntoMetaEntry for bool { - fn into_meta_entry(&self) -> MetaEntry { - MetaEntry::Boolean(*self) - } -} - -impl IntoMetaEntry for Slot { - fn into_meta_entry(&self) -> MetaEntry { - MetaEntry::Slot(self.clone()) - } -} - -impl IntoMetaEntry for f32 { - fn into_meta_entry(&self) -> MetaEntry { - MetaEntry::Float(*self) - } -} - -impl IntoMetaEntry for OptUuid { - fn into_meta_entry(&self) -> MetaEntry { - MetaEntry::OptUuid(*self) - } -} - -impl IntoMetaEntry for BlockPosition { - fn into_meta_entry(&self) -> MetaEntry { - MetaEntry::Position(*self) - } -} - -#[derive(Clone)] -pub struct EntityMetadata { - values: HashMap, -} - -impl EntityMetadata { - pub fn new() -> Self { - Self { - values: HashMap::new(), - } - } - - pub fn with(mut self, values: &[(u8, MetaEntry)]) -> Self { - for val in values { - self.values.insert(val.0, val.1.clone()); - } - - self - } - - pub fn set(&mut self, index: u8, entry: E) { - self.values.insert(index, entry.into_meta_entry()); - } - - pub fn get(&self, index: u8) -> Option { - self.values.get(&index).cloned() - } -} - -impl Default for EntityMetadata { - fn default() -> Self { - Self::new() - } -} - -pub trait EntityMetaIo { - fn push_metadata(&mut self, meta: &EntityMetadata); - fn try_get_metadata(&mut self) -> Result; -} - -impl EntityMetaIo for B -where - B: BytesMutExt + McTypeWrite, -{ - fn push_metadata(&mut self, meta: &EntityMetadata) { - for (index, entry) in meta.values.iter() { - self.push_u8(*index); - self.push_var_int(entry.id()); - write_entry_to_buf(entry, self); - } - - self.push_u8(0xff); // End of metadata - } - - fn try_get_metadata(&mut self) -> Result { - unimplemented!() - } -} - -impl EntityMetaIo for &mut Cursor<&[u8]> { - fn push_metadata(&mut self, _meta: &EntityMetadata) { - unimplemented!() - } - - fn try_get_metadata(&mut self) -> Result { - unimplemented!() - } -} - -fn write_entry_to_buf(entry: &MetaEntry, buf: &mut B) -where - B: BytesMutExt + McTypeWrite, -{ - match entry { - MetaEntry::Byte(x) => buf.push_i8(*x), - MetaEntry::VarInt(x) => { - buf.push_var_int(*x); - } - MetaEntry::Float(x) => buf.push_f32(*x), - MetaEntry::String(x) => buf.push_string(x), - MetaEntry::Chat(x) => buf.push_string(x), - MetaEntry::OptChat(ox) => { - if let Some(x) = ox { - buf.push_bool(true); - buf.push_string(x); - } else { - buf.push_bool(false); - } - } - MetaEntry::Slot(slot) => { - buf.push_slot(slot); - } - MetaEntry::Boolean(x) => buf.push_bool(*x), - MetaEntry::Rotation(x, y, z) => { - buf.push_f32(*x); - buf.push_f32(*y); - buf.push_f32(*z); - } - MetaEntry::Position(x) => buf.push_position(x), - MetaEntry::OptPosition(ox) => { - if let Some(x) = ox { - buf.push_bool(true); - buf.push_position(x); - } else { - buf.push_bool(false); - } - } - MetaEntry::Direction(x) => { - buf.push_var_int(x.id()); - } - MetaEntry::OptUuid(ox) => { - if let Some(x) = ox { - buf.push_bool(true); - buf.push_uuid(x); - } else { - buf.push_bool(false); - } - } - MetaEntry::OptBlockId(ox) => { - if let Some(x) = ox { - buf.push_var_int(*x); - } else { - buf.push_var_int(0); // No value implies air - } - } - MetaEntry::Nbt => unimplemented!(), - MetaEntry::Particle => unimplemented!(), - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Direction { - Down, - Up, - North, - South, - West, - East, -} - -impl Direction { - pub fn id(&self) -> i32 { - match self { - Direction::Down => 0, - Direction::Up => 1, - Direction::North => 2, - Direction::South => 3, - Direction::West => 4, - Direction::East => 5, - } - } -} diff --git a/core/src/inventory.rs b/core/src/inventory.rs deleted file mode 100644 index aa661453b..000000000 --- a/core/src/inventory.rs +++ /dev/null @@ -1,447 +0,0 @@ -//! Module for creating and modifying inventories of any type. - -use crate::item::Item; -use smallvec::{Array, SmallVec}; -use std::cmp::min; - -pub type SlotIndex = usize; - -// Constants representing various standard inventory slot indices - -pub const SLOT_CRAFTING_OUTPUT: SlotIndex = 0; -pub const SLOT_CRAFTING_INPUT_X0_Y0: SlotIndex = 1; -pub const SLOT_CRAFTING_INPUT_X1_Y0: SlotIndex = 2; -pub const SLOT_CRAFTING_INPUT_X0_Y1: SlotIndex = 3; -pub const SLOT_CRAFTING_INPUT_X1_Y1: SlotIndex = 4; - -pub const SLOT_ARMOR_MIN: SlotIndex = 5; -pub const SLOT_ARMOR_MAX: SlotIndex = 8; - -pub const SLOT_ARMOR_HEAD: SlotIndex = 5; -pub const SLOT_ARMOR_CHEST: SlotIndex = 6; -pub const SLOT_ARMOR_LEGS: SlotIndex = 7; -pub const SLOT_ARMOR_FEET: SlotIndex = 8; - -pub const SLOT_OFFHAND: SlotIndex = 45; - -pub const SLOT_INVENTORY_OFFSET: SlotIndex = 9; -pub const SLOT_HOTBAR_OFFSET: SlotIndex = 36; - -pub const HOTBAR_SIZE: SlotIndex = 9; -pub const INVENTORY_SIZE: SlotIndex = 27; - -pub const SLOT_ENTITY_EQUIPMENT_MAIN_HAND: SlotIndex = 0; -pub const SLOT_ENTITY_EQUIPMENT_OFF_HAND: SlotIndex = 1; -pub const SLOT_ENTITY_EQUIPMENT_BOOTS: SlotIndex = 2; -pub const SLOT_ENTITY_EQUIPMENT_LEGGINGS: SlotIndex = 3; -pub const SLOT_ENTITY_EQUIPMENT_CHESTPLATE: SlotIndex = 4; -pub const SLOT_ENTITY_EQUIPMENT_HELMET: SlotIndex = 5; - -pub type Slot = Option; - -lazy_static! { - static ref COLLECT_SEARCH_ORDER: Vec = { - let mut result = vec![]; - for x in SLOT_HOTBAR_OFFSET..SLOT_HOTBAR_OFFSET + HOTBAR_SIZE { - result.push(x); - } - - for x in SLOT_INVENTORY_OFFSET..SLOT_INVENTORY_OFFSET + INVENTORY_SIZE { - result.push(x); - } - - result - }; -} - -pub fn armor_slot_to_entity_equipment(slot: SlotIndex) -> SlotIndex { - assert!(slot >= 5 && slot <= 8); - match slot { - SLOT_ARMOR_HEAD => SLOT_ENTITY_EQUIPMENT_HELMET, - SLOT_ARMOR_CHEST => SLOT_ENTITY_EQUIPMENT_CHESTPLATE, - SLOT_ARMOR_LEGS => SLOT_ENTITY_EQUIPMENT_LEGGINGS, - SLOT_ARMOR_FEET => SLOT_ENTITY_EQUIPMENT_BOOTS, - _ => unreachable!(), - } -} - -/// Returns the max size of a stack with the given -/// type. -pub fn max_size(item: Item) -> u8 { - match item { - Item::WoodenSword - | Item::GoldenSword - | Item::StoneSword - | Item::IronSword - | Item::DiamondSword - | Item::WoodenAxe - | Item::GoldenAxe - | Item::StoneAxe - | Item::IronAxe - | Item::DiamondAxe - | Item::WoodenHoe - | Item::GoldenHoe - | Item::StoneHoe - | Item::IronHoe - | Item::DiamondHoe - | Item::WoodenPickaxe - | Item::GoldenPickaxe - | Item::StonePickaxe - | Item::IronPickaxe - | Item::DiamondPickaxe - | Item::WoodenShovel - | Item::GoldenShovel - | Item::StoneShovel - | Item::IronShovel - | Item::DiamondShovel - | Item::LeatherChestplate - | Item::GoldenChestplate - | Item::ChainmailChestplate - | Item::IronChestplate - | Item::DiamondChestplate - | Item::LeatherLeggings - | Item::GoldenLeggings - | Item::ChainmailLeggings - | Item::IronLeggings - | Item::DiamondLeggings - | Item::LeatherBoots - | Item::GoldenBoots - | Item::ChainmailBoots - | Item::IronBoots - | Item::DiamondBoots - | Item::LeatherHelmet - | Item::GoldenHelmet - | Item::ChainmailHelmet - | Item::IronHelmet - | Item::DiamondHelmet - | Item::Bow - | Item::Book - | Item::WrittenBook - | Item::WritableBook - | Item::FlintAndSteel - | Item::WhiteBed - | Item::OrangeBed - | Item::MagentaBed - | Item::LightBlueBed - | Item::YellowBed - | Item::LimeBed - | Item::PinkBed - | Item::GrayBed - | Item::LightGrayBed - | Item::CyanBed - | Item::PurpleBed - | Item::BlueBed - | Item::BrownBed - | Item::GreenBed - | Item::RedBed - | Item::BlackBed - | Item::ShulkerBox - | Item::TurtleEgg - | Item::TurtleHelmet - | Item::FishingRod - | Item::EnchantedBook - | Item::Potion - | Item::LingeringPotion - | Item::SplashPotion - | Item::WaterBucket - | Item::LavaBucket - | Item::TropicalFishBucket - | Item::CodBucket - | Item::MilkBucket - | Item::PufferfishBucket - | Item::SalmonBucket - | Item::CarrotOnAStick - | Item::Elytra - | Item::Shield - | Item::Trident - | Item::MusicDisc13 - | Item::MusicDiscCat - | Item::MusicDiscBlocks - | Item::MusicDiscChirp - | Item::MusicDiscFar - | Item::MusicDiscMall - | Item::MusicDiscMellohi - | Item::MusicDiscStal - | Item::MusicDiscStrad - | Item::MusicDiscWard - | Item::MusicDisc11 - | Item::MusicDiscWait - | Item::TotemOfUndying - | Item::Shears - | Item::AcaciaBoat - | Item::DarkOakBoat - | Item::OakBoat - | Item::SpruceBoat - | Item::BirchBoat - | Item::JungleBoat - | Item::MushroomStew - | Item::BeetrootSoup - | Item::RabbitStew - | Item::Cake - | Item::Minecart - | Item::ChestMinecart - | Item::CommandBlockMinecart - | Item::FurnaceMinecart - | Item::HopperMinecart - | Item::TntMinecart - | Item::DiamondHorseArmor - | Item::GoldenHorseArmor - | Item::IronHorseArmor => 1, - Item::EnderPearl - | Item::Snowball - | Item::WhiteBanner - | Item::OrangeBanner - | Item::MagentaBanner - | Item::LightBlueBanner - | Item::YellowBanner - | Item::LimeBanner - | Item::PinkBanner - | Item::GrayBanner - | Item::LightGrayBanner - | Item::CyanBanner - | Item::PurpleBanner - | Item::BlueBanner - | Item::BrownBanner - | Item::GreenBanner - | Item::RedBanner - | Item::BlackBanner - | Item::Sign - | Item::ArmorStand - | Item::Egg => 16, - _ => 64, - // TODO: are we missing some here? - } -} - -/// The various types of inventories ("windows"). -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum InventoryType { - Player, - Container, - Chest, - CraftingTable, - Furnace, - Dispenser, - EnchantingTable, - BrewingStand, - Villager, - Beacon, - Anvil, - Hopper, - Dropper, - ShulkerBox, - Horse, -} - -/// An inventory, consisting of a vector -/// of `Slot`s and a type. -#[derive(Debug, Clone)] -pub struct Inventory { - /// The item vector. - /// - /// The vector always contains an entry - /// for each slot in the inventory, indexed - /// by the slot IDs. When an entry is set to - /// `None`, there is no item in the slot. - items: Vec>, - /// The type of this inventory. - pub ty: InventoryType, -} - -impl Inventory { - /// Creates a new inventory of the given - /// type and number of slots. - pub fn new(ty: InventoryType, num_slots: u32) -> Self { - Self { - items: vec![None; num_slots as usize], - ty, - } - } - - /// Retrieves a reference to the item at the given slot index. - /// - /// # Panics - /// Panics if the index is out of bounds. - pub fn item_at(&self, index: SlotIndex) -> Option<&ItemStack> { - self.items[index].as_ref() - } - - pub fn item_at_mut(&mut self, index: SlotIndex) -> Option<&mut ItemStack> { - self.items[index].as_mut() - } - - /// Sets the item at the given slot index. - pub fn set_item_at(&mut self, index: SlotIndex, item: ItemStack) { - if item.amount == 0 { - self.items[index] = None; - } else { - self.items[index] = Some(item); - } - } - - /// Clears the item at the given slot index, returning - /// the old item. - pub fn clear_item_at(&mut self, index: SlotIndex) -> Option { - self.items[index].take() - } - - /// Attempts to insert the given item into a player - /// inventory. - /// - /// Returns the affected slots and the number of remaining - /// items which were not added to the inventory. - pub fn collect_item(&mut self, mut item: ItemStack) -> (SmallVec<[SlotIndex; 2]>, u8) { - let mut affected_slots = smallvec![]; - - // First, look for slots already having the type. - for slot in COLLECT_SEARCH_ORDER.iter() { - if let Some(slot_item) = self.item_at(*slot).cloned() { - if slot_item.ty == item.ty { - self.add_to_stack(&mut item, &slot_item, *slot, &mut affected_slots); - - if item.amount == 0 { - return (affected_slots, 0); - } - } - } - } - - for slot in COLLECT_SEARCH_ORDER.iter() { - let slot_item = self.item_at(*slot).cloned(); - if slot_item.is_none() { - let fake = ItemStack::new(item.ty, 0); - self.add_to_stack(&mut item, &fake, *slot, &mut affected_slots); - if item.amount == 0 { - return (affected_slots, 0); - } - } - - if let Some(slot_item) = slot_item { - if slot_item.ty == item.ty { - self.add_to_stack(&mut item, &slot_item, *slot, &mut affected_slots); - - if item.amount == 0 { - return (affected_slots, 0); - } - } - } - } - - (affected_slots, item.amount) - } - - /// Adds an item to a stack. - fn add_to_stack>( - &mut self, - item: &mut ItemStack, - slot_item: &ItemStack, - slot: SlotIndex, - affected_slots: &mut SmallVec, - ) { - let added = min(item.amount, max_size(item.ty) - slot_item.amount); - item.amount -= added; - - self.set_item_at(slot, ItemStack::new(slot_item.ty, slot_item.amount + added)); - affected_slots.push(slot); - } - - /// Returns the number of slots in this inventory. - pub fn slot_count(&self) -> u16 { - self.items.len() as u16 - } - - /// Returns a reference to this inventory's items. - pub fn items(&self) -> &[Option] { - &self.items - } -} - -/// Represents an item stack. -/// -/// An item stack includes a type, an amount, and a bunch of properties (enchantments, etc.) -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ItemStack { - /// The type of this item. - pub ty: Item, - /// The number of items in this stack. - pub amount: u8, - // TODO enchantments, more -} - -impl ItemStack { - pub fn new(ty: Item, amount: u8) -> Self { - Self { ty, amount } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_inventory() { - let mut inv = Inventory::new(InventoryType::Chest, 36); - assert_eq!(inv.slot_count(), 36); - - inv.set_item_at(0, ItemStack::new(Item::Air, 1)); - - let item = inv.item_at(0).unwrap(); - assert_eq!(item.ty, Item::Air); - assert_eq!(item.amount, 1); - - let item = inv.item_at_mut(0).unwrap(); - item.ty = Item::Sponge; - assert_eq!(inv.item_at(0).unwrap().ty, Item::Sponge); - - inv.clear_item_at(0); - assert!(inv.item_at(0).is_none()); - } - - #[test] - fn test_collect_item_basic() { - let mut inv = Inventory::new(InventoryType::Player, 46); - let item = ItemStack::new(Item::Cobblestone, 32); - inv.collect_item(item.clone()); - assert_eq!(inv.item_at(SLOT_HOTBAR_OFFSET).unwrap(), &item); - } - - #[test] - fn test_collect_item_full() { - let mut inv = Inventory::new(InventoryType::Player, 46); - let item = ItemStack::new(Item::DriedKelpBlock, 64); - - for i in 0..46 { - inv.set_item_at(i, item.clone()); - } - - inv.collect_item(ItemStack::new(Item::Cobblestone, 16)); - for i in 0..46 { - assert_eq!(inv.item_at(i).unwrap(), &item); - } - } - - #[test] - fn test_collect_item_type_already_in() { - let mut inv = Inventory::new(InventoryType::Player, 46); - let item = ItemStack::new(Item::Cobblestone, 33); - inv.set_item_at(31, item.clone()); - - inv.collect_item(item.clone()); - assert_eq!(inv.item_at(31).unwrap(), &ItemStack::new(item.ty, 64)); - assert_eq!( - inv.item_at(SLOT_HOTBAR_OFFSET).unwrap(), - &ItemStack::new(item.ty, 2) - ); - } - - #[test] - fn test_collect_item_overstack() { - let mut inv = Inventory::new(InventoryType::Player, 46); - let item = ItemStack::new(Item::DiamondSword, 1); - inv.set_item_at(SLOT_HOTBAR_OFFSET, item.clone()); - - inv.collect_item(item.clone()); - assert_eq!(inv.item_at(SLOT_HOTBAR_OFFSET).unwrap(), &item); - assert_eq!(inv.item_at(SLOT_HOTBAR_OFFSET + 1).unwrap(), &item); - } -} diff --git a/core/src/network/codec.rs b/core/src/network/codec.rs deleted file mode 100644 index 41fd09141..000000000 --- a/core/src/network/codec.rs +++ /dev/null @@ -1,265 +0,0 @@ -use crate::bytes_ext::TryGetError; -use crate::network::mctypes::{McTypeRead, McTypeWrite}; -use crate::network::packet::{PacketDirection, PacketId, PacketStage}; -use crate::{Packet, PacketType}; -use aes::Aes128; -use bytes::{Buf, BufMut, BytesMut}; -use cfb8::stream_cipher::{NewStreamCipher, StreamCipher}; -use cfb8::Cfb8; -use flate2::read::ZlibDecoder; -use flate2::write::ZlibEncoder; -use flate2::Compression; -use std::io::{Cursor, Read, Write}; -use tokio::codec::{Decoder, Encoder}; -use tokio::io; - -type AesCfb8 = Cfb8; - -/// Maximum possible size of a varint. -const MAX_VAR_INT_SIZE: usize = 5; -/// Maximum allowed length of a received packet. -const MAX_PACKET_LEN: usize = 1_048_576; // One MB -/// Maximum possible size of a packet header. -const HEADER_SIZE: usize = MAX_VAR_INT_SIZE * 2; - -#[derive(Debug, Fail)] -pub enum Error { - #[fail( - display = "Packet of length {} (under compression threshold {}) was sent compressed", - _0, _1 - )] - CompressedPacketTooSmall(usize, usize), - #[fail(display = "Packet length {} is too large", _0)] - PacketTooLarge(usize), - #[fail(display = "Invalid packet ID {} for stage {:?}", _0, _1)] - InvalidPacketId(u32, PacketStage), -} - -/// Codec for encoding and decoding Minecraft packets. -pub struct MinecraftCodec { - /// Direction of incoming packets. - incoming_direction: PacketDirection, - /// The current stage of this codec. - stage: PacketStage, - /// The encrypter, if encryption is enabled. - encrypter: Option, - /// The decrypter, if encryption is enabled. - decrypter: Option, - /// The compression threshold, if compression is enabled. - compression_threshold: Option, - /// Cached buffer for writing header data. - /// Using this avoids reallocations. - header_buffer: BytesMut, - /// Cached buffer into which we write decompressed - /// data. Using this avoids reallocations. - decompressed_buffer: Vec, - /// Index into `src` of next byte to decrypt. - decrypt_index: usize, -} - -impl MinecraftCodec { - pub fn new(incoming_direction: PacketDirection) -> Self { - Self { - incoming_direction, - stage: PacketStage::Handshake, - encrypter: None, - decrypter: None, - compression_threshold: None, - header_buffer: BytesMut::with_capacity(HEADER_SIZE), - decompressed_buffer: vec![], - decrypt_index: 0, - } - } - - pub fn enable_compression(&mut self, threshold: usize) { - self.compression_threshold = Some(threshold); - } - - pub fn enable_encryption(&mut self, key: [u8; 16]) { - // This is the toppoint of security: using the same IV - // for every packet. Typical for Mojang. - self.encrypter = Some(AesCfb8::new_var(&key, &key).unwrap()); - self.decrypter = Some(AesCfb8::new_var(&key, &key).unwrap()); - } - - pub fn set_stage(&mut self, stage: PacketStage) { - self.stage = stage; - } -} - -impl Encoder for MinecraftCodec { - type Item = Box; - type Error = io::Error; - - fn encode(&mut self, packet: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { - // Reserve space for the packet header (at most 2 * 5 bytes, for length + data length). - // `header` will contain the first 10 bytes of the buffer, while `dst` - // still contains the rest. - // "Data length" refers to the uncompressed size of the packet. - // Since we cannot know the size of the header in advance, thanks to varints, - // we reserve the maximum size and copy the header in with a correct offset. - assert!(dst.is_empty()); - dst.reserve(HEADER_SIZE); - let mut header = dst.split_to(HEADER_SIZE); - assert!(dst.is_empty()); - assert!(header.is_empty()); - - // Zero out `header`. - header.extend_from_slice(&[0u8; HEADER_SIZE]); - - // Write raw packet data to `dst`. - let ty = packet.ty(); - trace!("Sending packet with type {:?}", ty); - dst.push_var_int(ty.get_id().0 as i32); - packet.write_to(dst); - - // If compression is enabled, we follow a more complex course of action: - // * Write the raw packet data to `dst`. - // * If the data is less than the compression threshold, proceed as usual. - // * Otherwise, we move forward into the buffer, allocating - // another header and then writing the compressed bytes - // to the capacity after that. - let data_len: Option = if let Some(threshold) = self.compression_threshold { - let data_len = dst.len(); - if data_len >= threshold { - // Allocate new header - dst.reserve(HEADER_SIZE); - - let uncompressed = dst.split_to(data_len); - header = dst.split_to(HEADER_SIZE); - - assert!(dst.is_empty()); - // Compress data into `compressed`. - let mut encoder = ZlibEncoder::new(dst.writer(), Compression::default()); - encoder.write_all(uncompressed.as_ref()).unwrap(); - - Some(data_len) - } else { - Some(0) // Not compressed - } - } else { - None - }; - - // Figure out the length of `data_length` encoded. - let length_of_data_length = match data_len { - Some(data_len) => { - let mut temp = BytesMut::with_capacity(MAX_VAR_INT_SIZE); - temp.push_var_int(data_len as i32); - temp.len() - } - None => 0, - }; - - // Write header. We first write to a temporary buffer, - // then copy this to the correct position in `header`, - // trimming off the unused bytes. - self.header_buffer - .push_var_int((length_of_data_length + dst.len()) as i32); - if let Some(data_len) = data_len { - self.header_buffer.push_var_int(data_len as i32); - } - - // Offset into `header` to write to. - let header_offset = HEADER_SIZE - self.header_buffer.len(); - // Discard unused header bytes. - header.split_to(header_offset); - header.clear(); - - // Write into header. - header.extend_from_slice(&self.header_buffer); - self.header_buffer.clear(); - - // Finally, merge `header` and `dst`. - std::mem::swap(dst, &mut header); - dst.unsplit(header); - - // If encryption is enabled, encrypt data in place. - if let Some(crypter) = self.encrypter.as_mut() { - crypter.encrypt(dst); - } - - Ok(()) - } -} - -impl Decoder for MinecraftCodec { - type Item = Box; - type Error = failure::Error; - - fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { - // If encryption is enabled, decrypt undecrypted data. - if let Some(crypter) = self.decrypter.as_mut() { - crypter.decrypt(&mut src[self.decrypt_index..]); - self.decrypt_index = src.len(); - } - - // Conversion to `Cursor` is required because `Bytes` does - // not implement `Buf`. - let mut cursor = Cursor::new(src.as_ref()); - - // Read header. - let length = match cursor.try_get_var_int() { - Ok(length) => length as usize, - Err(TryGetError::NotEnoughBytes) => return Ok(None), - Err(e) => return Err(e.into()), - }; - - if length > cursor.remaining() { - // Full packet has not been read yet. - return Ok(None); - } - - // Prevent malicious clients from causing huge allocations. - if length > MAX_PACKET_LEN { - return Err(Error::PacketTooLarge(length).into()); - } - - // At this point, we know a full packet has been received. - - // Trim `cursor` and `src` to length of packet. - let position = cursor.position() as usize; - src.advance(position); - cursor = Cursor::new(&src[..length]); - - // If compression is enabled: - // * Read the data length field. If 0, continue as normal: the packet is not compressed. - // * Decompress remaining bytes into `self.decompressed_buffer`. - // * Update `cursor` to read from `self.decompressed_buffer`. - if let Some(threshold) = self.compression_threshold { - let data_length = cursor.try_get_var_int()?; - - if data_length != 0 { - self.decompressed_buffer.clear(); - - let mut decoder = ZlibDecoder::new(cursor); - decoder.read_to_end(&mut self.decompressed_buffer)?; - - let actual_data_length = self.decompressed_buffer.len(); - if actual_data_length < threshold { - return Err( - Error::CompressedPacketTooSmall(actual_data_length, threshold).into(), - ); - } - - cursor = Cursor::new(&self.decompressed_buffer); - } - } - - // Read packet. - let id = cursor.try_get_var_int()? as u32; - let packet_type = - PacketType::get_from_id(PacketId(id, self.incoming_direction, self.stage)) - .map_err(|_| Error::InvalidPacketId(id, self.stage))?; - - let mut packet = packet_type.get_implementation(); - packet.read_from(&mut cursor)?; - - trace!("Received packet with type {:?}", packet_type); - - src.advance(length); - self.decrypt_index = src.len(); - - Ok(Some(packet)) - } -} diff --git a/core/src/network/mctypes.rs b/core/src/network/mctypes.rs deleted file mode 100644 index d47a7174d..000000000 --- a/core/src/network/mctypes.rs +++ /dev/null @@ -1,231 +0,0 @@ -use crate::bytes_ext::{BytesExt, BytesMutExt, TryGetError}; -use crate::inventory::ItemStack; -use crate::prelude::*; -use crate::world::BlockPosition; -use bytes::{Buf, BytesMut}; -use feather_items::{Item, ItemExt}; -use serde::{Deserialize, Serialize}; -use std::io::Read; - -/// Identifies a type to which Minecraft-specific -/// types (`VarInt`, `VarLong`, etc.) can be written. -pub trait McTypeWrite { - /// Writes a `VarInt` to the object. See wiki.vg for - /// details on `VarInt`s and related types. - /// - /// Returns the number of bytes used to encode this integer. - fn push_var_int(&mut self, x: i32) -> usize; - /// Writes a string to the object. This method - /// will first write the length of the string in bytes - /// encodes as a `VarInt` and will then write - /// the UTF-8 bytes of the string. - fn push_string(&mut self, x: &str); - - fn push_position(&mut self, x: &BlockPosition); - - fn push_bool(&mut self, x: bool); - - fn push_uuid(&mut self, x: &Uuid); - - fn push_nbt(&mut self, x: &T); - - fn push_slot(&mut self, slot: &Option); -} - -/// Identifies a type from which Minecraft-specified -/// types can be read. -pub trait McTypeRead { - /// Reads a `VarInt` from this object, returning - /// `Some(x)` if successful or `None` if the object - /// does not contain a valid `VarInt`. - fn try_get_var_int(&mut self) -> Result; - /// Reads a string from the object. - fn try_get_string(&mut self) -> Result; - - fn try_get_position(&mut self) -> Result; - - fn try_get_bool(&mut self) -> Result; - - fn try_get_uuid(&mut self) -> Result; - - fn try_get_nbt<'de, T: Deserialize<'de>>(&mut self) -> Result; - - fn try_get_slot(&mut self) -> Result, TryGetError>; -} - -impl McTypeWrite for BytesMut { - fn push_var_int(&mut self, mut x: i32) -> usize { - let mut bytes_written = 0; - loop { - let mut temp = (x & 0b0111_1111) as u8; - x >>= 7; - if x != 0 { - temp |= 0b1000_0000; - } - self.push_u8(temp); - bytes_written += 1; - if x == 0 { - break; - } - } - - bytes_written - } - - /// Writes a string to the object. This method - /// will first write the length of the string in bytes - /// encodes as a `VarInt` and will then write - /// the UTF-8 bytes of the string. - fn push_string(&mut self, x: &str) { - let bytes = x.as_bytes(); - self.push_var_int(bytes.len() as i32); - - self.extend_from_slice(bytes); - } - - fn push_position(&mut self, x: &BlockPosition) { - let result: u64 = ((x.x as u64 & 0x03FF_FFFF) << 38) - | ((x.y as u64 & 0xFFF) << 26) - | (x.z as u64 & 0x03FF_FFFF); - - self.push_u64(result); - } - - fn push_bool(&mut self, x: bool) { - if x { - self.push_u8(1); - } else { - self.push_u8(0); - } - } - - fn push_uuid(&mut self, x: &Uuid) { - self.extend_from_slice(&x.as_bytes()[..]); - } - - fn push_nbt(&mut self, val: &T) { - // TODO: fix inefficient use of temp buf. - let mut temp = vec![]; - nbt::to_writer(&mut temp, val, None).unwrap(); // Unwrap is safe because writing would only fail if a struct couldn't be written - self.extend_from_slice(&temp); - } - - fn push_slot(&mut self, slot: &Option) { - self.push_bool(slot.is_some()); - - if let Some(slot) = slot.as_ref() { - self.push_var_int(slot.ty.native_protocol_id()); - self.push_i8(slot.amount as i8); - self.push_i8(0x00); // TAG_End - TODO item NBT support - } - } -} - -impl McTypeRead for B { - /// Reads a `VarInt` from this object, returning - /// `Some(x)` if successful or `None` if the object - /// does not contain a valid `VarInt`. - fn try_get_var_int(&mut self) -> Result { - let mut num_read = 0; - let mut result = 0; - loop { - if self.remaining() == 0 { - return Err(TryGetError::NotEnoughBytes); - } - let read = self.try_get_u8()?; - let value = i32::from(read & 0b0111_1111); - result |= value << (7 * num_read); - - num_read += 1; - if num_read > 5 { - return Err(TryGetError::NotEnoughBytes); - } - if read & 0b1000_0000 == 0 { - break; - } - } - Ok(result) - } - - /// Reads a string from the object. - fn try_get_string(&mut self) -> Result { - let len = self.try_get_var_int(); - if let Ok(len) = len { - // Check that the client isn't trying - // to make the server allocate ridiculous - // amounts of memory - if len > 32767 { - return Err(TryGetError::ValueTooLarge); - } - let mut result = String::with_capacity(len as usize); - for _ in 0..len { - let res = self.try_get_i8()? as u8; - result.push(res as char); - } - - return Ok(result); - } - - Err(TryGetError::NotEnoughBytes) - } - - fn try_get_position(&mut self) -> Result { - let val = self.try_get_i64()?; - let x = val >> 38; - let y = (val >> 26) & 0xFFF; - let z = val << 38 >> 38; - - Ok(BlockPosition::new(x as i32, y as i32, z as i32)) - } - - fn try_get_bool(&mut self) -> Result { - let byte = self.try_get_i8()?; - match byte { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(TryGetError::InvalidValue), - } - } - - fn try_get_uuid(&mut self) -> Result { - let mut bytes = [0u8; 16]; - self.bytes() - .read(&mut bytes) - .map_err(|_| TryGetError::NotEnoughBytes)?; - Ok(Uuid::from_bytes(bytes)) - } - - fn try_get_nbt<'de, D: Deserialize<'de>>(&mut self) -> Result { - unimplemented!() - } - - fn try_get_slot(&mut self) -> Result, TryGetError> { - let present = self.try_get_bool()?; - - if !present { - return Ok(None); - } - - let id = self.try_get_var_int()?; - let ty = Item::from_native_protocol_id(id).ok_or(TryGetError::InvalidValue)?; - let amount = self.try_get_i8()? as u8; - - // TODO NBT support - - Ok(Some(ItemStack::new(ty, amount))) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::io::Cursor; - - #[test] - fn test_read_var_int() { - // Examples from wiki.vg - let mut buf = BytesMut::new(); - buf.extend_from_slice(&[0xff, 0x01]); - assert_eq!(Cursor::new(&buf).try_get_var_int(), Ok(255)); - } -} diff --git a/core/src/network/mod.rs b/core/src/network/mod.rs deleted file mode 100644 index 732b62454..000000000 --- a/core/src/network/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod codec; -pub mod mctypes; -pub mod packet; - -pub fn cast_packet(packet: &dyn packet::Packet) -> &P { - packet.as_any().downcast_ref().unwrap() -} diff --git a/core/src/network/packet/mod.rs b/core/src/network/packet/mod.rs deleted file mode 100644 index d8bcc87ec..000000000 --- a/core/src/network/packet/mod.rs +++ /dev/null @@ -1,620 +0,0 @@ -#[allow(unused)] -#[allow(clippy::too_many_arguments)] -pub mod implementation; -use bytes::BytesMut; -use hashbrown::HashMap; -use std::any::Any; -use std::io::Cursor; - -pub trait AsAny { - fn as_any(&self) -> &dyn Any; -} - -pub trait Packet: AsAny + Send + Sync { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error>; - fn write_to(&self, buf: &mut BytesMut); - fn ty(&self) -> PacketType; - - /// Returns a clone of this packet in a dynamic box. - fn box_clone(&self) -> Box; -} - -#[derive(Clone, Debug)] -pub struct PacketBuilder { - pub init_fn: fn() -> Box, -} - -impl PacketBuilder { - pub fn build(&self) -> Box { - let f = self.init_fn; - f() - } - - pub fn with(f: fn() -> Box) -> Self { - Self { init_fn: f } - } -} - -#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, EnumCount)] -pub enum PacketType { - // Serverbound - - // Handshake - Handshake = 1, - - // Login - LoginStart = 2, - EncryptionResponse = 3, - LoginPluginResponse = 4, - - // Play - TeleportConfirm = 5, - QueryBlockNBT = 6, - ChatMessageServerbound = 7, - ClientStatus = 8, - ClientSettings = 9, - TabCompleteServerbound = 10, - ConfirmTransactionServerbound = 11, - EnchantItem = 12, - ClickWindow = 13, - CloseWindowServerbound = 14, - PluginMessageServerbound = 15, - EditBook = 16, - QueryEntityNBT = 17, - UseEntity = 18, - KeepAliveServerbound = 19, - Player = 20, - PlayerPosition = 21, - PlayerPositionAndLookServerbound = 22, - PlayerLook = 23, - VehicleMoveServerbound = 24, - SteerBoat = 25, - PickItem = 26, - CraftRecipeRequest = 27, - PlayerAbilitiesServerbound = 28, - PlayerDigging = 29, - EntityAction = 30, - SteerVehicle = 31, - RecipeBookData = 32, - NameItem = 33, - ResourcePackStatus = 34, - AdvancementTab = 35, - SelectTrade = 36, - SetBeaconEffect = 37, - HeldItemChangeServerbound = 38, - UpdateCommandBlock = 39, - UpdateCommandBlockMinecart = 40, - CreativeInventoryAction = 41, - UpdateStructureBlock = 42, - UpdateSign = 43, - AnimationServerbound = 44, - Spectate = 45, - PlayerBlockPlacement = 46, - UseItem = 47, - - // Status - Request = 48, - Ping = 49, - - // Clientbound - - // Handshake - // (none) - - // Login - DisconnectLogin = 50, - EncryptionRequest = 51, - LoginSuccess = 52, - SetCompression = 53, - LoginPluginRequest = 54, - - // Play - SpawnObject = 55, - SpawnExperienceOrb = 56, - SpawnGlobalOrb = 57, - SpawnGlobalEntity = 58, - SpawnMob = 59, - SpawnPainting = 60, - SpawnPlayer = 61, - AnimationClientbound = 62, - Statistics = 63, - BlockBreakAnimation = 64, - UpdateBlockEntity = 65, - BlockAction = 66, - BlockChange = 67, - BossBar = 68, - ServerDifficulty = 69, - ChatMessageClientbound = 70, - MultiBlockChange = 71, - TabCompleteClientbound = 72, - DeclareCommands = 73, - ConfirmTransactionClientbound = 74, - CloseWindowClientbound = 75, - OpenWindow = 76, - WindowItems = 77, - WindowProperty = 78, - SetSlot = 79, - SetCooldown = 80, - PluginMessageClientbound = 81, - NamedSoundEffect = 82, - DisconnectPlay = 83, - EntityStatus = 84, - NBTQueryResponse = 85, - Explosion = 86, - UnloadChunk = 87, - ChangeGameState = 88, - KeepAliveClientbound = 89, - ChunkData = 90, - Effect = 91, - Particle = 92, - JoinGame = 93, - MapData = 94, - Entity = 95, - EntityRelativeMove = 96, - EntityLookAndRelativeMove = 97, - EntityLook = 98, - VehicleMoveClientbound = 99, - OpenSignEditor = 100, - CraftRecipeResponse = 101, - PlayerAbilitiesClientbound = 102, - CombatEvent = 103, - PlayerInfo = 104, - FacePlayer = 105, - PlayerPositionAndLookClientbound = 106, - UseBed = 107, - UnlockRecipes = 108, - DestroyEntities = 109, - RemoveEntityEffect = 110, - ResourcePackSend = 111, - Respawn = 112, - EntityHeadLook = 113, - SelectAdvancementTab = 114, - WorldBorder = 115, - Camera = 116, - HeldItemChangeClientbound = 117, - DisplayScoreboard = 118, - EntityMetadata = 119, - AttachEntity = 120, - EntityVelocity = 121, - EntityEquipment = 122, - SetExperience = 123, - UpdateHealth = 124, - ScoreboardObjective = 125, - SetPassengers = 126, - Teams = 127, - UpdateScore = 128, - SpawnPosition = 129, - TimeUpdate = 130, - StopSound = 131, - SoundEffect = 132, - PlayerListHeaderAndFooter = 133, - CollectItem = 134, - EntityTeleport = 135, - Advancements = 136, - EntityProperties = 137, - EntityEffect = 138, - DeclareRecipes = 139, - Tags = 140, - - // Status - Response = 141, - Pong = 142, -} - -lazy_static! { - static ref PACKET_ID_MAPPINGS: HashMap = { - let mut m = HashMap::new(); - - m.insert( - PacketId(0x00, PacketDirection::Serverbound, PacketStage::Handshake), - PacketType::Handshake, - ); - - m.insert( - PacketId(0x00, PacketDirection::Serverbound, PacketStage::Login), - PacketType::LoginStart, - ); - m.insert( - PacketId(0x01, PacketDirection::Serverbound, PacketStage::Login), - PacketType::EncryptionResponse, - ); - m.insert( - PacketId(0x02, PacketDirection::Serverbound, PacketStage::Login), - PacketType::LoginPluginResponse, - ); - - m.insert( - PacketId(0x00, PacketDirection::Serverbound, PacketStage::Play), - PacketType::TeleportConfirm, - ); - m.insert( - PacketId(0x01, PacketDirection::Serverbound, PacketStage::Play), - PacketType::QueryBlockNBT, - ); - m.insert( - PacketId(0x02, PacketDirection::Serverbound, PacketStage::Play), - PacketType::ChatMessageServerbound, - ); - m.insert( - PacketId(0x03, PacketDirection::Serverbound, PacketStage::Play), - PacketType::ClientStatus, - ); - m.insert( - PacketId(0x04, PacketDirection::Serverbound, PacketStage::Play), - PacketType::ClientSettings, - ); - m.insert( - PacketId(0x05, PacketDirection::Serverbound, PacketStage::Play), - PacketType::TabCompleteServerbound, - ); - m.insert( - PacketId(0x06, PacketDirection::Serverbound, PacketStage::Play), - PacketType::ConfirmTransactionServerbound, - ); - m.insert( - PacketId(0x07, PacketDirection::Serverbound, PacketStage::Play), - PacketType::EnchantItem, - ); - m.insert( - PacketId(0x08, PacketDirection::Serverbound, PacketStage::Play), - PacketType::ClickWindow, - ); - m.insert( - PacketId(0x09, PacketDirection::Serverbound, PacketStage::Play), - PacketType::CloseWindowServerbound, - ); - m.insert( - PacketId(0x0A, PacketDirection::Serverbound, PacketStage::Play), - PacketType::PluginMessageServerbound, - ); - m.insert( - PacketId(0x0B, PacketDirection::Serverbound, PacketStage::Play), - PacketType::EditBook, - ); - m.insert( - PacketId(0x0C, PacketDirection::Serverbound, PacketStage::Play), - PacketType::QueryEntityNBT, - ); - m.insert( - PacketId(0x0D, PacketDirection::Serverbound, PacketStage::Play), - PacketType::UseEntity, - ); - m.insert( - PacketId(0x0E, PacketDirection::Serverbound, PacketStage::Play), - PacketType::KeepAliveServerbound, - ); - m.insert( - PacketId(0x0F, PacketDirection::Serverbound, PacketStage::Play), - PacketType::Player, - ); - m.insert( - PacketId(0x10, PacketDirection::Serverbound, PacketStage::Play), - PacketType::PlayerPosition, - ); - m.insert( - PacketId(0x11, PacketDirection::Serverbound, PacketStage::Play), - PacketType::PlayerPositionAndLookServerbound, - ); - m.insert( - PacketId(0x12, PacketDirection::Serverbound, PacketStage::Play), - PacketType::PlayerLook, - ); - m.insert( - PacketId(0x13, PacketDirection::Serverbound, PacketStage::Play), - PacketType::VehicleMoveServerbound, - ); - m.insert( - PacketId(0x14, PacketDirection::Serverbound, PacketStage::Play), - PacketType::SteerBoat, - ); - m.insert( - PacketId(0x15, PacketDirection::Serverbound, PacketStage::Play), - PacketType::PickItem, - ); - m.insert( - PacketId(0x16, PacketDirection::Serverbound, PacketStage::Play), - PacketType::CraftRecipeRequest, - ); - m.insert( - PacketId(0x17, PacketDirection::Serverbound, PacketStage::Play), - PacketType::PlayerAbilitiesServerbound, - ); - m.insert( - PacketId(0x18, PacketDirection::Serverbound, PacketStage::Play), - PacketType::PlayerDigging, - ); - m.insert( - PacketId(0x19, PacketDirection::Serverbound, PacketStage::Play), - PacketType::EntityAction, - ); - m.insert( - PacketId(0x1A, PacketDirection::Serverbound, PacketStage::Play), - PacketType::SteerVehicle, - ); - m.insert( - PacketId(0x1B, PacketDirection::Serverbound, PacketStage::Play), - PacketType::RecipeBookData, - ); - m.insert( - PacketId(0x1C, PacketDirection::Serverbound, PacketStage::Play), - PacketType::NameItem, - ); - m.insert( - PacketId(0x1D, PacketDirection::Serverbound, PacketStage::Play), - PacketType::ResourcePackStatus, - ); - m.insert( - PacketId(0x1E, PacketDirection::Serverbound, PacketStage::Play), - PacketType::AdvancementTab, - ); - m.insert( - PacketId(0x1F, PacketDirection::Serverbound, PacketStage::Play), - PacketType::SelectTrade, - ); - m.insert( - PacketId(0x20, PacketDirection::Serverbound, PacketStage::Play), - PacketType::SetBeaconEffect, - ); - m.insert( - PacketId(0x21, PacketDirection::Serverbound, PacketStage::Play), - PacketType::HeldItemChangeServerbound, - ); - m.insert( - PacketId(0x22, PacketDirection::Serverbound, PacketStage::Play), - PacketType::UpdateCommandBlock, - ); - m.insert( - PacketId(0x23, PacketDirection::Serverbound, PacketStage::Play), - PacketType::UpdateCommandBlockMinecart, - ); - m.insert( - PacketId(0x24, PacketDirection::Serverbound, PacketStage::Play), - PacketType::CreativeInventoryAction, - ); - m.insert( - PacketId(0x25, PacketDirection::Serverbound, PacketStage::Play), - PacketType::UpdateStructureBlock, - ); - m.insert( - PacketId(0x26, PacketDirection::Serverbound, PacketStage::Play), - PacketType::UpdateSign, - ); - m.insert( - PacketId(0x27, PacketDirection::Serverbound, PacketStage::Play), - PacketType::AnimationServerbound, - ); - m.insert( - PacketId(0x28, PacketDirection::Serverbound, PacketStage::Play), - PacketType::Spectate, - ); - m.insert( - PacketId(0x29, PacketDirection::Serverbound, PacketStage::Play), - PacketType::PlayerBlockPlacement, - ); - m.insert( - PacketId(0x2A, PacketDirection::Serverbound, PacketStage::Play), - PacketType::UseItem, - ); - - m.insert( - PacketId(0x00, PacketDirection::Serverbound, PacketStage::Status), - PacketType::Request, - ); - m.insert( - PacketId(0x01, PacketDirection::Serverbound, PacketStage::Status), - PacketType::Ping, - ); - - m.insert( - PacketId(0x00, PacketDirection::Clientbound, PacketStage::Login), - PacketType::DisconnectLogin, - ); - m.insert( - PacketId(0x01, PacketDirection::Clientbound, PacketStage::Login), - PacketType::EncryptionRequest, - ); - m.insert( - PacketId(0x02, PacketDirection::Clientbound, PacketStage::Login), - PacketType::LoginSuccess, - ); - m.insert( - PacketId(0x03, PacketDirection::Clientbound, PacketStage::Login), - PacketType::SetCompression, - ); - m.insert( - PacketId(0x04, PacketDirection::Clientbound, PacketStage::Login), - PacketType::LoginPluginRequest, - ); - - m.insert( - PacketId(0x00, PacketDirection::Clientbound, PacketStage::Status), - PacketType::Response, - ); - - m.insert( - PacketId(0x01, PacketDirection::Clientbound, PacketStage::Status), - PacketType::Pong, - ); - - m.insert( - PacketId(0x00, PacketDirection::Clientbound, PacketStage::Play), - PacketType::SpawnObject, - ); - - m.insert( - PacketId(0x03, PacketDirection::Clientbound, PacketStage::Play), - PacketType::SpawnMob, - ); - - m.insert( - PacketId(0x06, PacketDirection::Clientbound, PacketStage::Play), - PacketType::AnimationClientbound, - ); - - m.insert( - PacketId(0x0E, PacketDirection::Clientbound, PacketStage::Play), - PacketType::ChatMessageClientbound, - ); - - m.insert( - PacketId(0x17, PacketDirection::Clientbound, PacketStage::Play), - PacketType::SetSlot, - ); - - m.insert( - PacketId(0x1B, PacketDirection::Clientbound, PacketStage::Play), - PacketType::DisconnectPlay, - ); - - m.insert( - PacketId(0x1F, PacketDirection::Clientbound, PacketStage::Play), - PacketType::UnloadChunk, - ); - - m.insert( - PacketId(0x21, PacketDirection::Clientbound, PacketStage::Play), - PacketType::KeepAliveClientbound, - ); - - m.insert( - PacketId(0x05, PacketDirection::Clientbound, PacketStage::Play), - PacketType::SpawnPlayer, - ); - - m.insert( - PacketId(0x0B, PacketDirection::Clientbound, PacketStage::Play), - PacketType::BlockChange, - ); - - m.insert( - PacketId(0x22, PacketDirection::Clientbound, PacketStage::Play), - PacketType::ChunkData, - ); - - m.insert( - PacketId(0x25, PacketDirection::Clientbound, PacketStage::Play), - PacketType::JoinGame, - ); - - m.insert( - PacketId(0x28, PacketDirection::Clientbound, PacketStage::Play), - PacketType::EntityRelativeMove, - ); - - m.insert( - PacketId(0x29, PacketDirection::Clientbound, PacketStage::Play), - PacketType::EntityLookAndRelativeMove, - ); - - m.insert( - PacketId(0x2A, PacketDirection::Clientbound, PacketStage::Play), - PacketType::EntityLook, - ); - - m.insert( - PacketId(0x30, PacketDirection::Clientbound, PacketStage::Play), - PacketType::PlayerInfo, - ); - - m.insert( - PacketId(0x32, PacketDirection::Clientbound, PacketStage::Play), - PacketType::PlayerPositionAndLookClientbound, - ); - - m.insert( - PacketId(0x35, PacketDirection::Clientbound, PacketStage::Play), - PacketType::DestroyEntities, - ); - - m.insert( - PacketId(0x37, PacketDirection::Clientbound, PacketStage::Play), - PacketType::ResourcePackSend, - ); - - m.insert( - PacketId(0x39, PacketDirection::Clientbound, PacketStage::Play), - PacketType::EntityHeadLook, - ); - - m.insert( - PacketId(0x3F, PacketDirection::Clientbound, PacketStage::Play), - PacketType::EntityMetadata, - ); - - m.insert( - PacketId(0x41, PacketDirection::Clientbound, PacketStage::Play), - PacketType::EntityVelocity, - ); - - m.insert( - PacketId(0x42, PacketDirection::Clientbound, PacketStage::Play), - PacketType::EntityEquipment, - ); - - m.insert( - PacketId(0x49, PacketDirection::Clientbound, PacketStage::Play), - PacketType::SpawnPosition, - ); - - m.insert( - PacketId(0x4A, PacketDirection::Clientbound, PacketStage::Play), - PacketType::TimeUpdate, - ); - - m.insert( - PacketId(0x4F, PacketDirection::Clientbound, PacketStage::Play), - PacketType::CollectItem, - ); - - m - }; - static ref PACKET_TYPE_MAPPINGS: HashMap = { - let mut m = HashMap::new(); - - for (key, val) in PACKET_ID_MAPPINGS.clone().into_iter() { - m.insert(val, key); - } - - m - }; -} - -impl PacketType { - pub fn get_from_id(id: PacketId) -> Result { - PACKET_ID_MAPPINGS.get(&id).copied().ok_or(()) - } - - pub fn get_id(self) -> PacketId { - *PACKET_TYPE_MAPPINGS.get(&self).unwrap() - } - - pub fn get_implementation(self) -> Box { - implementation::IMPL_MAP.get(&self).unwrap().build() - } - - /// Returns a unique ID, allocated - /// consecutively for each packet type. - pub fn ordinal(self) -> usize { - self as usize - } -} - -/// Certain packets have the same ID as -/// another packet during a different login stage (blame Mojang), -/// so this struct is used to differentiate between packets like that. -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] -pub struct PacketId(pub u32, pub PacketDirection, pub PacketStage); - -#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] -pub enum PacketDirection { - Serverbound, - Clientbound, -} - -#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] -pub enum PacketStage { - Handshake, - Status, - Login, - Play, -} diff --git a/core/src/prelude.rs b/core/src/prelude.rs deleted file mode 100644 index 23662a0f0..000000000 --- a/core/src/prelude.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub use super::{ - world::{block::*, BlockPosition, ChunkMap, ChunkPosition, Position}, - Difficulty, Dimension, Gamemode, PvpStyle, -}; -pub use crate::network::cast_packet; -pub use uuid::Uuid; diff --git a/core/src/save/entity.rs b/core/src/save/entity.rs deleted file mode 100644 index 48b05e225..000000000 --- a/core/src/save/entity.rs +++ /dev/null @@ -1,331 +0,0 @@ -use crate::{Item, Position}; -use nbt::Value; -use std::collections::HashMap; - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "id")] -pub enum EntityData { - #[serde(rename = "minecraft:item")] - Item(ItemEntityData), - #[serde(rename = "minecraft:arrow")] - Arrow(ArrowEntityData), - #[serde(rename = "minecraft:cow")] - Cow(AnimalData), - #[serde(rename = "minecraft:pig")] - Pig(AnimalData), - #[serde(rename = "minecraft:chicken")] - Chicken(AnimalData), - #[serde(rename = "minecraft:sheep")] - Sheep(AnimalData), - #[serde(rename = "minecraft:horse")] - Horse(AnimalData), - #[serde(rename = "minecraft:llama")] - Llama(AnimalData), - #[serde(rename = "minectaft:mooshroom")] - Mooshroom(AnimalData), - #[serde(rename = "minecraft:rabbit}")] - Rabbit(AnimalData), - #[serde(rename = "minecraft:squid")] - Squid(AnimalData), - #[serde(rename = "minecraft:donkey")] - Donkey(AnimalData), - - /// Fallback type for unknown entities - #[serde(other)] - Unknown, -} - -impl EntityData { - pub fn into_nbt_value(self) -> Value { - let mut map = HashMap::new(); - - map.insert( - String::from("id"), - Value::String( - match self { - EntityData::Item(_) => "minecraft:item", - EntityData::Arrow(_) => "minecraft:arrow", - EntityData::Cow(_) => "minecraft:cow", - EntityData::Pig(_) => "minecraft:pig", - EntityData::Chicken(_) => "minecraft:chicken", - EntityData::Sheep(_) => "minecraft:sheep", - EntityData::Horse(_) => "minecraft:horse", - EntityData::Llama(_) => "minecraft:llama", - EntityData::Mooshroom(_) => "minecraft:mooshroom", - EntityData::Rabbit(_) => "minecraft:rabbit", - EntityData::Squid(_) => "minecraft:squid", - EntityData::Donkey(_) => "minecraft:donkey", - EntityData::Unknown => panic!("Cannot write unknown entities"), - } - .to_string(), - ), - ); - - match self { - EntityData::Item(data) => data.write_to_map(&mut map), - EntityData::Arrow(data) => data.write_to_map(&mut map), - EntityData::Cow(data) => data.write_to_map(&mut map), - EntityData::Pig(data) => data.write_to_map(&mut map), - EntityData::Chicken(data) => data.write_to_map(&mut map), - EntityData::Sheep(data) => data.write_to_map(&mut map), - EntityData::Horse(data) => data.write_to_map(&mut map), - EntityData::Llama(data) => data.write_to_map(&mut map), - EntityData::Mooshroom(data) => data.write_to_map(&mut map), - EntityData::Rabbit(data) => data.write_to_map(&mut map), - EntityData::Squid(data) => data.write_to_map(&mut map), - EntityData::Donkey(data) => data.write_to_map(&mut map), - EntityData::Unknown => unreachable!(), - } - - Value::Compound(map) - } -} - -/// Common entity tags. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BaseEntityData { - #[serde(rename = "Pos")] - pub position: Vec, - #[serde(rename = "Rotation")] - pub rotation: Vec, - #[serde(rename = "Motion")] - pub velocity: Vec, -} - -impl BaseEntityData { - fn write_to_map(self, map: &mut HashMap) { - map.insert( - String::from("Pos"), - Value::List(self.position.into_iter().map(Value::Double).collect()), - ); - map.insert( - String::from("Rotation"), - Value::List(self.rotation.into_iter().map(Value::Float).collect()), - ); - map.insert( - String::from("Motion"), - Value::List(self.velocity.into_iter().map(Value::Double).collect()), - ); - } -} - -impl BaseEntityData { - /// Creates a `BaseEntityData` from a position and velocity. - pub fn new(pos: Position, velocity: glm::DVec3) -> Self { - Self { - position: vec![pos.x, pos.y, pos.z], - rotation: vec![pos.yaw, pos.pitch], - velocity: vec![velocity.x, velocity.y, velocity.z], - } - } - - /// Reads the position and rotation fields. If the fields are invalid, None is returned. - pub fn read_position(self: &BaseEntityData) -> Option { - if self.position.len() == 3 && self.rotation.len() == 2 { - Some(Position { - x: self.position[0], - y: self.position[1], - z: self.position[2], - yaw: self.rotation[0], - pitch: self.rotation[1], - on_ground: true, - }) - } else { - None - } - } - - /// Reads the velocity field. If the field is invalid, None is returned. - pub fn read_velocity(self: &BaseEntityData) -> Option { - if self.velocity.len() == 3 { - Some(glm::vec3( - self.velocity[0], - self.velocity[1], - self.velocity[2], - )) - } else { - None - } - } -} - -impl Default for BaseEntityData { - fn default() -> Self { - BaseEntityData { - position: vec![0.0, 0.0, 0.0], - rotation: vec![0.0, 0.0], - velocity: vec![0.0, 0.0, 0.0], - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AnimalData { - #[serde(flatten)] - pub base: BaseEntityData, -} - -impl AnimalData { - fn write_to_map(self, map: &mut HashMap) { - self.base.write_to_map(map); - } -} - -/// Represents a single item, without slot information. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ItemData { - #[serde(rename = "Count")] - pub count: u8, - #[serde(rename = "id")] - pub item: String, -} - -impl ItemData { - fn write_to_map(self, map: &mut HashMap) { - map.insert(String::from("Count"), Value::Byte(self.count as i8)); - map.insert(String::from("id"), Value::String(self.item)); - } -} - -impl Default for ItemData { - fn default() -> Self { - Self { - count: 0, - item: Item::Air.identifier().to_string(), - } - } -} - -/// Data for an Item entity (`minecraft:item`). -#[derive(Clone, Default, Serialize, Deserialize, Debug)] -pub struct ItemEntityData { - // Inherit base entity data - #[serde(flatten)] - pub entity: BaseEntityData, - - // Item-specific tags - #[serde(rename = "Age")] - pub age: i16, - #[serde(rename = "PickupDelay")] - pub pickup_delay: u8, - #[serde(rename = "Item")] - pub item: ItemData, -} - -impl ItemEntityData { - fn write_to_map(self, map: &mut HashMap) { - self.entity.write_to_map(map); - - let mut item = HashMap::new(); - self.item.write_to_map(&mut item); - map.insert(String::from("Item"), Value::Compound(item)); - - map.insert(String::from("Age"), Value::Short(self.age)); - map.insert( - String::from("PickupDelay"), - Value::Byte(self.pickup_delay as i8), - ); - } -} - -/// Data for an Arrow entity (`minecraft:arrow`). -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct ArrowEntityData { - // Inherit base entity data - #[serde(flatten)] - pub entity: BaseEntityData, - - // Arrow-specific tags - - // TODO: Change this field to `bool` when issue with hematite_nbt is resolved. - // See: https://github.com/PistonDevelopers/hematite_nbt/issues/43 - #[serde(rename = "crit")] - pub critical: u8, -} - -impl ArrowEntityData { - fn write_to_map(self, map: &mut HashMap) { - self.entity.write_to_map(map); - - map.insert(String::from("crit"), Value::Byte(self.critical as i8)); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_read_position() { - let data = BaseEntityData { - position: vec![1.0, 2.0, 3.0], - rotation: vec![4.0, 5.0], - velocity: vec![6.0, 7.0, 8.0], - }; - let pos = data.read_position().unwrap(); - - assert!(pos.x - 1.0 < std::f64::EPSILON); - assert!(pos.y - 2.0 < std::f64::EPSILON); - assert!(pos.z - 3.0 < std::f64::EPSILON); - assert!(pos.yaw - 4.0 < std::f32::EPSILON); - assert!(pos.pitch - 5.0 < std::f32::EPSILON); - assert!(pos.on_ground); - } - - #[test] - fn test_read_position_invalid() { - let data = BaseEntityData { - position: vec![1.0], - rotation: vec![4.0, 5.0], - velocity: vec![6.0, 7.0, 8.0], - }; - let pos = data.read_position(); - assert!(pos.is_none()); - } - - #[test] - fn test_read_position_invalid_rot() { - let data = BaseEntityData { - position: vec![1.0, 2.0, 3.0], - rotation: vec![4.0], - velocity: vec![6.0, 7.0, 8.0], - }; - let pos = data.read_position(); - assert!(pos.is_none()); - } - - #[test] - fn test_read_velocity() { - let data = BaseEntityData { - position: vec![1.0, 2.0, 3.0], - rotation: vec![4.0, 5.0], - velocity: vec![6.0, 7.0, 8.0], - }; - let vel = data.read_velocity().unwrap(); - - assert!(vel[0] - 6.0 < std::f64::EPSILON); - assert!(vel[1] - 7.0 < std::f64::EPSILON); - assert!(vel[2] - 8.0 < std::f64::EPSILON); - } - - #[test] - fn test_read_velocity_invalid() { - let data = BaseEntityData { - position: vec![1.0, 2.0, 3.0], - rotation: vec![4.0, 5.0], - velocity: vec![6.0, 7.0], - }; - let vel = data.read_velocity(); - assert!(vel.is_none()); - } - - #[test] - fn test_new() { - let pos = position!(1.0, 10.0, 3.0, 115.0, -3.0); - let vel = glm::vec3(0.0, 1.0, 2.0); - - let data = BaseEntityData::new(pos, vel); - assert_eq!(data.read_position(), Some(pos)); - assert_eq!(data.read_velocity(), Some(vel)); - } -} diff --git a/core/src/save/player.dat b/core/src/save/player.dat deleted file mode 100644 index f278da5a2..000000000 Binary files a/core/src/save/player.dat and /dev/null differ diff --git a/core/src/save/player_data.rs b/core/src/save/player_data.rs deleted file mode 100644 index ca331ce2c..000000000 --- a/core/src/save/player_data.rs +++ /dev/null @@ -1,208 +0,0 @@ -use std::fs::File; - -use crate::entity::BaseEntityData; -use crate::inventory::{ - SlotIndex, HOTBAR_SIZE, INVENTORY_SIZE, SLOT_ARMOR_MAX, SLOT_ARMOR_MIN, SLOT_HOTBAR_OFFSET, - SLOT_INVENTORY_OFFSET, SLOT_OFFHAND, -}; -use crate::ItemStack; -use feather_items::Item; -use std::fs; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; -use uuid::Uuid; - -/// Represents the contents of a player data file. -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct PlayerData { - // Inherit base entity data - #[serde(flatten)] - pub entity: BaseEntityData, - - #[serde(rename = "playerGameType")] - pub gamemode: i32, - #[serde(rename = "Inventory")] - pub inventory: Vec, -} - -/// Represents a single inventory slot (including position index). -#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct InventorySlot { - #[serde(rename = "Count")] - pub count: i8, - #[serde(rename = "Slot")] - pub slot: i8, - #[serde(rename = "id")] - pub item: String, -} - -impl InventorySlot { - /// Converts a slot to an ItemStack. - pub fn to_stack(&self) -> ItemStack { - ItemStack { - ty: Item::from_identifier(self.item.as_str()).unwrap_or(Item::Air), - amount: self.count as u8, - } - } - - /// Converts a network protocol index, item, and count - /// to an `InventorySlot`. - pub fn from_network_index(network: SlotIndex, stack: ItemStack) -> Self { - let slot = if SLOT_HOTBAR_OFFSET <= network && network < SLOT_HOTBAR_OFFSET + HOTBAR_SIZE { - // Hotbar - (network - SLOT_HOTBAR_OFFSET) as i8 - } else if network == SLOT_OFFHAND { - -106 - } else if SLOT_ARMOR_MIN <= network && network <= SLOT_ARMOR_MAX { - ((SLOT_ARMOR_MAX - network) + 100) as i8 - } else if SLOT_INVENTORY_OFFSET <= network - && network < SLOT_INVENTORY_OFFSET + INVENTORY_SIZE - { - network as i8 - } else { - panic!("Invalid slot index {} on server", network); - }; - - Self { - count: stack.amount as i8, - slot, - item: stack.ty.identifier().to_string(), - } - } - - /// Converts an NBT inventory index to a network protocol index. - /// Returns None if the index is invalid. - pub fn convert_index(&self) -> Option { - if 0 <= self.slot && self.slot <= 8 { - // Hotbar - Some(crate::inventory::SLOT_HOTBAR_OFFSET + (self.slot as usize)) - } else if self.slot == -106 { - // Offhand - Some(crate::inventory::SLOT_OFFHAND as usize) - } else if 100 <= self.slot && self.slot <= 103 { - // Equipment - Some((108 - self.slot) as usize) - } else if 9 <= self.slot && self.slot <= 35 { - // Rest of inventory - Some(self.slot as usize) - } else { - // Unknown index - None - } - } -} - -fn load_from_file(reader: R) -> Result { - nbt::from_gzip_reader::<_, PlayerData>(reader) -} - -pub fn load_player_data(world_dir: &Path, uuid: Uuid) -> Result { - let file_path = file_path(world_dir, uuid); - let file = File::open(file_path)?; - let data = load_from_file(file)?; - Ok(data) -} - -fn save_to_file(mut writer: W, data: PlayerData) -> Result<(), nbt::Error> { - nbt::to_gzip_writer(&mut writer, &data, None) -} - -pub fn save_player_data(world_dir: &Path, uuid: Uuid, data: PlayerData) -> Result<(), nbt::Error> { - fs::create_dir_all(world_dir.join("playerdata"))?; - let file_path = file_path(world_dir, uuid); - let file = File::create(file_path)?; - save_to_file(file, data) -} - -fn file_path(world_dir: &Path, uuid: Uuid) -> PathBuf { - world_dir.join("playerdata").join(format!("{}.dat", uuid)) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::Gamemode; - use hashbrown::HashMap; - use std::io::Cursor; - - #[test] - fn test_deserialize_player() { - let cursor = Cursor::new(include_bytes!("player.dat").to_vec()); - - let player = load_from_file(cursor).unwrap(); - assert_eq!(player.gamemode, i32::from(Gamemode::Creative.get_id())); - } - - #[test] - fn test_convert_item() { - let slot = InventorySlot { - count: 1, - slot: 2, - item: String::from(Item::Feather.identifier()), - }; - - let item_stack = slot.to_stack(); - assert_eq!(item_stack.ty, Item::Feather); - assert_eq!(item_stack.amount, 1); - } - - #[test] - fn test_convert_item_unknown_type() { - let slot = InventorySlot { - count: 1, - slot: 2, - item: String::from("invalid:identifier"), - }; - - let item_stack = slot.to_stack(); - assert_eq!(item_stack.ty, Item::Air); - } - - #[test] - fn test_convert_slot_index() { - let mut map: HashMap = HashMap::new(); - - // Equipment - map.insert(103, crate::inventory::SLOT_ARMOR_HEAD); - map.insert(102, crate::inventory::SLOT_ARMOR_CHEST); - map.insert(101, crate::inventory::SLOT_ARMOR_LEGS); - map.insert(100, crate::inventory::SLOT_ARMOR_FEET); - map.insert(-106, crate::inventory::SLOT_OFFHAND); - - // Hotbar - for x in 0..9 { - map.insert(x, crate::inventory::SLOT_HOTBAR_OFFSET + (x as usize)); - } - - // Rest of inventory - for x in 9..36 { - map.insert(x, x as usize); - } - - dbg!(map.clone()); - - // Check all valid slots - for (src, expected) in map { - let slot = InventorySlot { - slot: src, - count: 1, - item: String::from(Item::Stone.identifier()), - }; - assert_eq!(slot.convert_index().unwrap(), expected); - assert_eq!( - InventorySlot::from_network_index(expected, ItemStack::new(Item::Stone, 1)), - slot - ); - } - - // Check that invalid slots error out - for invalid_slot in [-1, -2, 104].iter() { - let slot = InventorySlot { - slot: *invalid_slot as i8, - count: 1, - item: String::from("invalid:identifier"), - }; - assert!(slot.convert_index().is_none()); - } - } -} diff --git a/core/src/save/region/blob.rs b/core/src/save/region/blob.rs deleted file mode 100644 index 9bb03b988..000000000 --- a/core/src/save/region/blob.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! Conversion of `ChunkRoot` to `nbt::Blob`. -//! This is required due to https://github.com/PistonDevelopers/hematite_nbt/issues/27. - -use super::ChunkLevel; -use super::{ChunkRoot, LevelSection}; -use nbt::{Blob, Value}; -use std::collections::HashMap; - -pub fn chunk_root_to_blob(root: ChunkRoot) -> Blob { - let mut blob = Blob::new(); - blob.insert("DataVersion", root.data_version).unwrap(); - - blob.insert("Level", level_to_value(root.level)).unwrap(); - - blob -} - -fn level_to_value(level: ChunkLevel) -> Value { - let mut map = HashMap::new(); - - map.insert(String::from("xPos"), Value::Int(level.x_pos)); - map.insert(String::from("zPos"), Value::Int(level.z_pos)); - map.insert(String::from("LastUpdate"), Value::Long(0)); // TODO - map.insert(String::from("InhabitedTime"), Value::Long(0)); // TODO - map.insert(String::from("Biomes"), Value::IntArray(level.biomes)); - - let mut hmaps = HashMap::new(); - hmaps.insert( - String::from("MOTION_BLOCKING"), - Value::LongArray(vec![0; 32]), - ); // TODO - hmaps.insert( - String::from("MOTION_BLOCKING_NO_LEAVES"), - Value::LongArray(vec![0; 32]), - ); // TODO - hmaps.insert(String::from("OCEAN_FLOOR"), Value::LongArray(vec![0; 32])); // TODO - hmaps.insert( - String::from("OCEAN_FLOOR_WG"), - Value::LongArray(vec![0; 32]), - ); // TODO - hmaps.insert(String::from("WORLD_SURFACE"), Value::LongArray(vec![0; 32])); // TODO - hmaps.insert( - String::from("WORLD_SURFACE_WG"), - Value::LongArray(vec![0; 32]), - ); // TODO - map.insert(String::from("Heightmaps"), Value::Compound(hmaps)); - - let sections = level.sections.into_iter().map(section_to_value).collect(); - map.insert(String::from("Sections"), Value::List(sections)); - - map.insert(String::from("TileEntities"), Value::List(vec![])); // TODO - map.insert(String::from("ToBeTicked"), Value::List(vec![])); // TODO - - let mut liquids_to_be_ticked = vec![]; - (0..16).for_each(|_| liquids_to_be_ticked.push(Value::List(vec![]))); - map.insert( - String::from("LiquidsToBeTicked"), - Value::List(liquids_to_be_ticked), - ); - - let mut tile_ticks = vec![]; - (0..16).for_each(|_| tile_ticks.push(Value::List(vec![]))); - map.insert(String::from("TileTicks"), Value::List(tile_ticks)); - - let mut post_processing = vec![]; - (0..16).for_each(|_| post_processing.push(Value::List(vec![]))); - map.insert(String::from("PostProcessing"), Value::List(post_processing)); - - map.insert(String::from("LiquidTicks"), Value::List(vec![])); - - let mut structures = HashMap::new(); - - { - let mut references = HashMap::new(); - references.insert(String::from("EndCity"), Value::LongArray(vec![])); - references.insert(String::from("Fortress"), Value::LongArray(vec![])); - references.insert(String::from("Monument"), Value::LongArray(vec![])); - references.insert(String::from("Stronghold"), Value::LongArray(vec![])); - references.insert(String::from("Swamp_Hut"), Value::LongArray(vec![])); - - structures.insert(String::from("References"), Value::Compound(references)); - structures.insert(String::from("Starts"), Value::Compound(HashMap::new())); - } - - map.insert( - String::from("Status"), - Value::String(String::from("postprocessed")), - ); - - // Entities - let mut entities = Vec::with_capacity(level.entities.len()); - level.entities.into_iter().for_each(|entity| { - entities.push(entity.into_nbt_value()); - }); - - map.insert(String::from("Entities"), Value::List(entities)); - - Value::Compound(map) -} - -fn section_to_value(section: LevelSection) -> Value { - let mut map = HashMap::new(); - - map.insert(String::from("Y"), Value::Byte(section.y)); - map.insert( - String::from("BlockLight"), - Value::ByteArray(section.block_light), - ); - map.insert( - String::from("SkyLight"), - Value::ByteArray(section.sky_light), - ); - map.insert( - String::from("BlockStates"), - Value::LongArray(section.states), - ); - - let mut entries = vec![]; - for entry in section.palette { - let mut map = HashMap::new(); - map.insert(String::from("Name"), Value::String(entry.name)); - - if let Some(props) = entry.props { - let mut props_map = HashMap::new(); - props.props.into_iter().for_each(|(name, value)| { - props_map.insert(name, Value::String(value)); - }); - map.insert(String::from("Properties"), Value::Compound(props_map)); - } - - entries.push(Value::Compound(map)) - } - - map.insert(String::from("Palette"), Value::List(entries)); - - Value::Compound(map) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::region::DATA_VERSION; - use std::io::Cursor; - - #[test] - fn test_to_blob_roundtrip() { - let root = ChunkRoot { - data_version: DATA_VERSION, - level: ChunkLevel { - x_pos: 0, - z_pos: 0, - sections: vec![LevelSection { - y: 0, - states: vec![0], - palette: vec![], - block_light: vec![0], - sky_light: vec![0], - }], - biomes: vec![10], - entities: vec![], - }, - }; - - let blob = chunk_root_to_blob(root); - - let mut buf = vec![]; - blob.to_writer(&mut buf).unwrap(); - - let _: ChunkRoot = nbt::from_reader(Cursor::new(&buf)).unwrap(); - } -} diff --git a/core/src/world/block.rs b/core/src/world/block.rs deleted file mode 100644 index 0e25cfce8..000000000 --- a/core/src/world/block.rs +++ /dev/null @@ -1 +0,0 @@ -pub use feather_blocks::*; diff --git a/core/src/world/chunk.rs b/core/src/world/chunk.rs deleted file mode 100644 index 7ecd51e8f..000000000 --- a/core/src/world/chunk.rs +++ /dev/null @@ -1,1217 +0,0 @@ -use super::block::*; -use super::ChunkPosition; -use crate::Biome; -use multimap::MultiMap; - -/// The number of bits used for each block -/// in the global palette. -const GLOBAL_BITS_PER_BLOCK: u8 = 14; - -/// The minimum bits per block allowed when -/// using a section palette. -/// Bits per block values lower than this -/// value will be offsetted to this value. -const MIN_BITS_PER_BLOCK: u8 = 4; - -/// The maximum number of bits per block -/// allowed when using a section palette. -/// Values above this will use the global palette -/// instead. -const MAX_BITS_PER_BLOCK: u8 = 8; - -/// The height in blocks of a chunk column. -const CHUNK_HEIGHT: usize = 256; -/// The width in blocks of a chunk column. -const CHUNK_WIDTH: usize = 16; - -/// The height in blocks of a chunk section. -const SECTION_HEIGHT: usize = 16; - -/// The width in blocks of a chunk section. -const SECTION_WIDTH: usize = CHUNK_WIDTH; - -/// The volume in blocks of a chunk section. -const SECTION_VOLUME: usize = (SECTION_HEIGHT * SECTION_WIDTH * SECTION_WIDTH) as usize; - -/// The number of chunk sections in a column. -const NUM_SECTIONS: usize = 16; - -/// A chunk column consisting -/// of a 16x256x16 section of blocks. -/// A chunk column maintains an array -/// of up to 16 chunk sections, each corresponding -/// to a 16x16x16 section of blocks in the chunk. -#[derive(Clone)] -pub struct Chunk { - /// The location of this chunk, in chunk - /// coordinates. - location: ChunkPosition, - /// An array of the sections in this chunk. - /// A section with Y value `y` can be found at - /// index `y` in this array. - /// When an entry in this array is set to `None`, - /// the section at the entry's Y coordinate - /// is assumed to empty, meaning that it consists - /// of only air. - sections: [Option; NUM_SECTIONS], - /// The biomes in this section, indexable by - /// ((z << 4) | x). - biomes: [Biome; SECTION_WIDTH * SECTION_WIDTH], - /// Whether this chunk has been modified since the most recent - /// call to `check_modified`(). - modified: bool, -} - -impl Default for Chunk { - fn default() -> Self { - // Rust apparently forces you to implement - // `Copy` on types if you want to use the - // `[ChunkSection::new(); 16]` syntax, - // so I had to do this. - let sections = [ - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, - ]; - - Self { - location: ChunkPosition::new(0, 0), - modified: true, - sections, - biomes: [Biome::Plains; SECTION_WIDTH * SECTION_WIDTH], - } - } -} - -impl Chunk { - /// Creates a new empty chunk - /// with the specified location. - pub fn new(location: ChunkPosition) -> Self { - Self { - location, - modified: true, - ..Default::default() - } - } - - /// Creates a new empty chunk - /// with the specified location, - /// and filling its biomes with - /// the provided `default_biome`. - pub fn new_with_default_biome(location: ChunkPosition, default_biome: Biome) -> Self { - Self { - location, - modified: true, - biomes: [default_biome; SECTION_WIDTH * SECTION_HEIGHT], - ..Default::default() - } - } - - /// Gets the block at the specified - /// position in this chunk. The position - /// is in the chunk's local coordinate - /// space. - /// - /// The specified coordinates must be inside - /// this chunk, so the function will panic - /// if `x >= 16 || y >= 256 || z >= 16`. - pub fn block_at(&self, x: usize, y: usize, z: usize) -> Block { - Self::check_coords(x, y, z); - let chunk_section = &self.sections[(y / 16) as usize]; - match chunk_section { - Some(section) => section.block_at(x, y % 16, z), - None => Block::Air, - } - } - - /// Sets the block at the specified - /// position in this chunk. The position - /// is in the chunk's local coordinate - /// space. - /// - /// The specified coordinates must be inside - /// this chunk, so the function will panic - /// if `x >= 16 || y >= 256 || z >= 16`. - pub fn set_block_at(&mut self, x: usize, y: usize, z: usize, block: Block) { - Self::check_coords(x, y, z); - self.modified = true; - - let chunk_section = &mut self.sections[y / 16]; - - let section; - if let Some(sec) = chunk_section { - section = sec; - } else { - // The section is empty - create it - if block == Block::Air { - return; // Nothing to do - section already empty - } - - let new_section = ChunkSection::default(); - self.set_section_at(y / 16, Some(new_section)); - section = self.section_mut(y / 16).unwrap(); - } - - section.set_block_at(x, y % 16, z, block); - } - - pub fn sky_light_at(&self, x: usize, y: usize, z: usize) -> u8 { - Self::check_coords(x, y, z); - let chunk_section = self.section_for_y(y); - match chunk_section { - Some(chunk_section) => chunk_section.sky_light_at(x, y % 16, z), - None => 0, - } - } - - pub fn block_light_at(&self, x: usize, y: usize, z: usize) -> u8 { - Self::check_coords(x, y, z); - let chunk_section = self.section_for_y(y); - match chunk_section { - Some(chunk_section) => chunk_section.block_light_at(x, y % 16, z), - None => 0, - } - } - - pub fn set_sky_light_at(&mut self, x: usize, y: usize, z: usize, value: u8) { - Self::check_coords(x, y, z); - let chunk_section = self.section_for_y_mut(y); - chunk_section.set_sky_light_at(x, y % 16, z, value); - } - - pub fn set_block_light_at(&mut self, x: usize, y: usize, z: usize, value: u8) { - Self::check_coords(x, y, z); - let chunk_section = self.section_for_y_mut(y); - chunk_section.set_block_light_at(x, y % 16, z, value); - } - - fn section_for_y(&self, y: usize) -> &Option { - &self.sections[y / 16] - } - - fn section_for_y_mut(&mut self, y: usize) -> &mut ChunkSection { - self.sections[y / 16].get_or_insert_with(ChunkSection::default) - } - - fn check_coords(x: usize, y: usize, z: usize) { - assert!(x < CHUNK_WIDTH); - assert!(y < CHUNK_HEIGHT); - assert!(z < CHUNK_WIDTH); - } - - /// Returns a slice of the 16 - /// chunk sections in the chunk. - pub fn sections(&self) -> Vec> { - self.sections.iter().map(|sec| sec.as_ref()).collect() - } - - /// Returns a mutable slice of the 16 sections - /// in this chunk. - pub fn sections_mut(&mut self) -> Vec> { - self.modified = true; - self.sections.iter_mut().map(|sec| sec.as_mut()).collect() - } - - /// Returns the position in chunk coordinates - /// of this chunk. - pub fn position(&self) -> ChunkPosition { - self.location - } - - /// Returns a reference to the chunk section at the given - /// Y offset. The Y offset must be between 0 and 15, inclusive; - /// each Y offset value corresponds to 16 blocks vertically. - /// - /// If this function returns `None`, the section is assumed - /// to be empty, meaning it consists only of air. - pub fn section(&self, index: usize) -> Option<&ChunkSection> { - assert!(index < NUM_SECTIONS); - self.sections[index].as_ref() - } - - /// Returns a mutable reference to the chunk section at the given - /// Y offset. The Y offset must be between 0 and 15, inclusive; - /// each Y offset value corresponds to 16 blocks vertically. - /// - /// If this function returns `None`, the section is assumed - /// to be empty, meaning it consists only of air. - pub fn section_mut(&mut self, index: usize) -> Option<&mut ChunkSection> { - assert!(index < NUM_SECTIONS); - self.modified = true; - self.sections[index].as_mut() - } - - /// Sets the section at the given section index. - pub fn set_section_at(&mut self, index: usize, section: Option) { - assert!(index < NUM_SECTIONS); - self.sections[index] = section; - self.modified = true; - } - - /// Optimizes each section in this chunk. - /// - /// Returns the number of sections which were actually - /// optimized - sections which have not been - /// modified since the last time they were optimized - /// are not optimized. - pub fn optimize(&mut self) -> u32 { - let modified = self.modified; - let mut count = 0; - let mut to_remove = vec![]; - for (i, s) in self.sections.iter_mut().enumerate() { - if let Some(section) = s { - if section.optimize() { - // Section was optimized - increment count - count += 1; - } - - if section.empty() { - to_remove.push(i); - } - } - } - - for i in to_remove { - self.set_section_at(i, None); - } - - self.modified = modified; - - count - } - - /// Returns the biomes of this chunk. - pub fn biomes(&self) -> &[Biome] { - &self.biomes - } - - /// Returns a mutable reference to the biomes of this chunk. - pub fn biomes_mut(&mut self) -> &mut [Biome] { - self.modified = true; - &mut self.biomes - } - - /// Gets the biome for the specified column. - /// - /// # Panics - /// Panics if `x < 16` or `z < 16`. - pub fn biome_at(&self, x: usize, z: usize) -> Biome { - let index = Self::biome_index(x, z); - self.biomes[index] - } - - /// Sets the biome for the specified column. - /// - /// # Panics - /// Panics if `x < 16` or `z < 16`. - pub fn set_biome_at(&mut self, x: usize, z: usize, biome: Biome) { - let index = Self::biome_index(x, z); - self.modified = true; - self.biomes[index] = biome; - } - - /// Checks whether this chunk has been modified since the last - /// call to this function. - pub fn check_modified(&mut self) -> bool { - let res = self.modified; - self.modified = false; - res - } - - fn biome_index(x: usize, z: usize) -> usize { - assert!(x < 16); - assert!(z < 16); - - (z << 4) | x - } -} - -/// A chunk section consisting of a 16x16x16 -/// cube of blocks. -#[derive(Clone, Debug)] -pub struct ChunkSection { - /// The block state data for this chunk section. - data: BitArray, - /// This section's palette. `None` if using the global palette. - /// The palette should always remain sorted so that a binary - /// search can be performed on it. - palette: Option>, - /// The number of solid blocks in this chunk, i.e. those - /// that are not air. This value is used to figure out when - /// the section becomes empty. - solid_block_count: u16, - - block_light: BitArray, - sky_light: BitArray, - - /// A section is considered dirty when it has been - /// modified since the last time it was optimized. - dirty: bool, -} - -impl ChunkSection { - /// Creates a new, empty `ChunkSection`. - pub fn new( - mut data: BitArray, - mut palette: Option>, - block_light: BitArray, - sky_light: BitArray, - ) -> Self { - // Correct palette if not using the global palette - if let Some(palette) = palette.as_mut() { - Self::correct_data_and_palette(&mut data, palette); - } - - // Count solid blocks - let mut solid_block_count = 0; - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - if data.get(block_index(x, y, z)) != 0 { - solid_block_count += 1; - } - } - } - } - - Self { - data, - palette, - solid_block_count, - dirty: false, - block_light, - sky_light, - } - } - - /// Corrects a given raw palette and data array. - /// - /// Since chunk data stored by external sources - /// (e.g. Vanilla) might not require a sorted palette - /// like Feather does, we need to sort the palette and - /// correct data in the array when reading from external - /// sources. - /// - /// The correction is done in-place. - fn correct_data_and_palette(data: &mut BitArray, palette: &mut Vec) { - let original_palette = palette.clone(); // Palette without sorting guarantees - - palette.sort_unstable(); - - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - // Replace index into palette of each block with - // new index into the sorted palette. - let block_index = block_index(x, y, z); - let old_index = data.get(block_index); - let new_index = palette - .binary_search(&original_palette[old_index as usize]) - .unwrap(); - data.set(block_index, new_index as u64); - } - } - } - } - - /// Returns whether this chunk section is empty. - pub fn empty(&self) -> bool { - self.solid_block_count == 0 - } - - /// Retrieves the block at the given position in this chunk section. - /// The position is local to this section. - pub fn block_at(&self, x: usize, y: usize, z: usize) -> Block { - let index = block_index(x, y, z); - let block_id = self.data.get(index); - - let global_id = match &self.palette { - Some(palette) => palette[block_id as usize] as u16, - None => block_id as u16, - }; - - Block::from_native_state_id(global_id).unwrap() - } - - /// Sets the block at the given position in this chunk section. - /// The position is local to this section. - pub fn set_block_at(&mut self, x: usize, y: usize, z: usize, block: Block) { - self.dirty = true; - - let index = block_index(x, y, z); - let block_id = block.native_state_id(); - - // The value that will be put into the - let mut paletted_index; - if let Some(palette) = self.palette.as_mut() { - // Retrieve the block index from the palette. - - // If necessary, add the block to the palette. - match palette.binary_search(&block_id) { - Ok(index) => paletted_index = index, - Err(insertion_index) => { - palette.insert(insertion_index, block_id); - paletted_index = insertion_index; - - // Resize if necessary - if needed_bits((palette.len() - 1) as u64) > self.data.bits_per_value { - let new_bits_per_value = self.data.bits_per_value + 1; - if new_bits_per_value <= MAX_BITS_PER_BLOCK { - self.data = self.data.resize_to(self.data.bits_per_value + 1).unwrap(); - paletted_index = insertion_index; - } else { - // Switch to the global palette - let mut new_data = BitArray::new(GLOBAL_BITS_PER_BLOCK, SECTION_VOLUME); - for _x in 0..16 { - for _y in 0..16 { - for _z in 0..16 { - let block = self.block_at(_x, _y, _z); - new_data.set( - block_index(_x, _y, _z), - block.native_state_id() as u64, - ); - } - } - } - - self.palette = None; - paletted_index = block_id as usize; - self.data = new_data; - } - } - - // Correct data, since palette entries after - // the one which was inserted will be offsetted - // by one. - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - let index = block_index(x, y, z); - - let entry = self.data.get(index); - if entry >= insertion_index as u64 { - self.data.set(index, entry + 1); - } - } - } - } - } - } - } else { - // Use the global palette. - paletted_index = block_id as usize; - } - - let old_block = self.block_at(x, y, z); - if block == Block::Air && old_block != Block::Air { - self.solid_block_count -= 1; - } else if block != Block::Air && old_block == Block::Air { - self.solid_block_count += 1; - } - - self.data.set(index, paletted_index as u64); - debug_assert_eq!(self.block_at(x, y, z), block); - } - - /// Optimizes this chunk section, reducing the bits - /// per block value as much as possible and removing unused - /// entries from the palette. - /// - /// This function only optimizes the chunk if it is dirt, - /// i.e. if it has been modified since the last time - /// it was optimized. The returned value is `true` when - /// the chunk was optimized and `false` when it wasn't. - pub fn optimize(&mut self) -> bool { - // Only optimize the chunk if it has been modified. - if !self.dirty { - return false; - } - - self.dirty = false; - - // Replace palette with new one. - let mut new_palette = vec![]; - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - let block = self.block_at(x, y, z).native_state_id(); - match new_palette.binary_search(&block) { - Ok(_) => (), - Err(insert_index) => { - new_palette.insert(insert_index, block); - } - } - } - } - } - - // Recalculate all block IDs to match with the new palette. - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - let block = self.block_at(x, y, z).native_state_id(); - self.data.set( - block_index(x, y, z), - new_palette.binary_search(&block).unwrap() as u64, - ); - } - } - } - - self.palette = Some(new_palette); - - // Recalculate bits per block value. - let mut new_bits_per_block = needed_bits(self.palette.as_ref().unwrap().len() as u64); - if new_bits_per_block > MAX_BITS_PER_BLOCK { - self.palette = None; - } else { - if new_bits_per_block < MIN_BITS_PER_BLOCK { - new_bits_per_block = MIN_BITS_PER_BLOCK; - } - self.data = self.data.resize_to(new_bits_per_block).unwrap(); - } - - true // Chunk was optimized - } - - /// If the global palette is in use, convert it to a section palette. - /// This is used for chunk saving. - pub fn convert_palette_to_section(&mut self) { - if self.palette.is_some() { - // Nothing to do: section palette already in use. - return; - } - - let mut blocks = MultiMap::with_capacity(1024); - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - blocks.insert(self.block_at(x, y, z), (x, y, z)); - } - } - } - - // Create a palette based on the blocks in the chunk. - // We also have to modify the data array based on the new palette. - let mut palette = Vec::with_capacity(1024); - for (block, positions) in blocks.into_iter() { - palette.push(block.native_state_id()); - - for (x, y, z) in positions { - let index = block_index(x, y, z); - self.data.set(index, (palette.len() - 1) as u64); - } - } - - self.palette = Some(palette); - } - - /// Returns the internal data array for this section. - pub fn data(&self) -> &BitArray { - &self.data - } - - /// Returns the palette for this section. - pub fn palette(&self) -> Option<&Vec> { - self.palette.as_ref() - } - - /// Returns the number of bits used to store each block. - pub fn bits_per_block(&self) -> u8 { - self.data.bits_per_value - } - - pub fn sky_light(&self) -> &BitArray { - &self.sky_light - } - - pub fn block_light(&self) -> &BitArray { - &self.block_light - } - - pub fn sky_light_mut(&mut self) -> &mut BitArray { - &mut self.sky_light - } - - pub fn block_light_mut(&mut self) -> &mut BitArray { - &mut self.block_light - } - - pub fn sky_light_at(&self, x: usize, y: usize, z: usize) -> u8 { - let index = block_index(x, y, z); - self.sky_light.get(index) as u8 - } - - pub fn block_light_at(&self, x: usize, y: usize, z: usize) -> u8 { - let index = block_index(x, y, z); - self.block_light.get(index) as u8 - } - - pub fn set_sky_light_at(&mut self, x: usize, y: usize, z: usize, value: u8) { - assert!(value < 16, "light level cannot exceed 15"); - let index = block_index(x, y, z); - self.sky_light.set(index, u64::from(value)); - } - - pub fn set_block_light_at(&mut self, x: usize, y: usize, z: usize, value: u8) { - assert!(value < 16, "light level cannot exceed 15"); - let index = block_index(x, y, z); - self.block_light.set(index, u64::from(value)); - } -} - -impl Default for ChunkSection { - fn default() -> Self { - let air_id = Block::Air.native_state_id(); - Self { - data: BitArray::new(4, SECTION_VOLUME), - palette: Some(vec![air_id]), - solid_block_count: 0, - dirty: false, - block_light: BitArray::new(4, SECTION_VOLUME), - sky_light: BitArray::new(4, SECTION_VOLUME), - } - } -} - -/// Returns the index into a block state array -/// for the given block position. -fn block_index(x: usize, y: usize, z: usize) -> usize { - assert!(x < 16); - assert!(y < 16); - assert!(z < 16); - (y << 8) | (z << 4) | x -} - -/// A "bit array." This struct manages -/// an internal array of `u64` to which -/// values of arbitrary bit length can be written. -#[derive(Clone, Debug)] -pub struct BitArray { - /// The internal data array containing all values - data: Vec, - /// The capacity, in values, of this array - capacity: usize, - /// The number of bits used to represent each value - bits_per_value: u8, - /// The maximum value represented by an entry in this array - value_mask: u64, -} - -impl BitArray { - /// Creates a new `BitArray` with the given - /// bits per value and capacity. The array - /// will be initialized with zeroes. - pub fn new(bits_per_value: u8, capacity: usize) -> Self { - assert!( - bits_per_value <= 64, - "Bits per value cannot be more than 64" - ); - assert!(bits_per_value > 0, "Bits per value must be positive"); - let data = { - let len = (((capacity * (bits_per_value as usize)) as f64) / 64.0).ceil() as usize; - vec![0u64; len] - }; - - let value_mask = (1 << (bits_per_value as u64)) - 1; - - Self { - data, - capacity, - bits_per_value, - value_mask, - } - } - - /// Creates a new `BitArray` based on the given raw parts. - pub fn from_raw(data: Vec, bits_per_value: u8, capacity: usize) -> Self { - assert!( - bits_per_value <= 64, - "Bits per value cannot be more than 64" - ); - assert!(bits_per_value > 0, "Bits per value must be positive"); - - let value_mask = (1 << (bits_per_value as u64)) - 1; - - Self { - data, - capacity, - bits_per_value, - value_mask, - } - } - - /// Returns the highest possible value represented - /// by and entry in this `BitArray`. - pub fn highest_possible_value(&self) -> u64 { - self.value_mask - } - - /// Returns the value at the given location in this `BitArray`. - pub fn get(&self, index: usize) -> u64 { - assert!(index < self.capacity, "Index out of bounds"); - - let bit_index = index * (self.bits_per_value as usize); - - let start_long_index = bit_index / 64; - - let start_long = self.data[start_long_index]; - - let index_in_start_long = (bit_index % 64) as u64; - - let mut result = start_long >> index_in_start_long; - - let end_bit_offset = index_in_start_long + self.bits_per_value as u64; - - if end_bit_offset > 64 { - // Value stretches across multiple longs - let end_long = self.data[start_long_index + 1]; - result |= end_long << (64 - index_in_start_long); - } - - result & self.value_mask - } - - /// Sets the value at the given index into this `BitArray` - pub fn set(&mut self, index: usize, val: u64) { - assert!(index < self.capacity, "Index out of bounds"); - assert!( - val <= self.value_mask, - "Value does not fit into bits_per_value" - ); - - let bit_index = index * (self.bits_per_value as usize); - - let start_long_index = bit_index / 64; - - let index_in_start_long = (bit_index % 64) as u64; - - // Clear bits of this value first - self.data[start_long_index] = (self.data[start_long_index] - & !(self.value_mask << index_in_start_long)) - | ((val & self.value_mask) << index_in_start_long); - - let end_bit_offset = index_in_start_long + self.bits_per_value as u64; - if end_bit_offset > 64 { - // Value stretches across multiple longs - self.data[start_long_index + 1] = (self.data[start_long_index + 1] - & !((1 << (end_bit_offset - 64)) - 1)) - | val >> (64 - index_in_start_long); - } - - debug_assert_eq!(self.get(index), val); - } - - /// Produces a `BitArray` with the same values - /// as this `BitArray` but with a new bits per value. - /// If a value in this `BitArray` cannot be represented - /// by the new bits per value, `Err` is returned. - pub fn resize_to(&self, new_bits_per_value: u8) -> Result { - assert!( - new_bits_per_value <= 64, - "Bits per value cannot be more than 64" - ); - - let mut new_arr = BitArray::new(new_bits_per_value, self.capacity); - - for i in 0..self.capacity { - let val = self.get(i); - if needed_bits(val) > new_bits_per_value { - return Err(()); - } - - new_arr.set(i, val); - debug_assert_eq!(new_arr.get(i), val); - } - - Ok(new_arr) - } - - /// Returns the internal array. - pub fn inner(&self) -> &Vec { - &self.data - } -} - -/// Returns the number of bits -/// needed to represent the given value. -fn needed_bits(mut val: u64) -> u8 { - let mut result = 0; - loop { - val >>= 1; - result += 1; - - if val == 0 { - break; - } - } - - result -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn chunk_new() { - let pos = ChunkPosition::new(0, 0); - let chunk = Chunk::new(pos); - - // Confirm that chunk is empty - for x in 0..16 { - assert!(chunk.section(x).is_none()); - assert!(chunk.section(x).is_none()); - } - - assert_eq!(chunk.position(), pos); - } - - #[test] - fn chunk_new_with_default_biome() { - let pos = ChunkPosition::new(0, 0); - let chunk = Chunk::new_with_default_biome(pos, Biome::Mountains); - - // Confirm that chunk is empty - for x in 0..16 { - assert!(chunk.section(x).is_none()); - assert!(chunk.section(x).is_none()); - } - - assert_eq!(chunk.position(), pos); - - // Confirm that biomes are set - for x in 0..16 { - for z in 0..16 { - assert_eq!(chunk.biome_at(x, z), Biome::Mountains); - } - } - } - - #[test] - fn set_block_simple() { - let pos = ChunkPosition::new(0, 0); - let mut chunk = Chunk::new(pos); - - chunk.set_block_at(0, 0, 0, Block::Andesite); - assert_eq!(chunk.block_at(0, 0, 0), Block::Andesite); - assert!(chunk.section(0).is_some()); - } - - #[test] - fn fill_chunk() { - let pos = ChunkPosition::new(0, 0); - let mut chunk = Chunk::new(pos); - - let block = Block::Stone; - - for x in 0..16 { - for y in 0..256 { - for z in 0..16 { - chunk.set_block_at(x, y, z, block); - assert_eq!(chunk.block_at(x, y, z), block); - } - } - } - - // Check again, just to be sure - for x in 0..16 { - for y in 0..256 { - for z in 0..16 { - assert_eq!(chunk.block_at(x, y, z), block); - } - } - } - } - - #[test] - fn spray_chunk() { - // This test fills each section of the chunk - // with the blocks with IDs corresponding - // to 0-4095 in order, testing that - // resizing, etc. works correctly. - - let pos = ChunkPosition::new(0, 0); - let mut chunk = Chunk::new(pos); - - for section in chunk.sections() { - assert!(section.is_none()); - } - - for section in 0..16 { - let mut counter = 0; - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - let block = Block::from_native_state_id(counter).unwrap(); - chunk.set_block_at(x, (section * 16) + y, z, block); - assert_eq!(chunk.block_at(x, (section * 16) + y, z), block); - if counter != 0 { - assert!(chunk.section(section).is_some(), "Section {} bad", section); - } - counter += 1; - } - } - } - } - - // Go through again to be sure - for section in 0..16 { - assert!(chunk.section(section).is_some()); - let mut counter = 0; - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - let block = Block::from_native_state_id(counter).unwrap(); - assert_eq!(chunk.block_at(x, (section * 16) + y, z), block); - assert!(chunk.section(section).is_some()); - counter += 1; - } - } - } - } - - // Now, empty the chunk, call optimize(), and ensure - // that the sections become empty. - for x in 0..16 { - for y in 0..256 { - for z in 0..16 { - chunk.set_block_at(x, y, z, Block::Air); - } - } - } - - chunk.optimize(); - - for section in chunk.sections() { - assert!(section.is_none()); - } - } - - #[test] - fn section_from_data_and_palette() { - let pos = ChunkPosition::new(0, 0); - let mut chunk = Chunk::new(pos); - - let mut data = BitArray::new(5, 4096); - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - data.set(block_index(x, y, z), 0); - } - } - } - - let palette = vec![1]; - let section = ChunkSection::new( - data, - Some(palette), - BitArray::new(4, SECTION_VOLUME), - BitArray::new(4, SECTION_VOLUME), - ); - chunk.set_section_at(0, Some(section)); - - for x in 0..16 { - for y in 0..16 { - for z in 0..16 { - assert_eq!(chunk.block_at(x, y, z), Block::Stone); - } - } - } - } - - #[test] - fn bit_array() { - let mut barr = BitArray::new(5, 4096); - assert_eq!(barr.highest_possible_value(), 31); - - for i in 0..4096 { - barr.set(i, 8); - assert_eq!(barr.get(i), 8); - } - - for i in 0..4096 { - assert_eq!(barr.get(i), 8); - } - - let resized = barr.resize_to(8).unwrap(); - for i in 0..4096 { - assert_eq!(resized.get(i), 8); - } - - let resized = barr.resize_to(4).unwrap(); - for i in 0..4096 { - assert_eq!(resized.get(i), 8); - } - } - - #[test] - fn bit_array_resize_fail() { - let mut barr = BitArray::new(5, 4096); - - for i in 0..4096 { - barr.set(i, 31); - } - - assert!(barr.resize_to(4).is_err()); - } - - #[test] - fn bit_array_big_test() { - let mut barr = BitArray::new(14, 4096); - - for i in 0..4096 { - barr.set(i, i as u64); - assert_eq!(barr.get(i), i as u64); - if i != 4095 { - assert_eq!(barr.get(i + 1), 0); - } - if i != 0 { - assert_eq!(barr.get(i - 1), (i - 1) as u64); - } - } - - for i in 0..4096 { - assert_eq!(barr.get(i), i as u64); - } - } - - #[test] - fn bit_array_resize() { - let mut barr = BitArray::new(12, 4096); - assert_eq!(barr.bits_per_value, 12); - - for i in 0..4096 { - barr.set(i, i as u64); - assert_eq!(barr.get(i), i as u64); - } - - let mut barr = barr.resize_to(13).unwrap(); - assert_eq!(barr.bits_per_value, 13); - - for i in 0..4096 { - assert_eq!(barr.get(i), i as u64); - barr.set(i, (i + 1) as u64); - assert_eq!(barr.get(i), (i + 1) as u64); - } - - let mut barr = barr.resize_to(14).unwrap(); - assert_eq!(barr.bits_per_value, 14); - - for i in 0..4096 { - assert_eq!(barr.get(i), (i + 1) as u64); - barr.set(i, i as u64); - assert_eq!(barr.get(i), i as u64); - } - - for i in 0..4096 { - assert_eq!(barr.get(i), i as u64); - } - } - - #[test] - fn test_needed_bits() { - assert_eq!(needed_bits(31), 5); - assert_eq!(needed_bits(255), 8); - assert_eq!(needed_bits(256), 9); - assert_eq!(needed_bits(1), 1); - } - - #[test] - fn test_block_index() { - assert_eq!(block_index(0, 1, 0), 256); - assert_eq!(block_index(1, 1, 1), 256 + 16 + 1); - } - - #[test] - fn test_correct_data_and_palette() { - let mut data = BitArray::new(4, 4096); - let mut palette = vec![0, 4, 2, 7, 3]; - ChunkSection::correct_data_and_palette(&mut data, &mut palette); - assert_eq!(palette.len(), 5); - } - - #[test] - fn test_palette_insertion_in_middle() { - let mut chunk = ChunkSection::default(); - - chunk.set_block_at(0, 0, 0, Block::Cobblestone); - chunk.set_block_at(0, 1, 0, Block::Stone); - - assert_eq!(chunk.block_at(0, 0, 0), Block::Cobblestone); - assert_eq!(chunk.block_at(0, 1, 0), Block::Stone); - } - - #[test] - fn test_biomes() { - let mut chunk = Chunk::default(); - - for x in 0..SECTION_WIDTH { - for z in 0..SECTION_WIDTH { - assert_eq!(chunk.biome_at(x, z), Biome::Plains); - chunk.set_biome_at(x, z, Biome::BirchForest); - assert_eq!(chunk.biome_at(x, z), Biome::BirchForest); - } - } - } - - #[test] - fn test_modified() { - let mut chunk = Chunk::default(); - assert!(chunk.check_modified()); - assert!(!chunk.check_modified()); - - chunk.set_block_at(0, 0, 0, Block::Stone); - assert!(chunk.check_modified()); - assert!(!chunk.check_modified()); - } - - #[test] - fn test_convert_section_to_palette() { - let mut chunk = Chunk::default(); - - let mut counter = 0; - for x in 0..SECTION_WIDTH { - for y in 0..SECTION_HEIGHT { - for z in 0..SECTION_WIDTH { - chunk.set_block_at(x, y, z, Block::from_native_state_id(counter).unwrap()); - counter += 1; - } - } - } - - let section = chunk.section_mut(0).unwrap(); - section.convert_palette_to_section(); - - assert_eq!(section.palette().unwrap().len(), counter as usize); - - // Ensure that data array still represents the same data - counter = 0; - for x in 0..SECTION_WIDTH { - for y in 0..SECTION_HEIGHT { - for z in 0..SECTION_WIDTH { - assert_eq!( - chunk.block_at(x, y, z), - Block::from_native_state_id(counter).unwrap() - ); - counter += 1; - } - } - } - } - - #[test] - fn test_light() { - let mut chunk = Chunk::default(); - - for x in 0..SECTION_WIDTH { - for y in 0..SECTION_HEIGHT { - for z in 0..SECTION_WIDTH { - chunk.set_block_light_at(x, y, z, 10); - chunk.set_sky_light_at(x, y, z, 8); - assert_eq!(chunk.block_light_at(x, y, z), 10); - assert_eq!(chunk.sky_light_at(x, y, z), 8); - } - } - } - } -} diff --git a/core/src/world/mod.rs b/core/src/world/mod.rs deleted file mode 100644 index 48cc94d98..000000000 --- a/core/src/world/mod.rs +++ /dev/null @@ -1,458 +0,0 @@ -use crate::world::block::*; -use crate::world::chunk::Chunk; -use glm::{DVec3, Vec3}; -use hashbrown::HashMap; -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::ops::{Add, Sub}; - -pub mod block; -#[allow(clippy::cast_lossless)] -pub mod chunk; - -#[macro_export] -macro_rules! position { - ($x:expr, $y:expr, $z:expr, $pitch:expr, $yaw:expr, $on_ground:expr) => { - $crate::Position { - x: $x, - y: $y, - z: $z, - pitch: $pitch, - yaw: $yaw, - on_ground: $on_ground, - } - }; - ($x:expr, $y:expr, $z:expr, $pitch: expr, $yaw: expr) => { - position!($x, $y, $z, $pitch, $yaw, true) - }; - ($x:expr, $y:expr, $z:expr) => { - position!($x, $y, $z, 0.0, 0.0) - }; - ($x:expr, $y:expr, $z:expr, $on_ground: expr) => { - position!($x, $y, $z, 0.0, 0.0, $on_ground) - }; -} - -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Position { - pub x: f64, - pub y: f64, - pub z: f64, - pub pitch: f32, - pub yaw: f32, - pub on_ground: bool, -} - -impl Position { - pub fn distance(&self, other: Position) -> f64 { - self.distance_squared(other).sqrt() - } - - pub fn distance_squared(&self, other: Position) -> f64 { - square(self.x - other.x) + square(self.y - other.y) + square(self.z - other.z) - } - - /// Returns the position of the chunk - /// this position is in. - pub fn chunk_pos(&self) -> ChunkPosition { - ChunkPosition::new(self.x.floor() as i32 / 16, self.z.floor() as i32 / 16) - } - - /// Retrieves the position of the block - /// this position is in. - pub fn block_pos(&self) -> BlockPosition { - BlockPosition::new( - self.x.floor() as i32, - self.y.floor() as i32, - self.z.floor() as i32, - ) - } - - /// Returns a unit vector representing - /// the direction of this position's pitch - /// and yaw. - pub fn direction(&self) -> DVec3 { - let rotation_x = f64::from(self.yaw.to_radians()); - let rotation_y = f64::from(self.pitch.to_radians()); - - let y = -rotation_y.sin(); - - let xz = rotation_y.cos(); - - let x = -xz * rotation_x.sin(); - let z = xz * rotation_x.cos(); - - glm::vec3(x, y, z) - } - - pub fn as_vec(&self) -> DVec3 { - (*self).into() - } -} - -impl Add for Position { - type Output = Position; - - fn add(mut self, vec: Vec3) -> Self::Output { - self.x += f64::from(vec.x); - self.y += f64::from(vec.y); - self.z += f64::from(vec.z); - self - } -} - -impl Add for Position { - type Output = Position; - - fn add(mut self, rhs: DVec3) -> Self::Output { - self.x += rhs.x; - self.y += rhs.y; - self.z += rhs.z; - self - } -} - -impl Add for Position { - type Output = Position; - - fn add(mut self, rhs: Position) -> Self::Output { - self.x += rhs.x; - self.y += rhs.y; - self.z += rhs.z; - self.pitch += rhs.pitch; - self.yaw += rhs.yaw; - self - } -} - -impl Sub for Position { - type Output = Position; - - fn sub(mut self, vec: Vec3) -> Self::Output { - self.x -= f64::from(vec.x); - self.y -= f64::from(vec.y); - self.z -= f64::from(vec.z); - self - } -} - -impl Sub for Position { - type Output = Position; - - fn sub(mut self, vec: DVec3) -> Self::Output { - self.x -= vec.x; - self.y -= vec.y; - self.z -= vec.z; - self - } -} - -impl Sub for Position { - type Output = Position; - - fn sub(mut self, rhs: Position) -> Self::Output { - self.x -= rhs.x; - self.y -= rhs.y; - self.z -= rhs.z; - self - } -} - -impl Into for Position { - fn into(self) -> Vec3 { - glm::vec3(self.x as f32, self.y as f32, self.z as f32) - } -} - -impl Into for Position { - fn into(self) -> DVec3 { - glm::vec3(self.x, self.y, self.z) - } -} - -impl From for Position { - fn from(vec: Vec3) -> Self { - position!(f64::from(vec.x), f64::from(vec.y), f64::from(vec.z)) - } -} - -impl From for Position { - fn from(vec: DVec3) -> Self { - position!(vec.x, vec.y, vec.z) - } -} - -impl Display for Position { - fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { - write!( - f, - "({:.2}, {:.2}, {:.2}), ({:.2}, {:.2}), on_ground: {}", - self.x, self.y, self.z, self.pitch, self.yaw, self.on_ground - ) - } -} - -fn square(x: f64) -> f64 { - x * x -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Hash32, Default)] -pub struct ChunkPosition { - pub x: i32, - pub z: i32, -} - -impl ChunkPosition { - pub const fn new(x: i32, z: i32) -> Self { - Self { x, z } - } - - /// Computes the Manhattan distance from this chunk to another. - pub fn manhattan_distance(self, other: ChunkPosition) -> i32 { - (self.x - other.z).abs() + (self.z - other.z).abs() - } -} - -impl Display for ChunkPosition { - fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { - write!(f, "({}, {})", self.x, self.z) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Hash32, Default)] -pub struct BlockPosition { - pub x: i32, - pub y: i32, - pub z: i32, -} - -impl BlockPosition { - pub const fn new(x: i32, y: i32, z: i32) -> Self { - Self { x, y, z } - } - - pub fn chunk_pos(&self) -> ChunkPosition { - ChunkPosition::new(self.x >> 4, self.z >> 4) - } - - pub fn world_pos(&self) -> Position { - position!(f64::from(self.x), f64::from(self.y), f64::from(self.z)) - } - - /// Returns the Manhattan distance from this position to another. - pub fn manhattan_distance(self, other: BlockPosition) -> i32 { - (self.x - other.x).abs() + (self.y - other.y).abs() + (self.z - other.z).abs() - } -} - -impl Add for BlockPosition { - type Output = BlockPosition; - - fn add(mut self, rhs: BlockPosition) -> Self::Output { - self.x += rhs.x; - self.y += rhs.y; - self.z += rhs.z; - self - } -} - -pub struct ChunkMap { - chunk_map: HashMap, -} - -impl ChunkMap { - pub fn new() -> Self { - Self { - chunk_map: HashMap::new(), - } - } - - pub fn inner(&self) -> &HashMap { - &self.chunk_map - } - - pub fn inner_mut(&mut self) -> &mut HashMap { - &mut self.chunk_map - } - - /// Retrieves the chunk at the specified location. - /// If the chunk is not loaded, `None` will be returned. - pub fn chunk_at(&self, pos: ChunkPosition) -> Option<&Chunk> { - if let Some(chunk) = self.chunk_map.get(&pos) { - Some(chunk) - } else { - None - } - } - - /// Retrieves the chunk at the specified location. - /// If the chunk is not loaded, `None` will be returned. - pub fn chunk_at_mut(&mut self, pos: ChunkPosition) -> Option<&mut Chunk> { - if let Some(chunk) = self.chunk_map.get_mut(&pos) { - Some(chunk) - } else { - None - } - } - - /// Retrieves the block at the specified - /// location. If the chunk in which the block - /// exists is not laoded, `None` is returned. - pub fn block_at(&self, pos: BlockPosition) -> Option { - if pos.y > 255 || pos.y < 0 { - return None; - } - - let chunk_pos = pos.chunk_pos(); - - if let Some(chunk) = self.chunk_at(chunk_pos) { - let rpos = chunk_relative_pos(pos); - Some(chunk.block_at(rpos.0, rpos.1, rpos.2)) - } else { - None - } - } - - /// Sets the block at the given position. - /// If the chunk in which the position resides - /// does not exist, `Err` is returned. In all - /// other cases, `Ok` is returned. - /// - /// Note that on the server side, calling this function - /// does not broadcast the update in any way. As such, - /// the according function should be called instead. - pub fn set_block_at(&mut self, pos: BlockPosition, block: Block) -> Result<(), ()> { - if pos.y > 255 || pos.y < 0 { - return Err(()); - } - - let chunk_pos = pos.chunk_pos(); - - if let Some(chunk) = self.chunk_map.get_mut(&chunk_pos) { - let (x, y, z) = chunk_relative_pos(pos); - chunk.set_block_at(x, y, z, block); - Ok(()) - } else { - Err(()) - } - } - - /// Sets the chunk at the given location. - pub fn set_chunk_at(&mut self, pos: ChunkPosition, chunk: Chunk) { - self.chunk_map.insert(pos, chunk); - } - - /// Removes the chunk at the given location, - /// effectively unloading it. - pub fn unload_chunk_at(&mut self, pos: ChunkPosition) -> Option { - self.chunk_map.remove(&pos) - } - - /// Returns an immutable reference to the internal map. - pub fn chunks(&self) -> &HashMap { - &self.chunk_map - } - - /// Returns a mutable reference to the internal - /// map. - pub fn chunks_mut(&mut self) -> &mut HashMap { - &mut self.chunk_map - } -} - -impl Default for ChunkMap { - fn default() -> Self { - Self::new() - } -} - -pub fn chunk_relative_pos(block_pos: BlockPosition) -> (usize, usize, usize) { - ( - block_pos.x as usize & 0xf, - block_pos.y as usize, - block_pos.z as usize & 0xf, - ) -} - -pub trait ChunkGenerator { - fn generate(&self, chunk: &mut Chunk); -} - -pub struct FlatChunkGenerator {} - -impl ChunkGenerator for FlatChunkGenerator { - fn generate(&self, chunk: &mut Chunk) { - for x in 0..16 { - for y in 0..64 { - for z in 0..16 { - chunk.set_block_at(x, y, z, Block::Stone); - } - } - } - } -} - -pub struct GridChunkGenerator {} - -impl ChunkGenerator for GridChunkGenerator { - fn generate(&self, chunk: &mut Chunk) { - for x in 0..15 { - for y in 0..64 { - for z in 0..15 { - chunk.set_block_at(x, y, z, Block::Stone); - } - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_chunk_map() { - let mut world = ChunkMap::new(); - - let chunk = world.chunk_at(ChunkPosition::new(0, 0)); - if chunk.is_some() { - panic!(); - } - - let mut chunk = Chunk::new(ChunkPosition::new(0, 0)); - FlatChunkGenerator {}.generate(&mut chunk); - world.chunk_map.insert(ChunkPosition::new(0, 0), chunk); - - let chunk = world.chunk_at(ChunkPosition::new(0, 0)).unwrap(); - - for x in 0..15 { - for y in 0..64 { - for z in 0..15 { - assert_eq!(chunk.block_at(x, y, z), Block::Stone); - } - } - } - - assert_eq!(chunk.block_at(8, 64, 8), Block::Air); - } - - #[test] - fn test_set_block_at() { - let mut world = ChunkMap::new(); - - let mut chunk = Chunk::new(ChunkPosition::new(0, 0)); - GridChunkGenerator {}.generate(&mut chunk); - world.chunk_map.insert(ChunkPosition::new(0, 0), chunk); - - println!("-----"); - world - .set_block_at(BlockPosition::new(1, 63, 1), Block::Air) - .unwrap(); - - println!("-----"); - assert_eq!( - world.block_at(BlockPosition::new(1, 63, 1)).unwrap(), - Block::Air - ); - } -} diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 000000000..ad65df865 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,124 @@ +### Architecture + +Feather uses the Entity-Component-System architecture, also known as ECS. This architecture +is widely used in the Rust gamedev ecosystem. + +In the ECS architecture, there are three key types of objects: +* Entities: these are just IDs. In Feather, these are represented by the `Entity` struct. +They allow access to components. +* Components: these represent entities' data. Each entity can have zero or one component of every type. For example, `Position` +stores an entity position, and entities with the `Position` component have a position. You can access components +via `Game.ecs.get::()`, where `T` is the component you want. +* Systems: functions that run each tick. While components are data, systems are logic. They operate on components. + +ECS implementations allow for _queries_ that allow iteration over all entities with a specific set of components. +For example, to implement trivial physics: + +```rust +for (entity, (position, velocity)) in game.ecs.query::<(&mut Position, &Velocity)>().iter() { + *position += *velocity; +} +``` + +The above code snippet iterates over _all_ entities with `Position` and `Velocity` components. + +For more information on the ECS, we recommend checking out the [`hecs`](https://docs.rs/hecs) documentation. + +The Feather game state is defined in the `Game` struct, which lives in `crates/common/src/game.rs`. +This struct contains the `World` (blocks) and the `Ecs` (entities). It also provides +methods for common tasks, like "spawn entity" or "remove entity" or "get block." + +Note that entities in the ECS correspond either to Minecraft entities, like players or zombies, +or to internal entities like the "console entity." In general, you don't have to worry about +this distinction. + +### Commonly used components + +This is a list of components that are frequently accessed throughout the codebase. +* `Position` +* `Gamemode` for players +* `Name` - player's username (not for other entities) +* `CustomName` - entity's custom name (not for players) +* `Inventory` +* `Window` - wraps one or more `Inventory`s that the player is looking at right now. In a chest, +for example, a player's window would wrap the player inventory and the chest inventory. + +### Crate Structure + +Feather is a complex codebase with multiple components. To improve modularity and reusability, we've +split the codebase into a series of crates: + +* Core Minecraft functionality (not specific to Feather) goes in [`libcraft`](https://github.com/feather-rs/libcraft). +For example, the block, item, chunk, and region file structs live in `libcraft`. `libcraft` code is intended +for use in other Rust Minecraft tools, like map editors or world file converters. +* The plugin API lives in [`quill`](https://github.com/feather-rs/quill), which actually consists of three major crates: + * `quill-common` is shared between Feather itself and plugins. This is where most of our ECS components are defined, + so that both plugins and Feather can access them. + * `quill-sys` provides FFI functions for "host calls." Host calls are low-level functions that + plugins call to perform actions. For example, "get component" and "send message" are host calls. + * `quill` is the public-facing plugin API. It reexports types from `quill-common` and wraps the FFI functions in `quill-sys` + with a safe, idiomatic API. +* The remainder of the code is in Feather itself, which consists of three major crates: + * `feather-common` implements gameplay: it defines ECS systems that run the Minecraft game. For example, it includes + physics, block placement/digging, chat, etc. It operates on the types defined in `libcraft` and `quill-common`. + * `feather-server` is a wrapper around `feather-common` that provides packet handling and sending. + * `feather-plugin-host` implements the FFI functions in `quill-sys`. + +### Adding a component + +Components should be defined in the `quill-common` crate so plugins can access them. +(Some components can also be exported from `libcraft` if they're reusable outside of Feather.) +Just define a struct for the component, derive `Serialize` and `Deserialize`, and add +it to `components.rs`. + +The component can then be accessed both from Feather and from plugins. + +### Events + +In Feather, events are components. An entity with the `PlayerJoinEvent` component just joined +the game, for example. + +The event sytsem serves as a mechanism to communicate between different crates and modules. +For example, triggering a `BlockChangeEvent` _anywhere_ causes `feather-server` to send block +update packets to players. + +To trigger an event, use `game.ecs.insert_entity_event(entity, event)`. `entity` should be the +entity that the event happened to, e.g. for `PlayerJoinEvent`, it's the player that joined. + +Alternatively, if the event is not related to a specific entity, call `game.ecs.insert_event(event)`. +For example, `BlockChangeEvent` is one such event. + +To handle events, query for entities with that component. For example, to query +for players that just joined, use: + +```rust +for (player_entity, event) in game.ecs.query::<(&PlayerJoinEvent)>().iter() { + // handle event... +} +``` + +### Sending packets + +Most features need to send packets to clients. The Minecraft protocol and its +packets are documented at [wiki.vg](https://wiki.vg/Protocol). + +In Feather, the `Client` struct in `crates/server/src/client.rs` encapsulates +the packet sending code. Add a method there to send the packet you need. + +It's not possible to send packets from the `feather-common` crate. Instead, you should +trigger an event and handle it in `feather-server`. + +### Sending packets to nearby players + +Some packets should be sent to all players that can see a given entity, or all +players that can see a given block. Use `Server::broadcast_nearby_with` for this. + +### Receiving packets + +Packets are handled in `crates/server/src/packet_handlers.rs`. Add the necessary match +arm and implement your packet handler. + +### Further questions + +This documentation is a work in progress. Contact us on Discord if you have further +questions! diff --git a/feather/base/Cargo.toml b/feather/base/Cargo.toml new file mode 100644 index 000000000..a0bdcf549 --- /dev/null +++ b/feather/base/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "feather-base" +version = "0.1.0" +authors = [ "caelunshun " ] +edition = "2018" + +[dependencies] +ahash = "0.4" +anyhow = "1" +arrayvec = { version = "0.7", features = [ "serde" ] } +bitflags = "1" +bitvec = "0.21" +blocks = { path = "../blocks", package = "feather-blocks" } +byteorder = "1" +hematite-nbt = { git = "https://github.com/PistonDevelopers/hematite_nbt" } + +libcraft-blocks = { path = "../../libcraft/blocks" } +libcraft-core = { path = "../../libcraft/core" } +libcraft-items = { path = "../../libcraft/items" } +libcraft-particles = { path = "../../libcraft/particles" } +libcraft-text = { path = "../../libcraft/text" } +libcraft-inventory = { path = "../../libcraft/inventory" } + +nom = "5" +nom_locate = "2" +num-derive = "0.3" +num-traits = "0.2" +parking_lot = "0.11" +quill-common = { path = "../../quill/common" } +serde = { version = "1", features = [ "derive" ] } +serde_json = "1" +serde_with = "1" +smallvec = "1" +thiserror = "1" +uuid = { version = "0.8", features = [ "serde" ] } +vek = "0.14" +bytemuck = { version = "1", features = ["derive"] } + +[dev-dependencies] +rand = "0.8" +rand_pcg = "0.3" +serde_test = "1" diff --git a/core/src/save/mod.rs b/feather/base/src/anvil.rs similarity index 66% rename from core/src/save/mod.rs rename to feather/base/src/anvil.rs index 89c6aa8bb..a03899dd8 100644 --- a/core/src/save/mod.rs +++ b/feather/base/src/anvil.rs @@ -1,8 +1,9 @@ -//! Module containing functions for loading and saving to +//! Loading and saving to/from //! world saves. Currently includes region file loading, //! player data loading, and level data loading. +pub mod block_entity; pub mod entity; pub mod level; -pub mod player_data; +pub mod player; pub mod region; diff --git a/feather/base/src/anvil/block_entity.rs b/feather/base/src/anvil/block_entity.rs new file mode 100644 index 000000000..4174c6184 --- /dev/null +++ b/feather/base/src/anvil/block_entity.rs @@ -0,0 +1,201 @@ +use serde::ser::Error; +use serde::{Deserialize, Serialize, Serializer}; + +use super::player::InventorySlot; + +/// A block entity loaded or saved to the Anvil format. +/// Should be serialized using NBT. +/// +/// +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BlockEntityData { + #[serde(flatten)] + pub base: BlockEntityBase, + #[serde(flatten)] + pub kind: BlockEntityKind, +} + +/// Data common to all block entities. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BlockEntityBase { + /// X coordinate in global coordinate space. + pub x: i32, + /// Y coordinate in global space. + pub y: i32, + /// Z coordinate in global space. + pub z: i32, +} + +/// Kind of a block entity. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "id")] +pub enum BlockEntityKind { + #[serde(rename = "minecraft:beacon")] + #[serde(rename_all = "PascalCase")] + Beacon { + levels: i32, + primary: i32, + secondary: i32, + }, + #[serde(rename = "minecraft:bed")] + #[serde(rename_all = "PascalCase")] + Bed, // empty in JE + #[serde(rename = "minecraft:brewing_stand")] + #[serde(rename_all = "PascalCase")] + BrewingStand { + #[serde(default)] + items: Vec, + brew_time: i16, + fuel: i8, + }, + #[serde(rename = "minecraft:cauldron")] + #[serde(rename_all = "PascalCase")] + Cauldron { + #[serde(default)] + items: Vec, + potion_id: i16, + splash_potion: bool, + is_movable: bool, + }, + #[serde(rename = "minecraft:chest")] + #[serde(rename_all = "PascalCase")] + Chest { + #[serde(default)] + items: Vec, + loot_table: Option, + loot_table_seed: Option, + }, + #[serde(rename = "minecraft:comparator")] + #[serde(rename_all = "PascalCase")] + Comparator { output_signal: i32 }, + #[serde(rename = "minecraft:command_block")] + #[serde(rename_all = "PascalCase")] + CommandBlock { + custom_name: Option, + command: String, + success_count: i32, + last_output: String, + track_output: bool, + powered: bool, + auto: bool, + condition_met: bool, + update_last_execution: bool, + last_execution: i64, + }, + #[serde(rename = "minecraft:daylight_detector")] + #[serde(rename_all = "PascalCase")] + DaylightDetector, // empty + #[serde(rename = "minecraft:dispenser")] + #[serde(rename_all = "PascalCase")] + Dispenser { + #[serde(default)] + items: Vec, + }, + #[serde(rename = "minecraft:dropper")] + #[serde(rename_all = "PascalCase")] + Dropper { + #[serde(default)] + items: Vec, + }, + #[serde(rename = "minecraft:enchanting_table")] + #[serde(rename_all = "PascalCase")] + EnchantingTable, + #[serde(rename = "minecraft:ender_chest")] + #[serde(rename_all = "PascalCase")] + EnderChest, + #[serde(rename = "minecraft:end_gateway")] + #[serde(rename_all = "PascalCase")] + EndGateway { age: i64, exact_teleport: bool }, + #[serde(rename = "minecraft:end_portal")] + #[serde(rename_all = "PascalCase")] + EndPortal, + #[serde(rename = "minecraft:furnace")] + #[serde(rename_all = "PascalCase")] + Furnace { + #[serde(default)] + items: Vec, + burn_time: i16, + cook_time: i16, + cook_time_total: i16, + }, + #[serde(rename = "minecraft:hopper")] + #[serde(rename_all = "PascalCase")] + Hopper { + #[serde(default)] + items: Vec, + transfer_cooldown: i32, + }, + #[serde(rename = "minecraft:jigsaw")] + #[serde(rename_all = "PascalCase")] + Jigsaw { + target_pool: String, + final_state: String, + /// spelled "attachement" on the wiki, + /// but mispelling is probably a mistake? + attachment_type: String, + }, + #[serde(rename = "minecraft:jukebox")] + #[serde(rename_all = "PascalCase")] + Jukebox { + #[serde(default)] + record_item: InventorySlot, + }, + // TODO: a few more + /// Fallback type for unknown block entities + #[serde(other, serialize_with = "BlockEntityKind::serialize_unknown")] + Unknown, +} + +impl BlockEntityKind { + pub(crate) fn serialize_unknown(_serializer: S) -> Result { + Err(S::Error::custom("cannot serialize unknown block entities")) + } + + pub fn variant(&self) -> BlockEntityVariant { + match self { + BlockEntityKind::Beacon { .. } => BlockEntityVariant::Beacon, + BlockEntityKind::Bed { .. } => BlockEntityVariant::Bed, + BlockEntityKind::BrewingStand { .. } => BlockEntityVariant::BrewingStand, + BlockEntityKind::Cauldron { .. } => BlockEntityVariant::Cauldron, + BlockEntityKind::Comparator { .. } => BlockEntityVariant::Comparator, + BlockEntityKind::CommandBlock { .. } => BlockEntityVariant::CommandBlock, + BlockEntityKind::Chest { .. } => BlockEntityVariant::Chest, + BlockEntityKind::DaylightDetector { .. } => BlockEntityVariant::DaylightDetector, + BlockEntityKind::Dispenser { .. } => BlockEntityVariant::Dispenser, + BlockEntityKind::Dropper { .. } => BlockEntityVariant::Dropper, + BlockEntityKind::EnchantingTable { .. } => BlockEntityVariant::EnchantingTable, + BlockEntityKind::EnderChest { .. } => BlockEntityVariant::EnderChest, + BlockEntityKind::EndGateway { .. } => BlockEntityVariant::EndGateway, + BlockEntityKind::EndPortal { .. } => BlockEntityVariant::EndPortal, + BlockEntityKind::Furnace { .. } => BlockEntityVariant::Furnace, + BlockEntityKind::Hopper { .. } => BlockEntityVariant::Hopper, + BlockEntityKind::Jigsaw { .. } => BlockEntityVariant::Jigsaw, + BlockEntityKind::Jukebox { .. } => BlockEntityVariant::Jukebox, + BlockEntityKind::Unknown { .. } => BlockEntityVariant::Unknown, + } + } +} + +/// Variant of a `BlockEntityKind`. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum BlockEntityVariant { + Beacon, + Bed, + BrewingStand, + Cauldron, + Chest, + Comparator, + CommandBlock, + DaylightDetector, + Dispenser, + Dropper, + EnchantingTable, + EnderChest, + EndGateway, + EndPortal, + Furnace, + Hopper, + Jigsaw, + Jukebox, + Unknown, +} diff --git a/feather/base/src/anvil/entity.rs b/feather/base/src/anvil/entity.rs new file mode 100644 index 000000000..d5239d6ca --- /dev/null +++ b/feather/base/src/anvil/entity.rs @@ -0,0 +1,347 @@ +use arrayvec::ArrayVec; +use libcraft_items::{Item, ItemStack, ItemStackBuilder}; +use serde::ser::Error; +use serde::{Deserialize, Serialize, Serializer}; +use thiserror::Error; + +use crate::{vec3, Position, Vec3d}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum EntityDataKind { + Item, + Arrow, + Cow, + Pig, + Chicken, + Sheep, + Horse, + Llama, + Mooshroom, + Rabbit, + Squid, + Donkey, + Unknown, +} + +impl<'a> From<&'a EntityData> for EntityDataKind { + fn from(data: &'a EntityData) -> Self { + match data { + EntityData::Arrow(_) => EntityDataKind::Arrow, + EntityData::Item(_) => EntityDataKind::Item, + EntityData::Cow(_) => EntityDataKind::Cow, + EntityData::Pig(_) => EntityDataKind::Pig, + EntityData::Chicken(_) => EntityDataKind::Chicken, + EntityData::Sheep(_) => EntityDataKind::Sheep, + EntityData::Horse(_) => EntityDataKind::Horse, + EntityData::Llama(_) => EntityDataKind::Llama, + EntityData::Mooshroom(_) => EntityDataKind::Mooshroom, + EntityData::Rabbit(_) => EntityDataKind::Rabbit, + EntityData::Squid(_) => EntityDataKind::Squid, + EntityData::Donkey(_) => EntityDataKind::Donkey, + EntityData::Unknown => EntityDataKind::Unknown, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "id")] +pub enum EntityData { + #[serde(rename = "minecraft:item")] + Item(ItemEntityData), + #[serde(rename = "minecraft:arrow")] + Arrow(ArrowEntityData), + #[serde(rename = "minecraft:cow")] + Cow(AnimalData), + #[serde(rename = "minecraft:pig")] + Pig(AnimalData), + #[serde(rename = "minecraft:chicken")] + Chicken(AnimalData), + #[serde(rename = "minecraft:sheep")] + Sheep(AnimalData), + #[serde(rename = "minecraft:horse")] + Horse(AnimalData), + #[serde(rename = "minecraft:llama")] + Llama(AnimalData), + #[serde(rename = "minecraft:mooshroom")] + Mooshroom(AnimalData), + #[serde(rename = "minecraft:rabbit}")] + Rabbit(AnimalData), + #[serde(rename = "minecraft:squid")] + Squid(AnimalData), + #[serde(rename = "minecraft:donkey")] + Donkey(AnimalData), + + /// Fallback type for unknown entities + #[serde(other, serialize_with = "EntityData::serialize_unknown")] + Unknown, +} + +impl EntityData { + pub(crate) fn serialize_unknown(_serializer: S) -> Result { + Err(S::Error::custom("cannot serialize unknown entities")) + } +} + +/// Common entity tags. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BaseEntityData { + #[serde(rename = "Pos")] + pub position: ArrayVec, + #[serde(rename = "Rotation")] + pub rotation: ArrayVec, + #[serde(rename = "Motion")] + pub velocity: ArrayVec, +} + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum EntityLoadError { + #[error("missing position/rotation/velocity data")] + MissingData, +} + +impl BaseEntityData { + /// Creates a `BaseEntityData` from its parameters. + pub fn new(pos: Position, velocity: Vec3d) -> Self { + Self { + position: [pos.x, pos.y, pos.z].into(), + rotation: [pos.yaw, pos.pitch].into(), + velocity: [velocity.x, velocity.y, velocity.z].into(), + } + } + + /// Reads the position and rotation fields. If the fields are invalid, an error is returned. + pub fn read_position(self: &BaseEntityData) -> Result { + if self.position.len() == 3 && self.rotation.len() == 2 { + Ok(Position { + x: self.position[0], + y: self.position[1], + z: self.position[2], + yaw: self.rotation[0], + pitch: self.rotation[1], + }) + } else { + Err(EntityLoadError::MissingData) + } + } + + /// Reads the velocity field. If the field is invalid, an error is returned. + pub fn read_velocity(self: &BaseEntityData) -> Result { + if self.velocity.len() == 3 { + Ok(vec3(self.velocity[0], self.velocity[1], self.velocity[2])) + } else { + Err(EntityLoadError::MissingData) + } + } +} + +impl Default for BaseEntityData { + fn default() -> Self { + BaseEntityData { + position: [0.0, 0.0, 0.0].into(), + rotation: [0.0, 0.0].into(), + velocity: [0.0, 0.0, 0.0].into(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AnimalData { + #[serde(flatten)] + pub base: BaseEntityData, + #[serde(rename = "Health")] + pub health: f32, +} + +impl AnimalData { + /// Creates an `AnimalData` from its parameters. + pub fn new(base: BaseEntityData, health: f32) -> Self { + Self { base, health } + } +} + +impl Default for AnimalData { + fn default() -> Self { + AnimalData { + base: Default::default(), + health: 20.0, + } + } +} + +/// Represents a single item, without slot information. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ItemData { + #[serde(rename = "Count")] + pub count: i8, + #[serde(rename = "id")] + pub item: String, + #[serde(rename = "tag")] + pub nbt: Option, +} + +impl Default for ItemData { + fn default() -> Self { + Self { + count: 0, + item: Item::Air.name().to_owned(), + nbt: None, + } + } +} + +impl From for ItemStack { + fn from(item: ItemData) -> Self { + ItemStack::from(&item) + } +} + +// Can't do proper Borrow trait impl because of orphan rule +impl From<&ItemData> for ItemStack { + fn from(item: &ItemData) -> Self { + ItemNbt::item_stack( + &item.nbt, + Item::from_name(item.item.as_str()).unwrap_or(Item::Air), + item.count as u8, + ) + } +} + +impl From for ItemData +where + S: std::borrow::Borrow, +{ + fn from(s: S) -> Self { + let stack = s.borrow(); + let nbt = stack.into(); + let nbt = if nbt == Default::default() { + None + } else { + Some(nbt) + }; + Self { + count: stack.count() as i8, + item: stack.item().name().to_owned(), + nbt, + } + } +} + +/// Represents NBT tags on an item. +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct ItemNbt { + #[serde(rename = "Damage")] + pub damage: Option, + // TODO enchantments, display name, ... +} + +impl ItemNbt { + /// Create an `ItemStack` of the specified item and amount, setting any NBT present. + /// + /// # Panics + /// Panics if `count` is zero. + pub fn item_stack(nbt: &Option, item: Item, count: u8) -> ItemStack { + match nbt { + Some(ItemNbt { + damage: Some(damage), + }) => ItemStackBuilder::with_item(item) + .count(count as u32) + .damage(*damage) + .into(), + + Some(ItemNbt { damage: None }) | None => { + ItemStackBuilder::with_item(item).count(count as u32).into() + } + } + } +} + +impl From for ItemNbt +where + S: std::borrow::Borrow, +{ + fn from(s: S) -> Self { + let stack = s.borrow(); + Self { + damage: stack.damage_taken().map(|d| d as i32), + } + } +} + +/// Data for an Item entity (`minecraft:item`). +#[derive(Clone, Default, Serialize, Deserialize, Debug)] +pub struct ItemEntityData { + // Inherit base entity data + #[serde(flatten)] + pub entity: BaseEntityData, + + // Item-specific tags + #[serde(rename = "Age")] + pub age: i16, + #[serde(rename = "PickupDelay")] + pub pickup_delay: i16, + #[serde(rename = "Item")] + pub item: ItemData, + #[serde(rename = "Health")] + pub health: i16, +} + +/// Data for an Arrow entity (`minecraft:arrow`). +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct ArrowEntityData { + // Inherit base entity data + #[serde(flatten)] + pub entity: BaseEntityData, + + // Arrow-specific tags + + // TODO: Change this field to `bool` when issue with hematite_nbt is resolved. + // See: https://github.com/PistonDevelopers/hematite_nbt/issues/43 + #[serde(rename = "crit")] + pub critical: i8, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::position; + + #[test] + fn test_read_position() { + let data = BaseEntityData { + position: [1.0, 2.0, 3.0].into(), + rotation: [4.0, 5.0].into(), + velocity: [6.0, 7.0, 8.0].into(), + }; + let pos = data.read_position().unwrap(); + + assert!(pos.x - 1.0 < std::f64::EPSILON); + assert!(pos.y - 2.0 < std::f64::EPSILON); + assert!(pos.z - 3.0 < std::f64::EPSILON); + assert!(pos.yaw - 4.0 < std::f32::EPSILON); + assert!(pos.pitch - 5.0 < std::f32::EPSILON); + } + + #[test] + fn test_read_velocity() { + let data = BaseEntityData { + position: [1.0, 2.0, 3.0].into(), + rotation: [4.0, 5.0].into(), + velocity: [6.0, 7.0, 8.0].into(), + }; + let vel = data.read_velocity().unwrap(); + + assert!(vel[0] - 6.0 < std::f64::EPSILON); + assert!(vel[1] - 7.0 < std::f64::EPSILON); + assert!(vel[2] - 8.0 < std::f64::EPSILON); + } + + #[test] + fn test_new() { + let pos = position!(1.0, 10.0, 3.0, 115.0, -3.0); + let vel = vec3(0.0, 1.0, 2.0); + + let data = BaseEntityData::new(pos, vel); + assert_eq!(data.read_position(), Ok(pos)); + assert_eq!(data.read_velocity(), Ok(vel)); + } +} diff --git a/core/src/save/level.dat b/feather/base/src/anvil/level.dat similarity index 100% rename from core/src/save/level.dat rename to feather/base/src/anvil/level.dat diff --git a/core/src/save/level.rs b/feather/base/src/anvil/level.rs similarity index 81% rename from core/src/save/level.rs rename to feather/base/src/anvil/level.rs index eaedb1a54..b312e5de3 100644 --- a/core/src/save/level.rs +++ b/feather/base/src/anvil/level.rs @@ -1,13 +1,10 @@ //! Implements level.dat file loading. -use std::collections::HashMap; -use std::io::{Read, Write}; - -use serde::Deserialize; - -use feather_items::Item; - -use crate::Biome; +use libcraft_core::Biome; +use libcraft_items::Item; +use serde::{Deserialize, Serialize}; +use std::io::{Cursor, Read, Write}; +use std::{collections::HashMap, fs::File}; /// Root level tag #[derive(Debug, Clone, Serialize, Deserialize)] @@ -80,6 +77,25 @@ pub struct LevelData { pub generator_options: Option, } +impl LevelData { + pub fn load_from_file(file: &mut File) -> anyhow::Result { + let mut buf = vec![]; + file.read_to_end(&mut buf)?; + + nbt::from_gzip_reader::<_, Root>(Cursor::new(&buf)) + .map_err(Into::into) + .map(|root| root.data) + } + + pub fn save_to_file(&self, file: &mut File) -> anyhow::Result<()> { + let mut buf = vec![]; + nbt::to_gzip_writer(&mut buf, &Root { data: self.clone() }, None)?; + + file.write_all(&buf)?; + Ok(()) + } +} + /// Represents level version data. #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct LevelVersion { @@ -109,19 +125,19 @@ impl Default for SuperflatGeneratorOptions { structures: default_structures, layers: vec![ SuperflatLayer { - block: Item::Bedrock.identifier().to_string(), + block: Item::Bedrock.name().to_string(), height: 1, }, SuperflatLayer { - block: Item::Dirt.identifier().to_string(), + block: Item::Dirt.name().to_string(), height: 2, }, SuperflatLayer { - block: Item::GrassBlock.identifier().to_string(), + block: Item::GrassBlock.name().to_string(), height: 1, }, ], - biome: Biome::Plains.identifier().to_string(), + biome: Biome::Plains.name().to_string(), } } } @@ -148,7 +164,7 @@ impl LevelData { match self.generator_name.to_lowercase().as_str() { "default" => LevelGeneratorType::Default, "flat" => LevelGeneratorType::Flat, - "largeBiomes" => LevelGeneratorType::LargeBiomes, + "largebiomes" => LevelGeneratorType::LargeBiomes, "amplified" => LevelGeneratorType::Amplified, "buffet" => LevelGeneratorType::Buffet, "debug_all_block_states" => LevelGeneratorType::Debug, @@ -157,21 +173,6 @@ impl LevelData { } } -/// Deserializes a level.dat file from the given reader. -pub fn deserialize_level_file(reader: R) -> Result { - match nbt::from_gzip_reader::<_, Root>(reader) { - Ok(root) => Ok(root.data), - Err(e) => Err(e), - } -} - -pub fn save_level_file(level: &Root, writer: &mut W) -> Result<(), nbt::Error> { - match nbt::to_gzip_writer::<_, Root>(writer, level, None) { - Ok(_) => Ok(()), - Err(e) => Err(e), - } -} - #[cfg(test)] mod tests { use super::*; @@ -181,7 +182,7 @@ mod tests { fn test_deserialize_level_file() { let cursor = Cursor::new(include_bytes!("level.dat").to_vec()); - let level = deserialize_level_file(cursor).unwrap(); + let level = nbt::from_gzip_reader::<_, Root>(cursor).unwrap().data; assert!(!level.allow_commands); assert_eq!(level.clear_weather_time, 0); @@ -193,7 +194,7 @@ mod tests { assert!(!level.hardcore); assert!(level.initialized); assert_eq!(level.last_played, 1_560_968_104_655); - assert_eq!(level.raining, false); + assert!(!level.raining); assert_eq!(level.rain_time, 61872); assert_eq!(level.spawn_x, 0); assert_eq!(level.spawn_y, 70); diff --git a/feather/base/src/anvil/player.dat b/feather/base/src/anvil/player.dat new file mode 100644 index 000000000..11709a34c Binary files /dev/null and b/feather/base/src/anvil/player.dat differ diff --git a/feather/base/src/anvil/player.rs b/feather/base/src/anvil/player.rs new file mode 100644 index 000000000..c6389e82d --- /dev/null +++ b/feather/base/src/anvil/player.rs @@ -0,0 +1,306 @@ +use libcraft_items::{Item, ItemStack}; +use std::{ + collections::HashMap, + fs, + fs::File, + path::{Path, PathBuf}, +}; + +use nbt::Value; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use quill_common::components::{ + CanBuild, CanCreativeFly, CreativeFlying, CreativeFlyingSpeed, Instabreak, Invulnerable, + WalkSpeed, +}; + +use crate::inventory::*; + +use super::entity::{AnimalData, ItemNbt}; + +/// Represents the contents of a player data file. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PlayerData { + // Inherit base entity data + #[serde(flatten)] + pub animal: AnimalData, + + #[serde(rename = "playerGameType")] + pub gamemode: i32, + #[serde(rename = "previousPlayerGameType")] + pub previous_gamemode: i32, + #[serde(rename = "Inventory")] + pub inventory: Vec, + #[serde(rename = "SelectedItemSlot")] + pub held_item: i32, + pub abilities: PlayerAbilities, +} + +/// Represents player's abilities (flying, invulnerability, speed, etc.) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PlayerAbilities { + #[serde(rename = "walkSpeed")] + pub walk_speed: WalkSpeed, + #[serde(rename = "flySpeed")] + pub fly_speed: CreativeFlyingSpeed, + #[serde(rename = "mayfly")] + pub may_fly: CanCreativeFly, + #[serde(rename = "flying")] + pub is_flying: CreativeFlying, + #[serde(rename = "mayBuild")] + pub may_build: CanBuild, + #[serde(rename = "instabuild")] + pub instabreak: Instabreak, + pub invulnerable: Invulnerable, +} + +/// Represents a single inventory slot (including position index). +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct InventorySlot { + #[serde(rename = "Count")] + pub count: i8, + #[serde(rename = "Slot")] + #[serde(default)] + pub slot: i8, + #[serde(rename = "id")] + pub item: String, + #[serde(rename = "tag")] + pub nbt: Option, +} + +impl InventorySlot { + /// Converts an [`ItemStack`] and network protocol index into an [`InventorySlot`]. + #[allow(clippy::manual_range_contains)] + pub fn from_network_index(index: usize, stack: &ItemStack) -> Option { + let slot = if SLOT_HOTBAR_OFFSET <= index && index < SLOT_HOTBAR_OFFSET + HOTBAR_SIZE { + // Hotbar + (index - SLOT_HOTBAR_OFFSET) as i8 + } else if index == SLOT_OFFHAND { + -106 + } else if SLOT_ARMOR_MIN <= index && index <= SLOT_ARMOR_MAX { + ((SLOT_ARMOR_MAX - index) + 100) as i8 + } else if SLOT_INVENTORY_OFFSET <= index && index < SLOT_INVENTORY_OFFSET + INVENTORY_SIZE { + index as i8 + } else { + return None; + }; + + Some(Self::from_inventory_index(slot, stack)) + } + + /// Converts an [`ItemStack`] and inventory position index into an [`InventorySlot`]. + pub fn from_inventory_index(slot: i8, stack: &ItemStack) -> Self { + let nbt = stack.clone().into(); + let nbt = if nbt == Default::default() { + None + } else { + Some(nbt) + }; + Self { + count: stack.count() as i8, + slot, + item: stack.item().name().to_owned(), + nbt, + } + } + + /// Converts an NBT inventory index to a network protocol index. + /// Returns None if the index is invalid. + pub fn convert_index(&self) -> Option { + if 0 <= self.slot && self.slot <= 8 { + // Hotbar + Some(SLOT_HOTBAR_OFFSET + (self.slot as usize)) + } else if self.slot == -106 { + // Offhand + Some(SLOT_OFFHAND as usize) + } else if 100 <= self.slot && self.slot <= 103 { + // Equipment + Some((108 - self.slot) as usize) + } else if 9 <= self.slot && self.slot <= 35 { + // Rest of inventory + Some(self.slot as usize) + } else { + // Unknown index + None + } + } + + pub fn into_nbt_value(self) -> Value { + let mut compound = HashMap::new(); + + compound.insert(String::from("Count"), Value::Byte(self.count)); + compound.insert(String::from("id"), Value::String(self.item)); + compound.insert(String::from("Slot"), Value::Byte(self.slot)); + + let mut tags_compound = HashMap::new(); + if let Some(nbt) = self.nbt { + if let Some(damage) = nbt.damage { + tags_compound.insert(String::from("Damage"), Value::Int(damage)); + } + } + compound.insert(String::from("tag"), Value::Compound(tags_compound)); + Value::Compound(compound) + } +} + +impl From for ItemStack { + fn from(slot: InventorySlot) -> Self { + ItemStack::from(&slot) + } +} + +// Can't do proper Borrow trait impl because of orphan rule +impl From<&InventorySlot> for ItemStack { + fn from(slot: &InventorySlot) -> Self { + ItemNbt::item_stack( + &slot.nbt, + Item::from_name(slot.item.as_str()).unwrap_or(Item::Air), + slot.count as u8, + ) + } +} + +pub fn load_player_data(world_dir: &Path, uuid: Uuid) -> Result { + let file_path = file_path(world_dir, uuid); + let mut file = File::open(file_path)?; + let data = nbt::from_gzip_reader(&mut file)?; + Ok(data) +} + +pub fn save_player_data( + world_dir: &Path, + uuid: Uuid, + data: &PlayerData, +) -> Result<(), anyhow::Error> { + fs::create_dir_all(world_dir.join("playerdata"))?; + let file_path = file_path(world_dir, uuid); + let mut file = File::create(file_path)?; + nbt::to_gzip_writer(&mut file, data, None).map_err(anyhow::Error::from) +} + +fn file_path(world_dir: &Path, uuid: Uuid) -> PathBuf { + world_dir.join("playerdata").join(format!("{}.dat", uuid)) +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use std::io::Cursor; + + use num_traits::ToPrimitive; + + use crate::{ + inventory::{SLOT_ARMOR_CHEST, SLOT_ARMOR_FEET, SLOT_ARMOR_HEAD, SLOT_ARMOR_LEGS}, + Gamemode, + }; + + use super::*; + + #[test] + fn test_deserialize_player() { + let mut cursor = Cursor::new(include_bytes!("player.dat").to_vec()); + + let player: PlayerData = nbt::from_gzip_reader(&mut cursor).unwrap(); + assert_eq!(player.gamemode, Gamemode::Creative.to_i32().unwrap()); + assert_eq!( + player.previous_gamemode, + Gamemode::Spectator.to_i32().unwrap() + ); + assert_eq!(player.inventory[0].item, "minecraft:diamond_shovel"); + assert_eq!(player.inventory[0].nbt, Some(ItemNbt { damage: Some(3) })); + } + + #[test] + fn test_convert_item() { + let slot = InventorySlot { + count: 1, + slot: 2, + item: String::from(Item::Feather.name()), + nbt: None, + }; + + let item_stack: ItemStack = slot.into(); + assert_eq!(item_stack.item(), Item::Feather); + assert_eq!(item_stack.count(), 1); + } + + #[test] + fn test_convert_item_tags() { + let slot = InventorySlot { + count: 1, + slot: 2, + item: String::from(Item::DiamondAxe.name()), + nbt: Some(ItemNbt { damage: Some(42) }), + }; + + let item_stack: ItemStack = slot.into(); + assert_eq!(item_stack.item(), Item::DiamondAxe); + assert_eq!(item_stack.count(), 1); + assert_eq!(item_stack.damage_taken(), Some(42)); + } + + #[test] + fn test_convert_item_unknown_type() { + let slot = InventorySlot { + count: 1, + slot: 2, + item: String::from("invalid:identifier"), + nbt: None, + }; + + let item_stack: ItemStack = slot.into(); + assert_eq!(item_stack.item(), Item::Air); + } + + #[test] + fn test_convert_slot_index() { + let mut map: HashMap = HashMap::new(); + + // Equipment + map.insert(103, SLOT_ARMOR_HEAD); + map.insert(102, SLOT_ARMOR_CHEST); + map.insert(101, SLOT_ARMOR_LEGS); + map.insert(100, SLOT_ARMOR_FEET); + map.insert(-106, SLOT_OFFHAND); + + // Hotbar + for x in 0..9 { + map.insert(x, SLOT_HOTBAR_OFFSET + (x as usize)); + } + + // Rest of inventory + for x in 9..36 { + map.insert(x, x as usize); + } + + // Check all valid slots + for (src, expected) in map { + let slot = InventorySlot { + slot: src, + count: 1, + item: String::from(Item::Stone.name()), + nbt: None, + }; + assert_eq!(slot.convert_index().unwrap(), expected); + assert_eq!( + InventorySlot::from_network_index( + expected, + &ItemStack::new(Item::Stone, 1).unwrap() + ), + Some(slot), + ); + } + + // Check that invalid slots error out + for invalid_slot in [-1, -2, 104].iter() { + let slot = InventorySlot { + slot: *invalid_slot as i8, + count: 1, + item: String::from("invalid:identifier"), + nbt: None, + }; + assert!(slot.convert_index().is_none()); + } + } +} diff --git a/core/src/save/region/mod.rs b/feather/base/src/anvil/region.rs similarity index 73% rename from core/src/save/region/mod.rs rename to feather/base/src/anvil/region.rs index b471652c1..c1901b53c 100644 --- a/core/src/save/region/mod.rs +++ b/feather/base/src/anvil/region.rs @@ -1,95 +1,133 @@ -//! This module implements the loading and saving (soon) +//! This module implements the loading and saving //! of Anvil region files. -use std::collections::HashMap; +use crate::{ + chunk::{BlockStore, LightStore, PackedArray, Palette}, + Chunk, ChunkPosition, ChunkSection, +}; + +use super::{block_entity::BlockEntityData, entity::EntityData}; +use bitvec::{bitvec, vec::BitVec}; +use blocks::BlockId; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use libcraft_core::Biome; +use serde::{Deserialize, Serialize}; +use std::borrow::Cow; +use std::collections::BTreeMap; use std::fmt::{self, Display, Formatter}; use std::fs::{File, OpenOptions}; use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; -use std::path::PathBuf; +use std::ops::Deref; +use std::path::{Path, PathBuf}; use std::{fs, io, iter}; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use serde::Deserialize; - -use crate::save::entity::EntityData; -use crate::world::block::*; -use crate::world::chunk::{BitArray, Chunk, ChunkSection}; -use crate::world::ChunkPosition; -use crate::Biome; -use bitvec::bitvec; -use bitvec::vec::BitVec; -use feather_blocks::Block; - -mod blob; - /// The length and width of a region, in chunks. const REGION_SIZE: usize = 32; /// The data version supported by this code, currently corresponding -/// to 1.13.2. -const DATA_VERSION: i32 = 1631; +/// to 1.16.5. +const DATA_VERSION: i32 = 2586; /// Length, in bytes, of a sector. const SECTOR_BYTES: usize = 4096; /// Represents the data for a chunk after the "Chunk [x, y]" tag. #[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "PascalCase")] pub struct ChunkRoot { - #[serde(rename = "Level")] level: ChunkLevel, - #[serde(rename = "DataVersion")] data_version: i32, } /// Represents the level data for a chunk. #[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "PascalCase")] pub struct ChunkLevel { // TODO heightmaps, etc. #[serde(rename = "xPos")] x_pos: i32, #[serde(rename = "zPos")] z_pos: i32, - #[serde(rename = "Sections")] + last_update: i64, + inhabited_time: i64, + #[serde(default)] sections: Vec, - #[serde(rename = "Biomes")] + #[serde(serialize_with = "nbt::i32_array")] biomes: Vec, - #[serde(rename = "Entities")] + #[serde(default)] entities: Vec, + #[serde(rename = "TileEntities")] + #[serde(default)] + block_entities: Vec, + #[serde(rename = "ToBeTicked")] + #[serde(default)] + awaiting_block_updates: Vec>, + #[serde(rename = "LiquidsToBeTicked")] + #[serde(default)] + awaiting_liquid_updates: Vec>, + #[serde(default)] + post_processing: Vec>, + #[serde(rename = "TileTicks")] + #[serde(default)] + scheduled_block_updates: Vec, + #[serde(rename = "LiquidTicks")] + #[serde(default)] + scheduled_liquid_updates: Vec, + #[serde(rename = "Status")] + #[serde(default)] + worldgen_status: Cow<'static, str>, } /// Represents a chunk section in a region file. #[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "PascalCase")] pub struct LevelSection { - #[serde(rename = "Y")] y: i8, - #[serde(rename = "BlockStates")] + #[serde(serialize_with = "nbt::i64_array", rename = "BlockStates")] + #[serde(default)] states: Vec, - #[serde(rename = "Palette")] + #[serde(default)] palette: Vec, - #[serde(rename = "BlockLight")] + #[serde(serialize_with = "nbt::i8_array")] + #[serde(default)] block_light: Vec, - #[serde(rename = "SkyLight")] + #[serde(serialize_with = "nbt::i8_array")] + #[serde(default)] sky_light: Vec, } /// Represents a palette entry in a region file. #[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "PascalCase")] pub struct LevelPaletteEntry { /// The identifier of the type of this block - #[serde(rename = "Name")] - name: String, + name: Cow<'static, str>, /// Optional properties for this block - #[serde(rename = "Properties")] - props: Option, + properties: Option, } -/// Represents the proprties for a palette entry. +/// Represents the properties for a palette entry. #[derive(Serialize, Deserialize, Debug)] pub struct LevelProperties { /// Map containing a list of property names to values. #[serde(flatten)] - props: HashMap, + props: BTreeMap, Cow<'static, str>>, +} + +/// Represents a block update scheduled for a specific time. +#[derive(Serialize, Deserialize, Debug)] +pub struct ScheduledBlockUpdate { + /// The identifier of the type of this block + #[serde(rename = "i")] + name: Cow<'static, str>, + // TODO are these global or chunk coordinates? + /// X coordinate + pub x: i32, + /// Y coordinate + pub y: i32, + /// Z coordinate + pub z: i32, } /// A block of sectors in a region file. @@ -122,7 +160,7 @@ impl RegionHandle { pub fn load_chunk( &mut self, mut pos: ChunkPosition, - ) -> Result<(Chunk, Vec), Error> { + ) -> Result<(Chunk, Vec, Vec), Error> { // Get a copy of the original position before clipping let original_pos = pos; // Clip chunk position to region-local coordinates. @@ -170,7 +208,7 @@ impl RegionHandle { // Parse NBT data let cursor = Cursor::new(&buf[1..]); - let root: ChunkRoot = match compression_type { + let mut root: ChunkRoot = match compression_type { 1 => nbt::from_gzip_reader(cursor).map_err(Error::Nbt)?, 2 => nbt::from_zlib_reader(cursor).map_err(Error::Nbt)?, _ => return Err(Error::InvalidCompression(compression_type)), @@ -181,29 +219,36 @@ impl RegionHandle { return Err(Error::UnsupportedDataVersion(root.data_version)); } - let level = &root.level; + let level = &mut root.level; let mut chunk = Chunk::new(original_pos); // Read sections - for section in &level.sections { + for section in &mut level.sections { read_section_into_chunk(section, &mut chunk)?; } // Read biomes - if level.biomes.len() != 256 { + if level.biomes.len() != 1024 { return Err(Error::IndexOutOfBounds); } - for index in 0..256 { + for index in 0..1024 { let id = level.biomes[index]; - chunk.biomes_mut()[index] = - Biome::from_protocol_id(id).ok_or_else(|| Error::InvalidBiomeId(id))?; + chunk.biomes_mut().as_slice_mut()[index] = + Biome::from_id(id as u32).ok_or(Error::InvalidBiomeId(id))?; } - // Chunk was not modified, but it thinks it was: disable this - chunk.check_modified(); + // chunk.recalculate_heightmap(); + + Ok((chunk, level.entities.clone(), level.block_entities.clone())) + } - Ok((chunk, level.entities.to_vec())) + /// Checks if the specified chunk position is generated in this region. + /// # Panics + /// Panics if the specified chunk position is not within this + /// region file. + pub fn check_chunk_existence(&self, pos: ChunkPosition) -> bool { + self.header.location_for_chunk(pos).exists() } /// Saves the given chunk to this region file. The header will be updated @@ -211,7 +256,12 @@ impl RegionHandle { /// /// Behavior may be unexpected if this region file does not contain the given /// chunk position. - pub fn save_chunk(&mut self, chunk: &Chunk, entities: Vec) -> Result<(), Error> { + pub fn save_chunk( + &mut self, + chunk: &Chunk, + entities: &[EntityData], + block_entities: &[BlockEntityData], + ) -> Result<(), Error> { let chunk_pos = chunk.position(); let (local_x, local_z) = (chunk_pos.x % 32, chunk_pos.z % 32); @@ -225,16 +275,13 @@ impl RegionHandle { } // Write chunk to `ChunkRoot` tag. - let root = chunk_to_chunk_root(chunk, entities); - - let blob = blob::chunk_root_to_blob(root); + let root = chunk_to_chunk_root(chunk, entities, block_entities); // Write to intermediate buffer, because we need to know the length. let mut buf = Vec::with_capacity(4096); buf.write_u8(2).map_err(Error::Io)?; // Compression type: zlib - blob.to_zlib_writer(&mut buf) - .expect("Could not write chunk blob"); + nbt::to_zlib_writer(&mut buf, &root, None).map_err(Error::Nbt)?; let total_len = buf.len() + 4; // 4 bytes for length header @@ -274,35 +321,36 @@ impl RegionHandle { } } -fn read_section_into_chunk(section: &LevelSection, chunk: &mut Chunk) -> Result<(), Error> { +fn read_section_into_chunk(section: &mut LevelSection, chunk: &mut Chunk) -> Result<(), Error> { let data = §ion.states; // Create palette - let mut palette = vec![]; + let mut palette = Palette::new(); for entry in §ion.palette { // Construct properties map - let mut props = HashMap::new(); - if let Some(entry_props) = entry.props.as_ref() { + let mut props = BTreeMap::new(); + if let Some(entry_props) = entry.properties.as_ref() { props.extend( entry_props .props .iter() - .map(|(k, v)| (k.clone(), v.clone())), + .map(|(k, v)| (k.clone().into_owned(), v.clone().into_owned())), ); } // Attempt to get block from the given values - let block = Block::from_name_and_props(&entry.name, &props).ok_or(Error::InvalidBlock)?; - palette.push(block.native_state_id()); + let block = BlockId::from_identifier_and_properties(&entry.name, &props) + .ok_or_else(|| Error::InvalidBlock(entry.name.deref().to_owned()))?; + palette.index_or_insert(block); } // Create section // TODO don't clone data - need way around this - let data = BitArray::from_raw( - data.iter().map(|x| *x as u64).collect(), - ((data.len() as f32 * 64.0) / 4096.0).ceil() as u8, - 4096, - ); + let data = if data.is_empty() { + PackedArray::new(4096, 4) + } else { + PackedArray::from_u64_vec(data.iter().map(|x| *x as u64).collect(), 4096) + }; // Light // convert raw lighting data (4bits / block) into a BitArray @@ -324,9 +372,16 @@ fn read_section_into_chunk(section: &LevelSection, chunk: &mut Chunk) -> Result< u64::from_le_bytes(chunk) }) .collect(); - BitArray::from_raw(data, 4, 4096) + PackedArray::from_u64_vec(data, 4096) }; + if section.sky_light.is_empty() { + section.sky_light = vec![0; 2048]; + } + if section.block_light.is_empty() { + section.block_light = vec![0; 2048]; + } + if section.block_light.len() != 2048 || section.sky_light.len() != 2048 { return Err(Error::IndexOutOfBounds); } @@ -334,71 +389,90 @@ fn read_section_into_chunk(section: &LevelSection, chunk: &mut Chunk) -> Result< let block_light = convert_light_data(§ion.block_light); let sky_light = convert_light_data(§ion.sky_light); - let chunk_section = ChunkSection::new(data, Some(palette), block_light, sky_light); + let light = + LightStore::from_packed_arrays(block_light, sky_light).ok_or(Error::IndexOutOfBounds)?; + let blocks = BlockStore::from_raw_parts(Some(palette), data); - if section.y >= 16 { - // Haha... nope. - return Err(Error::IndexOutOfBounds); - } + let chunk_section = ChunkSection::new(blocks, light); - chunk.set_section_at(usize::from(section.y as u8), Some(chunk_section)); + chunk.set_section_at(section.y as isize, Some(chunk_section)); Ok(()) } -fn chunk_to_chunk_root(chunk: &Chunk, entities: Vec) -> ChunkRoot { +fn chunk_to_chunk_root( + chunk: &Chunk, + entities: &[EntityData], + block_entities: &[BlockEntityData], +) -> ChunkRoot { ChunkRoot { level: ChunkLevel { x_pos: chunk.position().x, z_pos: chunk.position().z, + last_update: 0, // TODO + inhabited_time: 0, // TODO + block_entities: block_entities.into(), sections: chunk .sections() .iter() .enumerate() - .filter_map(|(y, sec)| sec.map(|sec| (y, sec.clone()))) + .filter_map(|(y, sec)| sec.as_ref().map(|sec| (y, sec.clone()))) .map(|(y, mut section)| { let palette = convert_palette(&mut section); LevelSection { - y: y as i8, - states: section.data().inner().iter().map(|x| *x as i64).collect(), + y: (y as i8) - 1, + states: section + .blocks() + .data() + .as_u64_slice() + .iter() + .map(|x| *x as i64) + .collect(), palette, - block_light: slice_u64_to_i8(section.block_light().inner()).to_vec(), - sky_light: slice_u64_to_i8(section.sky_light().inner()).to_vec(), + block_light: slice_u64_to_i8(section.light().block_light().as_u64_slice()) + .to_vec(), + sky_light: slice_u64_to_i8(section.light().sky_light().as_u64_slice()) + .to_vec(), } }) .collect(), biomes: chunk .biomes() + .as_slice() .iter() - .map(|biome| biome.protocol_id()) + .map(|biome| biome.id() as i32) .collect(), - entities, + entities: entities.into(), + awaiting_block_updates: vec![vec![]; 16], // TODO + awaiting_liquid_updates: vec![vec![]; 16], // TODO + scheduled_block_updates: vec![], // TODO + scheduled_liquid_updates: vec![], + post_processing: vec![vec![]; 16], + worldgen_status: "postprocessed".into(), }, data_version: DATA_VERSION, } } fn convert_palette(section: &mut ChunkSection) -> Vec { - section.convert_palette_to_section(); - raw_palette_to_palette_entries(section.palette().unwrap()) + raw_palette_to_palette_entries(section.blocks().palette().unwrap().as_slice()) } -fn raw_palette_to_palette_entries(palette: &[u16]) -> Vec { +fn raw_palette_to_palette_entries(palette: &[BlockId]) -> Vec { palette .iter() - .map(|id| { - let block = Block::from_native_state_id(*id).unwrap(); - - let (name, props) = block.to_name_and_props(); - - let mut prop_map = HashMap::new(); - props.into_iter().for_each(|(name, value)| { - prop_map.insert(name.to_string(), value); - }); + .map(|block| { + let props = block.to_properties_map(); + let identifier = block.identifier(); LevelPaletteEntry { - name: name.to_string(), - props: Some(LevelProperties { props: prop_map }), + name: identifier.into(), + properties: Some(LevelProperties { + props: props + .into_iter() + .map(|(k, v)| (Cow::from(k), Cow::from(v))) + .collect(), + }), } }) .collect() @@ -466,8 +540,9 @@ impl SectorAllocator { let mut start = 0; let mut length = 0; + let mut found_block = None; for (index, is_used) in self.used_sectors.iter().enumerate() { - if is_used { + if *is_used { start = 0; length = 0; } else { @@ -482,14 +557,19 @@ impl SectorAllocator { count: length as u32, }; - (block.offset..block.offset + block.count) - .for_each(|sector| self.used_sectors.set(sector as usize, true)); - - return block; + found_block = Some(block); + break; } } } + if let Some(block) = found_block { + for sector in block.offset..block.offset + block.count { + self.used_sectors.set(sector as usize, true); + } + return block; + } + // No sector found: must allocate into end let block = SectorBlock { @@ -518,7 +598,7 @@ pub enum Error { /// An IO error occurred Io(io::Error), /// There was an invalid block in the chunk - InvalidBlock, + InvalidBlock(String), /// The chunk does not exist ChunkNotExist, /// The chunk uses an unsupported data version @@ -545,9 +625,9 @@ impl Display for Error { Error::InvalidCompression(id) => { f.write_str(&format!("Chunk uses invalid compression type {}", id))? } - Error::InvalidBlock => f.write_str("Chunk contains invalid block")?, + Error::InvalidBlock(name) => f.write_str(&format!("Chunk contains invalid block {}", name))?, Error::ChunkNotExist => f.write_str("The chunk does not exist")?, - Error::UnsupportedDataVersion(_) => f.write_str("The chunk uses an unsupported data version. Feather currently only supports 1.13.2 region files.")?, + Error::UnsupportedDataVersion(_) => f.write_str("The chunk uses an unsupported data version. Feather currently only supports 1.16.5 region files.")?, Error::InvalidBlockType => f.write_str("Chunk contains invalid block type")?, Error::MissingRootTag => f.write_str("Chunk is missing a root NBT tag")?, Error::IndexOutOfBounds => f.write_str("Section index out of bounds")?, @@ -570,7 +650,7 @@ impl std::error::Error for Error {} /// This function does not actually load all the chunks /// in the region into memory; it only reads the file's /// header so that chunks can be retrieved later. -pub fn load_region(dir: &PathBuf, pos: RegionPosition) -> Result { +pub fn load_region(dir: &Path, pos: RegionPosition) -> Result { let mut file = { let buf = region_file_path(dir, pos); @@ -582,7 +662,8 @@ pub fn load_region(dir: &PathBuf, pos: RegionPosition) -> Result Result Result { +pub fn create_region(dir: &Path, pos: RegionPosition) -> Result { create_region_dir(dir).map_err(Error::Io)?; let mut file = { let buf = region_file_path(dir, pos); @@ -632,14 +713,14 @@ fn open_opts() -> OpenOptions { .clone() } -fn region_file_path(dir: &PathBuf, pos: RegionPosition) -> PathBuf { - let mut buf = dir.clone(); +fn region_file_path(dir: &Path, pos: RegionPosition) -> PathBuf { + let mut buf = dir.to_path_buf(); buf.push(format!("region/r.{}.{}.mca", pos.x, pos.z)); buf } -fn create_region_dir(dir: &PathBuf) -> Result<(), io::Error> { - let mut dir = dir.clone(); +fn create_region_dir(dir: &Path) -> Result<(), io::Error> { + let mut dir = dir.to_path_buf(); dir.push("region"); fs::create_dir_all(dir.as_path()) } diff --git a/feather/base/src/anvil/serialization_helper.rs b/feather/base/src/anvil/serialization_helper.rs new file mode 100644 index 000000000..f6c170f3f --- /dev/null +++ b/feather/base/src/anvil/serialization_helper.rs @@ -0,0 +1,206 @@ +pub mod packed_u9 { + use serde::de::Error as DeError; + use serde::de::{SeqAccess, Visitor}; + use serde::export::Formatter; + use serde::ser::Error as SerError; + use serde::{Deserializer, Serializer}; + use std::marker::PhantomData; + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + struct PackedVisitor(PhantomData u16>); + + impl<'de> Visitor<'de> for PackedVisitor { + type Value = Vec; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("a sequence of type long with length a multiple of 9") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let len = seq.size_hint().unwrap(); // nbt always knows sequence size + if len % 9 != 0 { + // Invalid sequence length + return Err(A::Error::custom("sequence length must be a multiple of 9")); + } + let unpacked_len = len * 64 / 9; + + let mut u9_array: Vec = Vec::with_capacity(unpacked_len); + + let mut container: Option = seq.next_element()?.map(|x: i64| x as u64); // We checked the length + let mut shift = 0; + for _elem in 0..unpacked_len { + // For every element (u9) + + // unwrapping here is safe, as this can only fail if there is an implementation error in this algorithm + // or in the SeqAccess because we checked the sequence length + let mut element: u16 = ((container.unwrap() >> shift) & 0x1FF) as u16; + shift += 9; + + if shift >= 64 { + // Take next container + container = seq.next_element()?.map(|x: i64| x as u64); + + if shift > 64 { + // We have some bits left to get from the next container + + // same here with the unwrapping + element |= ((container.unwrap() << -(shift - 64 - 9)) & 0x1FF) as u16; + } + + shift -= 64; + } + + u9_array.push(element); + } + + debug_assert_eq!(container, None); + debug_assert_eq!(shift, 0); + + Ok(u9_array) + } + } + + deserializer.deserialize_seq(PackedVisitor(PhantomData)) + } + + pub fn serialize(u9_array: &[u16], serializer: S) -> Result + where + S: Serializer, + { + if u9_array.len() % 64 != 0 { + // Invalid array length + return Err(S::Error::custom("array length must be a multiple of 64")); + } + + let packed_iter = (0..u9_array.len() * 9 / 64) // iterate through each resulting u64 + .map(|i| { + ( + i / 9 * 64, // u9_array_offset; every 64 u9 the u64 boundary is aligned with the u9 boundary again -> one section. each section is 9 u64 long + i % 9, // container_index; index of the current container in this specific section + ) + }) + .map(|(u9_array_offset, container_index)| { + (0..8) // every u64 (partially) contains 8 u9 + .map(|i| { + ( + i + container_index * 7 + u9_array_offset, // u9_array index; times 7 because the u9 indices need to overlap + (i as isize) * 9 - container_index as isize, // amount of shift left (negative means shift right) + ) + }) + .map(|(u9_array_index, shift_left)| { + let u9 = u9_array[u9_array_index] as u64; + if shift_left < 0 { + u9 >> -shift_left as u64 + } else { + u9 << shift_left as u64 + } + }) + .fold(0, |container, u9| container | u9) + }) + .map(|container| container as i64); + + nbt::i64_array(packed_iter, serializer) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::iter; + use serde::{Deserialize, Serialize}; + use serde_test::Token; + + #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] + struct TestPackedU9 { + #[serde(with = "packed_u9")] + list: Vec, + } + + #[test] + #[allow(clippy::inconsistent_digit_grouping)] + fn test_packed_u9_pattern() { + let data_u64 = iter::repeat(0xAAAA_AAAA_AAAA_AAAAu64 as i64); // 64-bit 0b1010... + let data_u9 = [0b01_01_01_01_0u16, 0b1_01_01_01_01u16] + .iter() + .cloned() + .cycle(); // corresponding 9-bit pattern + + let unpacked: Vec = data_u9.take(256).collect(); + let packed: Vec = data_u64.take(36).collect(); + + // Test serde serialization + let mut tokenized_vec = packed.iter().map(|&x| Token::I64(x)).collect(); + + let mut tokenized_sequence = Vec::new(); + tokenized_sequence.push(Token::Struct { + name: "TestPackedU9", + len: 1, + }); + tokenized_sequence.push(Token::Str("list")); + // see https://github.com/PistonDevelopers/hematite_nbt/pull/52 + tokenized_sequence.push(Token::TupleStruct { + name: "__hematite_nbt_i64_array__", + len: 36, + }); + tokenized_sequence.append(&mut tokenized_vec); + tokenized_sequence.push(Token::TupleStructEnd); + tokenized_sequence.push(Token::StructEnd); + + let test_object = TestPackedU9 { list: unpacked }; + + serde_test::assert_tokens(&test_object, tokenized_sequence.as_slice()) + } + + #[test] + #[allow(clippy::inconsistent_digit_grouping)] // Sorry clippy but grouping by 9 bits makes sense here + fn test_packed_u9_order() { + let data_u64 = [ + // this repeats every 9 u64... + 0b0_001000000_000100000_000010000_000001000_000000100_000000010_000000001u64, + 0b00_000100000_000010000_000001000_000000100_000000010_000000001_01000000u64, + 0b000_000010000_000001000_000000100_000000010_000000001_010000000_0010000u64, + 0b0000_000001000_000000100_000000010_000000001_010000000_001000000_000100u64, + 0b01000_000000100_000000010_000000001_010000000_001000000_000100000_00001u64, + 0b000100_000000010_000000001_010000000_001000000_000100000_000010000_0000u64, + 0b0000010_000000001_010000000_001000000_000100000_000010000_000001000_000u64, + 0b00000001_010000000_001000000_000100000_000010000_000001000_000000100_00u64, + 0b010000000_001000000_000100000_000010000_000001000_000000100_000000010_0u64, + ] + .iter() + .cloned() + .map(|x| x as i64) + .cycle(); + let data_u9 = (0..8).map(|x| 1 << x).cycle(); // corresponding 9-bit pattern + + let unpacked: Vec = data_u9.take(256).collect(); + let packed: Vec = data_u64.take(36).collect(); + + // Test serde serialization + let mut tokenized_vec = packed.iter().map(|&x| Token::I64(x)).collect(); + + let mut tokenized_sequence = Vec::new(); + tokenized_sequence.push(Token::Struct { + name: "TestPackedU9", + len: 1, + }); + tokenized_sequence.push(Token::Str("list")); + // see https://github.com/PistonDevelopers/hematite_nbt/pull/52 + tokenized_sequence.push(Token::TupleStruct { + name: "__hematite_nbt_i64_array__", + len: 36, + }); + tokenized_sequence.append(&mut tokenized_vec); + tokenized_sequence.push(Token::TupleStructEnd); + tokenized_sequence.push(Token::StructEnd); + + let test_object = TestPackedU9 { list: unpacked }; + + serde_test::assert_tokens(&test_object, tokenized_sequence.as_slice()) + } +} diff --git a/feather/base/src/block.rs b/feather/base/src/block.rs new file mode 100644 index 000000000..be84a2049 --- /dev/null +++ b/feather/base/src/block.rs @@ -0,0 +1,163 @@ +use bytemuck::{Pod, Zeroable}; +use serde::{Deserialize, Serialize}; + +use thiserror::Error; + +use libcraft_core::{BlockPosition, ChunkPosition, Position}; +use std::convert::TryFrom; + +/// Validated position of a block. +/// +/// This structure is immutable. +/// All operations that change a [`ValidBlockPosition`] must be done by +/// turning it into a [`BlockPosition`], performing said operations, +/// then using [`ValidBlockPosition`]'s [`TryFrom`] impl to get a [`ValidBlockPosition`]. +/// +/// The definition of a valid block position is defined by [`BlockPosition::valid`]. +/// +/// # Examples +/// +/// Converting a [`BlockPosition`] to a [`ValidBlockPosition`], unwrapping any errors that +/// occur. +/// ``` +/// # use feather_base::BlockPosition; +/// # use feather_base::ValidBlockPosition; +/// # use std::convert::TryInto; +/// // Create an unvalidated block position +/// let block_position = BlockPosition::new(727, 32, 727); +/// +/// // Validate the block position and unwrap any errors +/// let valid_block_position: ValidBlockPosition = block_position.try_into().unwrap(); +/// ``` +/// +/// Performing operations on a [`ValidBlockPosition`], then re-validating it. +/// ``` +/// # use feather_base::BlockPosition; +/// # use feather_base::ValidBlockPosition; +/// # use std::convert::TryInto; +/// # let mut valid_block_position: ValidBlockPosition = BlockPosition::new(727, 32, 727).try_into().unwrap(); +/// // Convert the ValidBlockPosition into an unvalidated one to perform math +/// let mut block_position: BlockPosition = valid_block_position.into(); +/// +/// block_position.x = 821; +/// block_position.z += 32; +/// +/// assert!(block_position.valid()); +/// +/// valid_block_position = block_position.try_into().unwrap(); +/// ``` +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + Default, + Serialize, + Deserialize, + Zeroable, + Pod, +)] +#[repr(C)] +pub struct ValidBlockPosition { + x: i32, + y: i32, + z: i32, +} + +impl ValidBlockPosition { + pub fn x(&self) -> i32 { + self.x + } + + pub fn y(&self) -> i32 { + self.y + } + + pub fn z(&self) -> i32 { + self.z + } + + pub fn chunk(self) -> ChunkPosition { + self.into() + } + + pub fn position(self) -> Position { + self.into() + } +} + +impl TryFrom for ValidBlockPosition { + type Error = BlockPositionValidationError; + + fn try_from(value: BlockPosition) -> Result { + if value.valid() { + Ok(ValidBlockPosition { + x: value.x, + y: value.y, + z: value.z, + }) + } else { + Err(BlockPositionValidationError::OutOfRange(value)) + } + } +} + +impl From for BlockPosition { + fn from(position: ValidBlockPosition) -> Self { + BlockPosition { + x: position.x, + y: position.y, + z: position.z, + } + } +} + +impl From for ChunkPosition { + fn from(position: ValidBlockPosition) -> Self { + let position: BlockPosition = position.into(); + position.into() + } +} + +impl From for Position { + fn from(position: ValidBlockPosition) -> Self { + let position: BlockPosition = position.into(); + position.into() + } +} + +#[derive(Error, Debug)] +pub enum BlockPositionValidationError { + #[error("coordinate {0:?} out of range")] + OutOfRange(BlockPosition), +} + +#[cfg(test)] +mod tests { + + use std::convert::TryInto; + + use libcraft_core::BlockPosition; + + use crate::ValidBlockPosition; + + #[test] + #[should_panic] + fn check_out_of_bounds_up() { + let block_position = BlockPosition::new(0, 39483298, 0); + + >::try_into(block_position).unwrap(); + } + + #[test] + #[should_panic] + fn check_out_of_bounds_down() { + let block_position = BlockPosition::new(0, -39483298, 0); + + >::try_into(block_position).unwrap(); + } +} diff --git a/feather/base/src/chunk.rs b/feather/base/src/chunk.rs new file mode 100644 index 000000000..8568ea366 --- /dev/null +++ b/feather/base/src/chunk.rs @@ -0,0 +1,618 @@ +use std::usize; + +use ::blocks::BlockId; +use libcraft_core::Biome; + +use crate::ChunkPosition; + +/// The number of bits used for each block +/// in the global palette. +pub const GLOBAL_BITS_PER_BLOCK: u8 = 15; + +/// The minimum bits per block allowed when +/// using a section palette. +/// Bits per block values lower than this +/// value will be offsetted to this value. +pub const MIN_BITS_PER_BLOCK: u8 = 4; + +/// The maximum number of bits per block +/// allowed when using a section palette. +/// Values above this will use the global palette +/// instead. +pub const MAX_BITS_PER_BLOCK: u8 = 8; + +/// The height in blocks of a chunk column. +pub const CHUNK_HEIGHT: usize = 256; +/// The width in blocks of a chunk column. +pub const CHUNK_WIDTH: usize = 16; + +/// The height in blocks of a chunk section. +pub const SECTION_HEIGHT: usize = 16; + +/// The width in blocks of a chunk section. +pub const SECTION_WIDTH: usize = CHUNK_WIDTH; + +/// The volume in blocks of a chunk section. +pub const SECTION_VOLUME: usize = (SECTION_HEIGHT * SECTION_WIDTH * SECTION_WIDTH) as usize; + +/// The number of chunk sections in a column. +pub const NUM_SECTIONS: usize = 16; + +mod biome_store; +mod blocks; +mod heightmap; +mod light; +mod packed_array; +mod palette; + +pub use self::blocks::BlockStore; +pub use biome_store::BiomeStore; +pub use heightmap::{Heightmap, HeightmapFunction, HeightmapStore}; +pub use light::LightStore; +pub use packed_array::PackedArray; +pub use palette::Palette; + +/// A 16x256x16 chunk of blocks plus associated +/// light, biome, and heightmap data. +/// Consists of 16 `ChunkSection`s. +#[derive(Debug, Clone)] +pub struct Chunk { + sections: [Option; NUM_SECTIONS + 2], + + biomes: BiomeStore, + + heightmaps: HeightmapStore, + + position: ChunkPosition, +} + +impl Default for Chunk { + fn default() -> Self { + let sections = [ + None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, + ]; + Self { + sections, + biomes: BiomeStore::default(), + position: ChunkPosition::new(0, 0), + heightmaps: HeightmapStore::new(), + } + } +} + +impl Chunk { + /// Creates a new empty chunk with the + /// specified position. + /// + /// Biomes are initialized to plains. + pub fn new(position: ChunkPosition) -> Self { + Self::new_with_default_biome(position, Biome::Plains) + } + + /// Creates a new empty chunk with the specified + /// position. + /// + /// Biomes are initialized to `biome`. + pub fn new_with_default_biome(position: ChunkPosition, default_biome: Biome) -> Self { + Self { + position, + biomes: BiomeStore::new(default_biome), + ..Default::default() + } + } + + /// Gets the position of this chunk. + pub fn position(&self) -> ChunkPosition { + self.position + } + + /// Sets the position of this chunk. + pub fn set_position(&mut self, pos: ChunkPosition) { + self.position = pos; + } + + /// Gets the block at the given position within this chunk. + /// + /// Returns `None` if the coordinates are out of bounds. + pub fn block_at(&self, x: usize, y: usize, z: usize) -> Option { + let section = self.section_for_y(y)?; + match section { + Some(section) => section.block_at(x, y % SECTION_HEIGHT, z), + None => Some(BlockId::air()), + } + } + + /// Sets the block at the given position within this chunk. + /// + /// Returns `None` if the coordinates are out of bounds. + /// FIXME: Do not update heightmap when it is not neccessary + pub fn set_block_at(&mut self, x: usize, y: usize, z: usize, block: BlockId) -> Option<()> { + let old_block = self.block_at(x, y, z)?; + let section = self.section_for_y_mut(y)?; + let result = match section { + Some(section) => { + let result = section.set_block_at(x, y % SECTION_HEIGHT, z, block); + // If the block update caused the section to contain only + // air, free it to conserve memory. + if section.is_empty() { + self.clear_section(y); + } + result + } + None => { + if !block.is_air() { + let mut section = ChunkSection::default(); + let result = section.set_block_at(x, y % SECTION_HEIGHT, z, block); + self.set_section_at((y / SECTION_HEIGHT) as isize, Some(section)); + result + } else { + Some(()) + } + } + }; + self.heightmaps + .update(x, y, z, old_block, block, Self::block_at_fn(&self.sections)); + result + } + + /// Fills the given chunk section with `block`. + pub fn fill_section(&mut self, section: usize, block: BlockId) -> bool { + let section = match self.sections.get_mut(section) { + Some(section) => section, + None => return false, + }; + + if block == BlockId::air() { + *section = None; + } else { + let section = section.get_or_insert_with(Default::default); + section.fill(block); + } + + true + } + + /// Recalculates heightmaps for this chunk. + pub fn recalculate_heightmaps(&mut self) { + self.heightmaps + .recalculate(Self::block_at_fn(&self.sections)) + } + + fn block_at_fn( + sections: &[Option], + ) -> impl Fn(usize, usize, usize) -> BlockId + '_ { + move |x, y, z| { + let section = §ions[(y / SECTION_HEIGHT) + 1]; + match section { + Some(section) => section.block_at(x, y % SECTION_HEIGHT, z).unwrap(), + None => BlockId::air(), + } + } + } + + pub fn block_light_at(&self, x: usize, y: usize, z: usize) -> Option { + match self.section_for_y(y)? { + Some(s) => s.block_light_at(x, y % SECTION_HEIGHT, z), + None => Some(15), + } + } + + pub fn sky_light_at(&self, x: usize, y: usize, z: usize) -> Option { + match self.section_for_y(y)? { + Some(s) => s.sky_light_at(x, y % SECTION_HEIGHT, z), + None => Some(15), + } + } + + pub fn set_block_light_at(&mut self, x: usize, y: usize, z: usize, light: u8) -> Option<()> { + if let Some(section) = self.section_for_y_mut(y)? { + section.set_block_light_at(x, y, z, light) + } else { + Some(()) + } + } + + pub fn set_sky_light_at(&mut self, x: usize, y: usize, z: usize, light: u8) -> Option<()> { + if let Some(section) = self.section_for_y_mut(y)? { + section.set_sky_light_at(x, y, z, light) + } else { + Some(()) + } + } + + fn section_for_y(&self, y: usize) -> Option<&Option> { + self.sections.get((y / SECTION_HEIGHT) + 1) + } + + fn section_for_y_mut(&mut self, y: usize) -> Option<&mut Option> { + self.sections.get_mut((y / SECTION_HEIGHT) + 1) + } + + fn clear_section(&mut self, y: usize) { + self.sections[(y / SECTION_HEIGHT) + 1] = None; + } + + /// Gets the [`BiomeStore`] for this chunk. + pub fn biomes(&self) -> &BiomeStore { + &self.biomes + } + + /// Mutably gets the [`BiomeStore`] for this chunk. + pub fn biomes_mut(&mut self) -> &mut BiomeStore { + &mut self.biomes + } + + /// Gets the [`HeightmapStore`] for this chunk. + pub fn heightmaps(&self) -> &HeightmapStore { + &self.heightmaps + } + + /// Mutably gets the [`HeightmapStore`] for this chunk. + pub fn heightmaps_mut(&mut self) -> &mut HeightmapStore { + &mut self.heightmaps + } + + /// Gets the chunk section at index `y`. + pub fn section(&self, y: isize) -> Option<&ChunkSection> { + self.sections.get((y + 1) as usize)?.as_ref() + } + + /// Mutably gets the chunk section at index `y`. + pub fn section_mut(&mut self, y: isize) -> Option<&mut ChunkSection> { + self.sections.get_mut((y + 1) as usize)?.as_mut() + } + + /// Sets the section at index `y`. + pub fn set_section_at(&mut self, y: isize, section: Option) { + self.sections[(y + 1) as usize] = section; + } + + /// Gets the sections of this chunk. + pub fn sections(&self) -> &[Option] { + &self.sections + } +} + +/// A 16x16x16 chunk of blocks. +#[derive(Debug, Clone)] +pub struct ChunkSection { + blocks: BlockStore, + + light: LightStore, +} + +impl Default for ChunkSection { + fn default() -> Self { + Self::new(BlockStore::new(), LightStore::new()) + } +} + +impl ChunkSection { + /// Creates new `ChunkSection` from its + /// raw parts. + pub fn new(blocks: BlockStore, light: LightStore) -> Self { + Self { blocks, light } + } + + /// Determines whether this chunk is empty (contains only air). + pub fn is_empty(&self) -> bool { + self.non_air_blocks() == 0 + } + + /// Returns the number of air blocks in this chunk section. + pub fn air_blocks(&self) -> u32 { + self.blocks.air_blocks() + } + + /// Returns the number of non-air blocks in this chunk section. + pub fn non_air_blocks(&self) -> u32 { + SECTION_VOLUME as u32 - self.air_blocks() + } + + /// Gets the block at the given coordinates within this + /// chunk section. + pub fn block_at(&self, x: usize, y: usize, z: usize) -> Option { + self.blocks.block_at(x, y, z) + } + + /// Sets the block at the given coordinates within + /// this chunk section. + /// + /// Returns `None` if the coordinates were out of bounds. + pub fn set_block_at(&mut self, x: usize, y: usize, z: usize, block: BlockId) -> Option<()> { + self.blocks.set_block_at(x, y, z, block) + } + + /// Fills this chunk section with the given block. + /// + /// Does not currently update heightmaps. + pub fn fill(&mut self, block: BlockId) { + self.blocks.fill(block); + } + + pub fn block_light_at(&self, x: usize, y: usize, z: usize) -> Option { + self.light.block_light_at(x, y, z) + } + + pub fn sky_light_at(&self, x: usize, y: usize, z: usize) -> Option { + self.light.sky_light_at(x, y, z) + } + + pub fn set_block_light_at(&mut self, x: usize, y: usize, z: usize, light: u8) -> Option<()> { + self.light.set_block_light_at(x, y, z, light) + } + + pub fn set_sky_light_at(&mut self, x: usize, y: usize, z: usize, light: u8) -> Option<()> { + self.light.set_sky_light_at(x, y, z, light) + } + + pub fn light(&self) -> &LightStore { + &self.light + } + + pub fn light_mut(&mut self) -> &mut LightStore { + &mut self.light + } + + pub fn blocks(&self) -> &BlockStore { + &self.blocks + } + + pub fn blocks_mut(&mut self) -> &mut BlockStore { + &mut self.blocks + } + + fn block_index(x: usize, y: usize, z: usize) -> Option { + if x >= SECTION_WIDTH || y >= SECTION_WIDTH || z >= SECTION_WIDTH { + None + } else { + Some((y << 8) | (z << 4) | x) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::HIGHEST_ID; + + #[test] + fn chunk_new() { + let pos = ChunkPosition::new(0, 0); + let chunk = Chunk::new(pos); + + // Confirm that chunk is empty + for x in 0..16 { + assert!(chunk.section(x).is_none()); + assert!(chunk.section(x).is_none()); + } + + assert_eq!(chunk.position(), pos); + } + + #[test] + fn chunk_new_with_default_biome() { + let pos = ChunkPosition::new(0, 0); + let chunk = Chunk::new_with_default_biome(pos, Biome::Mountains); + + // Confirm that chunk is empty + for x in 0..16 { + assert!(chunk.section(x).is_none()); + assert!(chunk.section(x).is_none()); + } + + assert_eq!(chunk.position(), pos); + + // Confirm that biomes are set + for x in 0..4 { + for z in 0..4 { + assert_eq!(chunk.biomes.get(x, 0, z), Biome::Mountains); + } + } + } + + #[test] + fn set_block_simple() { + let pos = ChunkPosition::new(0, 0); + let mut chunk = Chunk::new(pos); + + chunk.set_block_at(0, 0, 0, BlockId::andesite()); + assert_eq!(chunk.block_at(0, 0, 0).unwrap(), BlockId::andesite()); + assert!(chunk.section(0).is_some()); + } + + #[test] + fn fill_chunk() { + let pos = ChunkPosition::new(0, 0); + let mut chunk = Chunk::new(pos); + + let block = BlockId::stone(); + + for x in 0..16 { + for y in 0..256 { + for z in 0..16 { + chunk.set_block_at(x, y, z, block).unwrap(); + assert_eq!(chunk.block_at(x, y, z), Some(block)); + } + } + } + + // Check again, just to be sure + for x in 0..16 { + for y in 0..256 { + for z in 0..16 { + assert_eq!(chunk.block_at(x, y, z), Some(block)); + } + } + } + } + + #[test] + fn spray_chunk() { + // This test fills each section of the chunk + // with the blocks with IDs corresponding + // to 0-4095 in order, testing that + // resizing, etc. works correctly. + + let pos = ChunkPosition::new(0, 0); + let mut chunk = Chunk::new(pos); + + for section in chunk.sections() { + assert!(section.is_none()); + } + + for section in 0..16 { + let mut counter = 0; + for x in 0..16 { + for y in 0..16 { + for z in 0..16 { + let block = BlockId::from_vanilla_id(counter); + chunk.set_block_at(x, (section * 16) + y, z, block); + assert_eq!(chunk.block_at(x, (section * 16) + y, z), Some(block)); + if counter != 0 { + assert!( + chunk.section(section as isize).is_some(), + "Section {} failed", + section + ); + } + counter += 1; + } + } + } + } + + // Go through again to be sure + for section in 0..16 { + assert!(chunk.section(section).is_some()); + let mut counter = 0; + for x in 0..16 { + for y in 0..16 { + for z in 0..16 { + let block = BlockId::from_vanilla_id(counter); + assert_eq!( + chunk.block_at(x, (section as usize * 16) + y, z), + Some(block) + ); + assert!(chunk.section(section).is_some()); + counter += 1; + } + } + } + } + + // Now, empty the chunk and ensure + // that the sections become empty. + for x in 0..16 { + for y in 0..256 { + for z in 0..16 { + chunk.set_block_at(x, y, z, BlockId::air()); + } + } + } + + for section in chunk.sections() { + assert!(section.is_none()); + } + } + + #[test] + fn section_from_data_and_palette() { + let pos = ChunkPosition::new(0, 0); + let mut chunk = Chunk::new(pos); + + let mut palette = Palette::new(); + let stone_index = palette.index_or_insert(BlockId::stone()); + + let mut data = PackedArray::new(4096, 5); + for i in 0..4096 { + data.set(i, stone_index as u64); + } + + let section = ChunkSection::new( + BlockStore::from_raw_parts(Some(palette), data), + LightStore::new(), + ); + chunk.set_section_at(0, Some(section)); + + for x in 0..16 { + for y in 0..16 { + for z in 0..16 { + assert_eq!(chunk.block_at(x, y, z).unwrap(), BlockId::stone()); + } + } + } + } + + #[test] + fn test_palette_insertion_in_middle() { + let mut chunk = ChunkSection::default(); + + chunk.set_block_at(0, 0, 0, BlockId::cobblestone()).unwrap(); + chunk.set_block_at(0, 1, 0, BlockId::stone()).unwrap(); + + assert_eq!(chunk.block_at(0, 0, 0).unwrap(), BlockId::cobblestone()); + assert_eq!(chunk.block_at(0, 1, 0).unwrap(), BlockId::stone()); + } + + #[test] + fn test_biomes() { + let mut chunk = Chunk::default(); + + for x in 0..4 { + for z in 0..4 { + assert_eq!(chunk.biomes().get(x, 0, z), Biome::Plains); + chunk.biomes_mut().set(x, 0, z, Biome::BirchForest); + assert_eq!(chunk.biomes().get(x, 0, z), Biome::BirchForest); + } + } + } + + #[test] + fn test_light() { + let mut chunk = Chunk::default(); + + chunk.set_block_at(0, 0, 0, BlockId::stone()).unwrap(); + + for x in 0..SECTION_WIDTH { + for y in 0..SECTION_HEIGHT { + for z in 0..SECTION_WIDTH { + chunk.set_block_light_at(x, y, z, 10); + chunk.set_sky_light_at(x, y, z, 8); + assert_eq!(chunk.block_light_at(x, y, z), Some(10)); + assert_eq!(chunk.sky_light_at(x, y, z), Some(8)); + } + } + } + } + + #[test] + fn heightmaps() { + let mut chunk = Chunk::new(ChunkPosition::new(0, 0)); + + chunk.set_block_at(0, 10, 0, BlockId::stone()); + assert_eq!(chunk.heightmaps.motion_blocking.height(0, 0), Some(10)); + } + + #[test] + fn fill_chunk_section() { + let mut section = ChunkSection::default(); + section.set_block_at(0, 0, 0, BlockId::stone()); + section.fill(BlockId::acacia_wood()); + + for x in 0..CHUNK_WIDTH { + for y in 0..SECTION_HEIGHT { + for z in 0..CHUNK_WIDTH { + assert_eq!(section.block_at(x, y, z), Some(BlockId::acacia_wood())); + } + } + } + } + + #[test] + fn global_bits() { + //The highest block state id must fit into GLOBAL_BITS_PER_BLOCK + assert_eq!(HIGHEST_ID >> GLOBAL_BITS_PER_BLOCK, 0) + } +} diff --git a/feather/base/src/chunk/biome_store.rs b/feather/base/src/chunk/biome_store.rs new file mode 100644 index 000000000..f1f1536d5 --- /dev/null +++ b/feather/base/src/chunk/biome_store.rs @@ -0,0 +1,133 @@ +use libcraft_core::Biome; + +use crate::{CHUNK_HEIGHT, CHUNK_WIDTH}; + +pub const BIOME_SAMPLE_RATE: usize = 4; + +pub const BIOMES_PER_CHUNK: usize = (CHUNK_WIDTH / BIOME_SAMPLE_RATE) + * (CHUNK_WIDTH / BIOME_SAMPLE_RATE) + * (CHUNK_HEIGHT / BIOME_SAMPLE_RATE); + +/// Stores the biomes of a chunk. +/// +/// Since Minecraft 1.16, Mojang uses a 3D +/// biome grid sampled in 4x4x4 blocks. We +/// do the same, though right now Feather +/// only uses 2D biomes. +#[derive(Debug, Copy, Clone)] +pub struct BiomeStore { + biomes: [Biome; BIOMES_PER_CHUNK], +} + +impl BiomeStore { + pub fn new(default_biome: Biome) -> Self { + Self { + biomes: [default_biome; BIOMES_PER_CHUNK], + } + } + + /// Creates a `BiomeStore` from a slice of `BIOMES_PER_CHUNK` biomes. + /// + /// Returns `None` if `biomes` is not of the correct length. + pub fn from_slice(biome_slice: &[Biome]) -> Option { + let mut biomes = [Biome::Plains; BIOMES_PER_CHUNK]; + if biomes.len() != biome_slice.len() { + return None; + } + + biomes.copy_from_slice(biome_slice); + Some(Self { biomes }) + } + + /// Sets the biome at the given coordinates, in multiples + /// of 4 blocks. + /// + /// # Panics + /// Panics if `x >= 4`, `z >= 4`, or `y >= 64`. + pub fn set(&mut self, x: usize, y: usize, z: usize, biome: Biome) { + let index = self.index(x, y, z); + self.biomes[index] = biome; + } + + /// Gets the biome at the given coordinates, + /// in multiples of 4 blocks. + /// + /// # Panics + /// Panics if `x >= 4`, `z >= 4`, or `y >= 64`. + pub fn get(&self, x: usize, y: usize, z: usize) -> Biome { + let index = self.index(x, y, z); + self.biomes[index] + } + + pub fn get_at_block(&self, x: usize, y: usize, z: usize) -> Biome { + self.get(x / 4, y / 4, z / 4) + } + + /// Gets biome data as a raw slice. + pub fn as_slice(&self) -> &[Biome] { + &self.biomes + } + + /// Gets biomes as a mutably slice. + pub fn as_slice_mut(&mut self) -> &mut [Biome] { + &mut self.biomes + } + + fn index(&self, x: usize, y: usize, z: usize) -> usize { + assert!(x < 4); + assert!(y < 64); + assert!(z < 4); + x + (z * 4) + (y * 16) + } +} + +impl Default for BiomeStore { + fn default() -> Self { + Self::new(Biome::Plains) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_biome() { + let biomes = BiomeStore::new(Biome::Badlands); + for x in 0..4 { + for y in 0..64 { + for z in 0..4 { + assert_eq!(biomes.get(x, y, z), Biome::Badlands); + } + } + } + } + + #[test] + fn set_and_get_biomes() { + let mut biomes = BiomeStore::new(Biome::Beach); + + biomes.set(0, 1, 2, Biome::BambooJungle); + assert_eq!(biomes.get(0, 1, 2), Biome::BambooJungle); + } + + #[test] + #[should_panic] + fn out_of_bounds() { + let biomes = BiomeStore::new(Biome::Plains); + biomes.get(4, 0, 0); + } + + #[test] + fn from_slice_correct_length() { + let biome_slice = [Biome::BasaltDeltas; BIOMES_PER_CHUNK]; + let biomes = BiomeStore::from_slice(&biome_slice).unwrap(); + assert_eq!(biomes.as_slice(), biome_slice); + } + + #[test] + fn from_slice_incorrect_length() { + let biome_slice = [Biome::BasaltDeltas; BIOMES_PER_CHUNK - 1]; + assert!(BiomeStore::from_slice(&biome_slice).is_none()); + } +} diff --git a/feather/base/src/chunk/blocks.rs b/feather/base/src/chunk/blocks.rs new file mode 100644 index 000000000..3fefe1258 --- /dev/null +++ b/feather/base/src/chunk/blocks.rs @@ -0,0 +1,172 @@ +use blocks::BlockId; + +use crate::ChunkSection; + +use super::{ + PackedArray, Palette, GLOBAL_BITS_PER_BLOCK, MAX_BITS_PER_BLOCK, MIN_BITS_PER_BLOCK, + SECTION_VOLUME, +}; + +/// Stores the blocks of a chunk section. +#[derive(Debug, Clone)] +pub struct BlockStore { + /// `None` if using the global palette + palette: Option, + + /// Stores indices into `palette`, or just block IDs + /// if using the global palette + blocks: PackedArray, + + air_block_count: u32, +} + +impl Default for BlockStore { + fn default() -> Self { + Self::new() + } +} + +impl BlockStore { + /// Creates a new `BlockStore` containing air. + pub fn new() -> Self { + Self { + palette: Some(Palette::new()), + blocks: PackedArray::new(SECTION_VOLUME, MIN_BITS_PER_BLOCK as usize), + air_block_count: SECTION_VOLUME as u32, + } + } + + /// Creates a new `BlockStore` from the palette + /// and data array. + pub fn from_raw_parts(palette: Option, blocks: PackedArray) -> Self { + let air_block_count = Self::count_air_blocks(&blocks, &palette); + Self { + palette, + blocks, + air_block_count, + } + } + + pub fn data(&self) -> &PackedArray { + &self.blocks + } + + pub fn data_mut(&mut self) -> &mut PackedArray { + &mut self.blocks + } + + pub fn palette(&self) -> Option<&Palette> { + self.palette.as_ref() + } + + pub fn palette_mut(&mut self) -> Option<&mut Palette> { + self.palette.as_mut() + } + + fn count_air_blocks(blocks: &PackedArray, palette: &Option) -> u32 { + let mut count = 0; + blocks.iter().for_each(|x| { + let block = match palette { + Some(p) => p.get(x as usize), + None => BlockId::from_vanilla_id(x as u16), + }; + if block.is_air() { + count += 1; + } + }); + count + } + + pub fn air_blocks(&self) -> u32 { + self.air_block_count + } + + pub fn set_air_blocks(&mut self, new_value: u32) { + self.air_block_count = new_value; + } + + pub fn block_at(&self, x: usize, y: usize, z: usize) -> Option { + let index = ChunkSection::block_index(x, y, z)?; + let block_index = self.blocks.get(index).expect("block_index out of bounds?"); + + Some(match &self.palette { + Some(palette) => palette.get(block_index as usize), + None => BlockId::from_vanilla_id(block_index as u16), + }) + } + + pub fn set_block_at(&mut self, x: usize, y: usize, z: usize, block: BlockId) -> Option<()> { + let index = ChunkSection::block_index(x, y, z)?; + self.update_air_block_count(x, y, z, block); + + let block_index = self.get_block_palette_index(block); + self.blocks.set(index, block_index as u64); + + Some(()) + } + + pub fn fill(&mut self, block: BlockId) { + let index = if let Some(ref mut palette) = self.palette { + palette.clear(); + palette.index_or_insert(block) + } else { + self.palette = Some(Palette::new()); + self.palette.as_mut().unwrap().index_or_insert(block) + }; + + self.blocks.fill(index as u64); + + if block.is_air() { + self.air_block_count = SECTION_VOLUME as u32; + } else { + self.air_block_count = 0; + } + } + + fn get_block_palette_index(&mut self, block: BlockId) -> usize { + match &mut self.palette { + Some(p) => { + let index = p.index_or_insert(block); + self.resize_if_needed(); + index + } + None => block.vanilla_id() as usize, + } + } + + fn resize_if_needed(&mut self) { + let palette = self.palette.as_ref().unwrap(); + + if palette.len() - 1 > self.blocks.max_value() as usize { + // Resize to either the global palette or a new section palette size. + let new_size = self.blocks.bits_per_value() + 1; + if new_size > MAX_BITS_PER_BLOCK as usize { + self.use_global_palette(); + } else { + self.blocks = self.blocks.resized(new_size); + } + } + } + + fn use_global_palette(&mut self) { + self.blocks = self.blocks.resized(GLOBAL_BITS_PER_BLOCK as usize); + let palette = self.palette.as_ref().unwrap(); + + // Update blocks to use vanilla IDs instead of palette indices + for i in 0..SECTION_VOLUME { + let block = palette.get(self.blocks.get(i).unwrap() as usize); + self.blocks.set(i, block.vanilla_id() as u64); + } + + self.palette = None; + } + + fn update_air_block_count(&mut self, x: usize, y: usize, z: usize, new: BlockId) { + let old = self.block_at(x, y, z).unwrap(); + if old.is_air() && !new.is_air() { + self.air_block_count -= 1; + } else if !old.is_air() && new.is_air() { + self.air_block_count += 1; + } + } +} diff --git a/feather/base/src/chunk/heightmap.rs b/feather/base/src/chunk/heightmap.rs new file mode 100644 index 000000000..14c954233 --- /dev/null +++ b/feather/base/src/chunk/heightmap.rs @@ -0,0 +1,202 @@ +use std::marker::PhantomData; + +use blocks::{BlockId, SimplifiedBlockKind}; + +use crate::{CHUNK_HEIGHT, CHUNK_WIDTH}; + +use super::PackedArray; + +/// Stores heightmaps for a chunk. +#[derive(Debug, Clone)] +pub struct HeightmapStore { + pub motion_blocking: Heightmap, + pub motion_blocking_no_leaves: Heightmap, + pub light_blocking: Heightmap, + pub ocean_floor: Heightmap, + pub world_surface: Heightmap, +} + +impl Default for HeightmapStore { + fn default() -> Self { + Self::new() + } +} + +impl HeightmapStore { + pub fn new() -> Self { + Self { + motion_blocking: Heightmap::new(), + motion_blocking_no_leaves: Heightmap::new(), + light_blocking: Heightmap::new(), + ocean_floor: Heightmap::new(), + world_surface: Heightmap::new(), + } + } + + pub fn update( + &mut self, + x: usize, + y: usize, + z: usize, + old_block: BlockId, + new_block: BlockId, + get_block: impl Fn(usize, usize, usize) -> BlockId, + ) { + self.motion_blocking + .update(x, y, z, old_block, new_block, &get_block); + self.motion_blocking_no_leaves + .update(x, y, z, old_block, new_block, &get_block); + self.light_blocking + .update(x, y, z, old_block, new_block, &get_block); + self.ocean_floor + .update(x, y, z, old_block, new_block, &get_block); + self.world_surface + .update(x, y, z, old_block, new_block, &get_block); + } + + pub fn recalculate(&mut self, get_block: impl Fn(usize, usize, usize) -> BlockId) { + self.motion_blocking.recalculate(&get_block); + self.motion_blocking_no_leaves.recalculate(&get_block); + self.light_blocking.recalculate(&get_block); + self.ocean_floor.recalculate(&get_block); + self.world_surface.recalculate(&get_block); + } +} + +/// A function used to compute heightmaps. +pub trait HeightmapFunction { + /// Returns whether a block should be considered + /// "solid" during the heightmap computation. + fn is_solid(block: BlockId) -> bool; +} + +#[derive(Debug, Clone)] +pub struct LightBlocking; +impl HeightmapFunction for LightBlocking { + fn is_solid(block: BlockId) -> bool { + block.is_opaque() + } +} + +#[derive(Debug, Clone)] +pub struct MotionBlocking; +impl HeightmapFunction for MotionBlocking { + fn is_solid(block: BlockId) -> bool { + block.is_solid() || block.is_fluid() + } +} + +#[derive(Debug, Clone)] +pub struct MotionBlockingNoLeaves; +impl HeightmapFunction for MotionBlockingNoLeaves { + fn is_solid(block: BlockId) -> bool { + (block.is_solid() || block.is_fluid()) + && block.simplified_kind() != SimplifiedBlockKind::Leaves + } +} + +#[derive(Debug, Clone)] +pub struct OceanFloor; +impl HeightmapFunction for OceanFloor { + fn is_solid(block: BlockId) -> bool { + block.is_solid() + } +} + +#[derive(Debug, Clone)] +pub struct WorldSurface; +impl HeightmapFunction for WorldSurface { + fn is_solid(block: BlockId) -> bool { + !block.is_air() + } +} + +#[derive(Debug, Clone)] +pub struct Heightmap { + heights: PackedArray, + _marker: PhantomData, +} + +impl Default for Heightmap +where + F: HeightmapFunction, +{ + fn default() -> Self { + Self::new() + } +} + +impl Heightmap +where + F: HeightmapFunction, +{ + pub fn new() -> Self { + Self { + heights: PackedArray::new(256, 9), + _marker: PhantomData, + } + } + + pub fn set_height(&mut self, x: usize, z: usize, height: usize) { + let index = self.index(x, z); + self.heights.set(index, height as u64); + } + + pub fn set_height_index(&mut self, index: usize, height: i64) { + self.heights.as_u64_mut_vec()[index] = height as u64; + } + + pub fn height(&self, x: usize, z: usize) -> Option { + let index = self.index(x, z); + self.heights.get(index).map(|x| x as usize) + } + + pub fn as_u64_slice(&self) -> &[u64] { + self.heights.as_u64_slice() + } + + fn index(&self, x: usize, z: usize) -> usize { + (z << 4) | x + } + + /// Updates this height map after a block has been updated. + pub fn update( + &mut self, + x: usize, + y: usize, + z: usize, + old_block: BlockId, + new_block: BlockId, + get_block: impl Fn(usize, usize, usize) -> BlockId, + ) { + if F::is_solid(old_block) && self.height(x, z) == Some(y) { + // This was old the highest block + for i in (0..y).rev() { + let block = get_block(x, i, z); + + if F::is_solid(block) { + self.set_height(x, z, i + 1); + break; + } + } + } + if F::is_solid(new_block) && self.height(x, z).unwrap() < y { + // This is the new highest block + self.set_height(x, z, y); + } + } + + /// Recalculates this entire heightmap. + pub fn recalculate(&mut self, get_block: impl Fn(usize, usize, usize) -> BlockId) { + for x in 0..CHUNK_WIDTH { + for z in 0..CHUNK_WIDTH { + for y in (0..CHUNK_HEIGHT).rev() { + if F::is_solid(get_block(x, y, z)) { + self.set_height(x, z, y + 1); + break; + } + } + } + } + } +} diff --git a/feather/base/src/chunk/light.rs b/feather/base/src/chunk/light.rs new file mode 100644 index 000000000..433b01a4e --- /dev/null +++ b/feather/base/src/chunk/light.rs @@ -0,0 +1,74 @@ +use crate::ChunkSection; + +use super::{PackedArray, SECTION_VOLUME}; + +/// Contains light data for a chunk section. +#[derive(Debug, Clone)] +pub struct LightStore { + block_light: PackedArray, + sky_light: PackedArray, +} + +impl Default for LightStore { + fn default() -> Self { + Self::new() + } +} + +impl LightStore { + /// Creates a `LightStore` with sky light set to 15. + pub fn new() -> Self { + let mut this = LightStore { + block_light: PackedArray::new(SECTION_VOLUME, 4), + sky_light: PackedArray::new(SECTION_VOLUME, 4), + }; + this.sky_light.fill(15); + this + } + + /// Creates a `LightStore` from packed arrays. + pub fn from_packed_arrays(block_light: PackedArray, sky_light: PackedArray) -> Option { + if block_light.len() != SECTION_VOLUME + || sky_light.len() != SECTION_VOLUME + || block_light.bits_per_value() != 4 + || sky_light.bits_per_value() != 4 + { + None + } else { + Some(Self { + block_light, + sky_light, + }) + } + } + + pub fn block_light_at(&self, x: usize, y: usize, z: usize) -> Option { + let index = ChunkSection::block_index(x, y, z)?; + self.block_light.get(index).map(|x| x as u8) + } + + pub fn sky_light_at(&self, x: usize, y: usize, z: usize) -> Option { + let index = ChunkSection::block_index(x, y, z)?; + self.sky_light.get(index).map(|x| x as u8) + } + + pub fn set_block_light_at(&mut self, x: usize, y: usize, z: usize, light: u8) -> Option<()> { + let index = ChunkSection::block_index(x, y, z)?; + self.block_light.set(index, light.min(15) as u64); + Some(()) + } + + pub fn set_sky_light_at(&mut self, x: usize, y: usize, z: usize, light: u8) -> Option<()> { + let index = ChunkSection::block_index(x, y, z)?; + self.sky_light.set(index, light.min(15) as u64); + Some(()) + } + + pub fn block_light(&self) -> &PackedArray { + &self.block_light + } + + pub fn sky_light(&self) -> &PackedArray { + &self.sky_light + } +} diff --git a/feather/base/src/chunk/packed_array.rs b/feather/base/src/chunk/packed_array.rs new file mode 100644 index 000000000..f1d3eae8c --- /dev/null +++ b/feather/base/src/chunk/packed_array.rs @@ -0,0 +1,298 @@ +/// A packed array of integers where each integer consumes +/// `n` bits. Used to store block data in chunks. +#[derive(Debug, Clone)] +pub struct PackedArray { + length: usize, + bits_per_value: usize, + bits: Vec, +} + +impl PackedArray { + /// Creates a new `PackedArray` with the given length + /// and number of bits per value. Values are initialized + /// to zero. + /// + /// # Panics + /// Panics if `bits_per_value > 64`. + pub fn new(length: usize, bits_per_value: usize) -> Self { + let mut this = Self { + length, + bits_per_value, + bits: Vec::new(), + }; + let needed_u64s = this.needed_u64s(); + this.bits = vec![0u64; needed_u64s]; + + this + } + + /// Creates a `PackedArray` from raw `u64` data + /// and a length. + pub fn from_u64_vec(bits: Vec, length: usize) -> Self { + let bits_per_value = bits.len() * 64 / length; + Self { + length, + bits_per_value, + bits, + } + } + + /// Gets the value at the given index. + #[inline] + pub fn get(&self, index: usize) -> Option { + if index >= self.len() { + return None; + } + + let (u64_index, bit_index) = self.indexes(index); + + let u64 = self.bits[u64_index]; + Some((u64 >> bit_index) & self.mask()) + } + + /// Sets the value at the given index. + /// + /// # Panics + /// Panics if `index >= self.length()` or `value > self.max_value()`. + #[inline] + pub fn set(&mut self, index: usize, value: u64) { + assert!( + index < self.len(), + "index out of bounds: index is {}; length is {}", + index, + self.len() + ); + + let mask = self.mask(); + assert!(value <= mask); + + let (u64_index, bit_index) = self.indexes(index); + + let u64 = &mut self.bits[u64_index]; + *u64 &= !(mask << bit_index); + *u64 |= value << bit_index; + } + + /// Sets all values is the packed array to `value`. + /// + /// # Panics + /// Panics if `value > self.max_value()`. + pub fn fill(&mut self, value: u64) { + assert!(value <= self.max_value()); + let mut x = 0; + for i in 0..self.values_per_u64() { + x |= value << (i * self.bits_per_value); + } + + self.bits.fill(x); + } + + /// Returns an iterator over values in this array. + pub fn iter(&self) -> impl Iterator + '_ { + let values_per_u64 = self.values_per_u64(); + let bits_per_value = self.bits_per_value() as u64; + let mask = self.mask(); + let length = self.len(); + + self.bits + .iter() + .flat_map(move |&u64| { + (0..values_per_u64).map(move |i| (u64 >> (i as u64 * bits_per_value)) & mask) + }) + .take(length) + } + + /// Resizes this packed array to a new bits per value. + pub fn resized(&mut self, new_bits_per_value: usize) -> PackedArray { + Self::from_iter(self.iter(), new_bits_per_value) + } + + /// Collects an iterator into a `PackedArray`. + pub fn from_iter(iter: impl IntoIterator, bits_per_value: usize) -> Self { + assert!(bits_per_value <= 64); + let iter = iter.into_iter(); + let mut bits = Vec::with_capacity(iter.size_hint().0); + + let mut current_u64 = 0u64; + let mut current_offset = 0; + let mut length = 0; + + for value in iter { + debug_assert!(value < 1 << bits_per_value); + current_u64 |= value << current_offset; + + current_offset += bits_per_value; + if current_offset > 64 - bits_per_value { + bits.push(current_u64); + current_offset = 0; + current_u64 = 0; + } + + length += 1; + } + + if current_offset != 0 { + bits.push(current_u64); + } + + Self { + length, + bits_per_value, + bits, + } + } + + /// Returns the maximum value of an integer in this packed array. + #[inline] + pub fn max_value(&self) -> u64 { + self.mask() + } + + /// Returns the length of this packed array. + #[inline] + pub fn len(&self) -> usize { + self.length + } + + /// Determines whether the length of this array is 0. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of bits used to represent each value. + #[inline] + pub fn bits_per_value(&self) -> usize { + self.bits_per_value + } + + pub fn set_bits_per_value(&mut self, new_value: usize) { + self.bits_per_value = new_value; + } + + /// Gets the raw `u64` data. + pub fn as_u64_slice(&self) -> &[u64] { + &self.bits + } + + pub fn as_u64_mut_vec(&mut self) -> &mut Vec { + &mut self.bits + } + + fn mask(&self) -> u64 { + (1 << self.bits_per_value) - 1 + } + + fn needed_u64s(&self) -> usize { + (self.length + self.values_per_u64() - 1) / self.values_per_u64() + } + + fn values_per_u64(&self) -> usize { + 64 / self.bits_per_value + } + + fn indexes(&self, index: usize) -> (usize, usize) { + let u64_index = index / self.values_per_u64(); + let bit_index = (index % self.values_per_u64()) * self.bits_per_value; + + (u64_index, bit_index) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::{Rng, SeedableRng}; + use rand_pcg::Pcg64Mcg; + + #[test] + fn smoke() { + let length = 100; + let mut array = PackedArray::new(length, 10); + assert_eq!(array.len(), length); + assert_eq!(array.bits_per_value(), 10); + assert_eq!(array.bits.len(), 17); + + for i in 0..length { + assert_eq!(array.get(i), Some(0)); + array.set(i, (i * 10) as u64); + assert_eq!(array.get(i), Some((i * 10) as u64)); + } + } + + #[test] + fn out_of_bounds() { + let array = PackedArray::new(97, 10); + assert_eq!(array.bits.len(), 17); + assert_eq!(array.get(96), Some(0)); + assert_eq!(array.get(97), None); + } + + #[test] + fn iter() { + let mut array = PackedArray::new(10_000, 10); + let mut rng = Pcg64Mcg::seed_from_u64(10); + let mut oracle = Vec::new(); + + for i in 0..array.len() { + let value = rng.gen_range(0..1024); + oracle.push(value); + array.set(i, value); + assert_eq!(array.get(i), Some(value)); + } + + for (i, &oracle_value) in oracle.iter().enumerate() { + assert_eq!(array.get(i), Some(oracle_value)); + } + + for (value, &oracle_value) in array.iter().zip(oracle.iter()) { + assert_eq!(value, oracle_value); + } + } + + #[test] + fn resize() { + let mut rng = Pcg64Mcg::seed_from_u64(11); + + let length = 1024; + let mut array = PackedArray::new(length, 1); + + let mut oracle = Vec::new(); + for new_bits_per_value in 2..=16 { + for i in 0..array.len() { + let value = rng.gen_range(0..array.max_value() + 1); + array.set(i, value); + oracle.push(value); + } + + for (i, &oracle_value) in oracle.iter().enumerate() { + assert_eq!(array.get(i), Some(oracle_value)); + } + + array = array.resized(new_bits_per_value); + + for (i, &oracle_value) in oracle.iter().enumerate() { + assert_eq!(array.get(i), Some(oracle_value)); + } + + oracle.clear(); + } + } + + #[test] + fn fill() { + let mut array = PackedArray::new(1024, 10); + array.fill(102); + assert!(array.iter().all(|x| x == 102)); + + array.fill(256); + assert!(array.iter().all(|x| x == 256)); + } + + #[test] + #[should_panic] + fn fill_too_large() { + let mut array = PackedArray::new(100, 10); + array.fill(1024); // 1024 == 2^10 + } +} diff --git a/feather/base/src/chunk/palette.rs b/feather/base/src/chunk/palette.rs new file mode 100644 index 000000000..97a05008d --- /dev/null +++ b/feather/base/src/chunk/palette.rs @@ -0,0 +1,152 @@ +use blocks::BlockId; + +/// Stores the set of distinct `BlockId`s in a chunk section. +/// +/// Empty entries in the palette default to air. +/// +/// The entry with index 0 is always air. +#[derive(Debug, Clone)] +pub struct Palette { + blocks: Vec, + free_indices: Vec, +} + +impl Default for Palette { + fn default() -> Self { + Self::new() + } +} + +#[allow(clippy::len_without_is_empty)] // palette is never empty +impl Palette { + /// Creates an empty palette. + pub fn new() -> Self { + Self { + blocks: vec![BlockId::air()], + free_indices: Vec::new(), + } + } + + /// Gets the blocks in this palette as a slice. + pub fn as_slice(&self) -> &[BlockId] { + &self.blocks + } + + /// Gets the index in the palette of `block`. + /// Inserts the block into the palette if it + /// does not already exist. + pub fn index_or_insert(&mut self, block: BlockId) -> usize { + match self.index_of(block) { + Some(i) => i, + None => self.insert(block), + } + } + + fn insert(&mut self, block: BlockId) -> usize { + match self.free_indices.pop() { + Some(i) => { + self.blocks[i] = block; + i + } + None => { + let i = self.blocks.len(); + self.blocks.push(block); + i + } + } + } + + /// Gets the block at index `i`, or air if + /// the palette does not contain `i`. + pub fn get(&self, index: usize) -> BlockId { + self.blocks.get(index).copied().unwrap_or_else(BlockId::air) + } + + /// Gets the number of blocks in the palette. + pub fn len(&self) -> usize { + self.blocks.len() + } + + /// Removes the given block from this palette. + pub fn remove(&mut self, block: BlockId) { + if let Some(index) = self.index_of(block) { + self.blocks[index] = BlockId::air(); + self.free_indices.push(index); + } + } + + /// Clears the palette, leaving only the air entry at index 0. + pub fn clear(&mut self) { + self.blocks.clear(); + self.blocks.push(BlockId::air()); + } + + fn index_of(&self, block: BlockId) -> Option { + self.blocks.iter().position(|b| *b == block) + } +} + +#[cfg(test)] +mod tests { + use ahash::AHashMap; + use blocks::BlockId; + + use super::*; + + #[test] + fn add_blocks() { + let mut palette = Palette::new(); + + for i in 0..100 { + let index = palette.index_or_insert(BlockId::from_vanilla_id(i)); + assert_eq!(index, i as usize); + assert_eq!(palette.get(index), BlockId::from_vanilla_id(i)); + } + + assert_eq!(palette.len(), 100); + } + + #[test] + fn empty_entries_are_air() { + let palette = Palette::new(); + assert_eq!(palette.get(0), BlockId::air()); + } + + #[test] + fn remove_blocks() { + let mut palette = Palette::new(); + + let mut mapping: AHashMap = AHashMap::new(); + + for i in 0..100 { + let block = BlockId::from_vanilla_id(i); + let index = palette.index_or_insert(BlockId::from_vanilla_id(i)); + if i % 2 == 0 { + palette.remove(block); + } else { + mapping.insert(block, index); + } + } + + assert_eq!(palette.len(), 50); + + for i in 0..100 { + if i % 2 == 0 { + continue; + } + let block = BlockId::from_vanilla_id(i); + assert_eq!(palette.index_or_insert(block), mapping[&block]); + } + } + + #[test] + fn clear() { + let mut palette = Palette::new(); + for id in 100..200 { + palette.index_or_insert(BlockId::from_vanilla_id(id)); + } + palette.clear(); + assert_eq!(palette.len(), 1); + assert_eq!(palette.index_of(BlockId::air()), Some(0)); + } +} diff --git a/feather/base/src/chunk_lock.rs b/feather/base/src/chunk_lock.rs new file mode 100644 index 000000000..033281d09 --- /dev/null +++ b/feather/base/src/chunk_lock.rs @@ -0,0 +1,134 @@ +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; + +use crate::Chunk; +use anyhow::bail; +use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; + +pub type ChunkHandle = Arc; +/// A wrapper around a RwLock. Cannot be locked for writing when unloaded. +/// This structure exists so that a chunk can be read from even after being unloaded without accidentaly writing to it. +#[derive(Debug)] +pub struct ChunkLock { + loaded: AtomicBool, + lock: RwLock, +} +impl ChunkLock { + pub fn new(chunk: Chunk, loaded: bool) -> Self { + Self { + loaded: AtomicBool::new(loaded), + lock: RwLock::new(chunk), + } + } + /// Returns whether the chunk is loaded. + pub fn is_loaded(&self) -> bool { + self.loaded.load(Ordering::SeqCst) + } + /// Attempts to set the chunk as unloaded. Returns an error if the chunk is locked as writable. + pub fn set_unloaded(&self) -> anyhow::Result<()> { + if self.loaded.swap(false, Ordering::SeqCst) { + // FIXME: Decide what to do when unloading an unloaded chunk + } + if self.lock.try_read().is_none() { + // Locking fails when someone else already owns a write lock + bail!("Cannot unload chunk because it is locked as writable!") + } + Ok(()) + } + /// Sets the chunk as loaded and returns the previous state. + pub fn set_loaded(&self) -> bool { + self.loaded.swap(true, Ordering::SeqCst) + } + + /// Locks this chunk with read acccess. Doesn't block. + /// Returns None if the chunk is unloaded or locked for writing, Some otherwise. + pub fn try_read(&self) -> Option> { + self.lock.try_read() + } + + /// Locks this chunk with read acccess, blocking the current thread until it can be acquired. + /// Returns None if the chunk is unloaded, Some otherwise. + pub fn read(&self) -> RwLockReadGuard { + self.lock.read() + } + /// Locks this chunk with exclusive write acccess. Doesn't block. + /// Returns None if the chunk is unloaded or locked already, Some otherwise. + pub fn try_write(&self) -> Option> { + if self.is_loaded() { + self.lock.try_write() + } else { + None + } + } + /// Locks this chunk with exclusive write acccess, blocking the current thread until it can be acquired. + /// Returns None if the chunk is unloaded, Some otherwise. + pub fn write(&self) -> Option> { + if self.is_loaded() { + Some(self.lock.write()) + } else { + None + } + } + + pub fn is_locked(&self) -> bool { + self.lock.is_locked() + } +} + +#[cfg(test)] +mod tests { + use std::{ + thread::{sleep, spawn, JoinHandle}, + time::Duration, + }; + + use libcraft_core::ChunkPosition; + + use super::*; + fn empty_lock(x: i32, z: i32, loaded: bool) -> ChunkLock { + ChunkLock::new(Chunk::new(ChunkPosition::new(x, z)), loaded) + } + #[test] + fn normal_function() { + let lock = empty_lock(0, 0, true); + for _ in 0..100 { + // It should be possible to lock in any way + if rand::random::() { + let _guard = lock.try_read().unwrap(); + } else { + let _guard = lock.try_write().unwrap(); + } + } + } + #[test] + fn cannot_write_unloaded() { + let lock = empty_lock(0, 0, false); + assert!(lock.try_write().is_none()) + } + #[test] + fn can_read_unloaded() { + let lock = empty_lock(0, 0, false); + assert!(lock.try_read().is_some()) + } + #[test] + fn multithreaded() { + let lock = Arc::new(empty_lock(0, 0, true)); + let mut handles: Vec> = vec![]; + for _ in 0..20 { + let l = lock.clone(); + handles.push(spawn(move || { + while let Some(guard) = l.write() { + sleep(Duration::from_millis(10)); + drop(guard) + } + })) + } + sleep(Duration::from_millis(1000)); + lock.set_unloaded().unwrap_or(()); // Discard error + for h in handles { + h.join().unwrap() // Wait for all threads to stop + } + } +} diff --git a/feather/base/src/inventory.rs b/feather/base/src/inventory.rs new file mode 100644 index 000000000..1351f771d --- /dev/null +++ b/feather/base/src/inventory.rs @@ -0,0 +1,32 @@ +//! Constants representing various standard inventory slot indices +//! for the `Player` window +//! Deprecated; mainly exists for interop with world saves. + +pub const SLOT_CRAFTING_OUTPUT: usize = 0; +pub const SLOT_CRAFTING_INPUT_X0_Y0: usize = 1; +pub const SLOT_CRAFTING_INPUT_X1_Y0: usize = 2; +pub const SLOT_CRAFTING_INPUT_X0_Y1: usize = 3; +pub const SLOT_CRAFTING_INPUT_X1_Y1: usize = 4; + +pub const SLOT_ARMOR_MIN: usize = 5; +pub const SLOT_ARMOR_MAX: usize = 8; + +pub const SLOT_ARMOR_HEAD: usize = 5; +pub const SLOT_ARMOR_CHEST: usize = 6; +pub const SLOT_ARMOR_LEGS: usize = 7; +pub const SLOT_ARMOR_FEET: usize = 8; + +pub const SLOT_OFFHAND: usize = 45; + +pub const SLOT_INVENTORY_OFFSET: usize = 9; +pub const SLOT_HOTBAR_OFFSET: usize = 36; + +pub const HOTBAR_SIZE: usize = 9; +pub const INVENTORY_SIZE: usize = 27; + +pub const SLOT_ENTITY_EQUIPMENT_MAIN_HAND: usize = 0; +pub const SLOT_ENTITY_EQUIPMENT_OFF_HAND: usize = 1; +pub const SLOT_ENTITY_EQUIPMENT_BOOTS: usize = 2; +pub const SLOT_ENTITY_EQUIPMENT_LEGGINGS: usize = 3; +pub const SLOT_ENTITY_EQUIPMENT_CHESTPLATE: usize = 4; +pub const SLOT_ENTITY_EQUIPMENT_HELMET: usize = 5; diff --git a/feather/base/src/lib.rs b/feather/base/src/lib.rs new file mode 100644 index 000000000..730d4c51a --- /dev/null +++ b/feather/base/src/lib.rs @@ -0,0 +1,61 @@ +//! Core functionality for Feather. This crate primarily +//! implements or reexports essential data structures, such as: +//! * Inventories +//! * The block ID system +//! * The chunk data structure + +use std::time::Duration; + +use num_derive::{FromPrimitive, ToPrimitive}; +use serde::{Deserialize, Serialize}; + +pub mod anvil; +mod block; +pub mod chunk; +pub mod chunk_lock; +pub mod inventory; +pub mod metadata; + +pub use block::{BlockPositionValidationError, ValidBlockPosition}; +pub use blocks::*; +pub use chunk::{Chunk, ChunkSection, CHUNK_HEIGHT, CHUNK_WIDTH}; +pub use chunk_lock::*; + +pub use libcraft_blocks::{BlockKind, BlockState}; +pub use libcraft_core::{ + position, vec3, Biome, BlockPosition, ChunkPosition, EntityKind, Gamemode, Position, Vec3d, +}; +pub use libcraft_inventory::{Area, Inventory}; +pub use libcraft_items::{Item, ItemStack, ItemStackBuilder, ItemStackError}; +pub use libcraft_particles::{Particle, ParticleKind}; +pub use libcraft_text::{deserialize_text, Text, Title}; +#[doc(inline)] +pub use metadata::EntityMetadata; + +/// Number of updates (ticks) to do per second. +pub const TPS: u32 = 20; +/// The number of milliseconds per tick. +pub const TICK_MILLIS: u32 = 1000 / TPS; +/// The duration of a tick. +pub const TICK_DURATION: Duration = Duration::from_millis(TICK_MILLIS as u64); + +/// Default port for Minecraft servers. +pub const DEFAULT_PORT: u16 = 25565; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, FromPrimitive, ToPrimitive)] +pub enum Direction { + North, + South, + East, + West, +} + +/// A profile property, which stores metadata +/// for some player's account. This is usually +/// used to store skin data. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ProfileProperty { + pub name: String, + pub value: String, + pub signature: String, +} diff --git a/feather/base/src/metadata.rs b/feather/base/src/metadata.rs new file mode 100644 index 000000000..92b62b852 --- /dev/null +++ b/feather/base/src/metadata.rs @@ -0,0 +1,229 @@ +//! This module implements the entity +//! metadata format. See +//! for the specification. + +use crate::{Direction, ValidBlockPosition}; +use bitflags::bitflags; +use libcraft_items::InventorySlot; +use std::collections::BTreeMap; +use uuid::Uuid; + +pub type OptUuid = Option; +pub type OptChat = Option; +pub type OptVarInt = Option; + +// Meta index constants. +pub const META_INDEX_ENTITY_BITMASK: u8 = 0; +pub const META_INDEX_AIR: u8 = 1; +pub const META_INDEX_CUSTOM_NAME: u8 = 2; +pub const META_INDEX_IS_CUSTOM_NAME_VISIBLE: u8 = 3; +pub const META_INDEX_IS_SILENT: u8 = 4; +pub const META_INDEX_NO_GRAVITY: u8 = 5; + +pub const META_INDEX_POSE: u8 = 6; + +pub const META_INDEX_FALLING_BLOCK_SPAWN_POSITION: u8 = 7; + +bitflags! { + pub struct EntityBitMask: u8 { + const ON_FIRE = 0x01; + const CROUCHED = 0x02; + const SPRINTING = 0x08; + const SWIMMING = 0x10; + const INVISIBLE = 0x20; + const GLOWING_EFFECT = 0x40; + const FLYING_WITH_ELYTRA = 0x80; + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum MetaEntry { + Byte(i8), + VarInt(i32), + Float(f32), + String(String), + Chat(String), + OptChat(OptChat), + Slot(InventorySlot), + Boolean(bool), + Rotation(f32, f32, f32), + Position(ValidBlockPosition), + OptPosition(Option), + Direction(Direction), + OptUuid(OptUuid), + OptBlockId(Option), + Nbt(nbt::Blob), + Particle, + VillagerData(i32, i32, i32), + OptVarInt(OptVarInt), + Pose(i32), +} + +impl MetaEntry { + pub fn id(&self) -> i32 { + match self { + MetaEntry::Byte(_) => 0, + MetaEntry::VarInt(_) => 1, + MetaEntry::Float(_) => 2, + MetaEntry::String(_) => 3, + MetaEntry::Chat(_) => 4, + MetaEntry::OptChat(_) => 5, + MetaEntry::Slot(_) => 6, + MetaEntry::Boolean(_) => 7, + MetaEntry::Rotation(_, _, _) => 8, + MetaEntry::Position(_) => 9, + MetaEntry::OptPosition(_) => 10, + MetaEntry::Direction(_) => 11, + MetaEntry::OptUuid(_) => 12, + MetaEntry::OptBlockId(_) => 13, + MetaEntry::Nbt(_) => 14, + MetaEntry::Particle => 15, + MetaEntry::VillagerData(_, _, _) => 16, + MetaEntry::OptVarInt(_) => 17, + MetaEntry::Pose(_) => 18, + } + } +} + +pub enum Pose { + Standing, + FallFlying, + Sleeping, + Swimming, + SpinAttack, + Sneaking, + Dying, +} + +impl ToMetaEntry for Pose { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::Pose(match self { + Self::Standing => 0, + Self::FallFlying => 1, + Self::Sleeping => 2, + Self::Swimming => 3, + Self::SpinAttack => 4, + Self::Sneaking => 5, + Self::Dying => 6, + }) + } +} + +pub trait ToMetaEntry { + fn to_meta_entry(&self) -> MetaEntry; +} + +impl ToMetaEntry for u8 { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::Byte(*self as i8) + } +} + +impl ToMetaEntry for i8 { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::Byte(*self) + } +} + +impl ToMetaEntry for i32 { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::VarInt(*self) + } +} + +impl ToMetaEntry for f32 { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::Float(*self) + } +} + +impl ToMetaEntry for OptChat { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::OptChat(self.clone()) + } +} + +impl ToMetaEntry for InventorySlot { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::Slot(self.clone()) + } +} + +impl ToMetaEntry for bool { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::Boolean(*self) + } +} + +impl ToMetaEntry for ValidBlockPosition { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::Position(*self) + } +} + +impl ToMetaEntry for OptUuid { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::OptUuid(*self) + } +} + +impl ToMetaEntry for OptVarInt { + fn to_meta_entry(&self) -> MetaEntry { + MetaEntry::OptVarInt(*self) + } +} + +#[derive(Clone, Debug)] +pub struct EntityMetadata { + pub values: BTreeMap, +} + +impl EntityMetadata { + pub fn new() -> Self { + Self { + values: BTreeMap::new(), + } + } + + /// Returns an entity metadata with the defaults for an `Entity`. + pub fn entity_base() -> Self { + Self::new() + .with(META_INDEX_ENTITY_BITMASK, EntityBitMask::empty().bits()) + .with(META_INDEX_AIR, 0i32) + .with(META_INDEX_CUSTOM_NAME, OptChat::None) + .with(META_INDEX_IS_CUSTOM_NAME_VISIBLE, false) + .with(META_INDEX_IS_SILENT, false) + .with(META_INDEX_NO_GRAVITY, false) + } + + pub fn with_many(mut self, values: &[(u8, MetaEntry)]) -> Self { + for val in values { + self.values.insert(val.0, val.1.clone()); + } + + self + } + + pub fn set(&mut self, index: u8, entry: impl ToMetaEntry) { + self.values.insert(index, entry.to_meta_entry()); + } + + pub fn with(mut self, index: u8, entry: impl ToMetaEntry) -> Self { + self.set(index, entry); + self + } + + pub fn get(&self, index: u8) -> Option { + self.values.get(&index).cloned() + } + + pub fn iter(&self) -> impl Iterator { + self.values.iter().map(|(key, entry)| (*key, entry)) + } +} + +impl Default for EntityMetadata { + fn default() -> Self { + Self::new() + } +} diff --git a/feather/blocks/Cargo.toml b/feather/blocks/Cargo.toml new file mode 100644 index 000000000..12a8835a9 --- /dev/null +++ b/feather/blocks/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "feather-blocks" +version = "0.1.0" +authors = [ "caelunshun " ] +edition = "2018" + +[dependencies] +anyhow = "1" +bincode = "1" +num-traits = "0.2" +once_cell = { version = "1" } +serde = { version = "1", features = [ "derive" ] } +thiserror = "1" +vek = "0.14" +libcraft-blocks = { path = "../../libcraft/blocks" } diff --git a/feather/blocks/generator/Cargo.toml b/feather/blocks/generator/Cargo.toml new file mode 100644 index 000000000..d92d6c62f --- /dev/null +++ b/feather/blocks/generator/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "feather-blocks-generator" +version = "0.1.0" +authors = ["caelunshun "] +edition = "2018" + +[lib] +name = "feather_blocks_generator" +path = "src/lib.rs" + +[[bin]] +name = "feather-blocks-generator" +path = "src/main.rs" + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" +anyhow = "1" +indexmap = { version = "1", features = ["serde-1"] } +quote = "1" +syn = "1" +proc-macro2 = "1" +heck = "0.3" +once_cell = "1" +maplit = "1" +bincode = "1" diff --git a/feather/blocks/generator/src/lib.rs b/feather/blocks/generator/src/lib.rs new file mode 100644 index 000000000..b5b8fbd84 --- /dev/null +++ b/feather/blocks/generator/src/lib.rs @@ -0,0 +1,752 @@ +use crate::load::ident; +use heck::CamelCase; +use heck::SnakeCase; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; +use quote::ToTokens; +use serde::ser::{SerializeSeq, SerializeStruct}; +use serde::{Serialize, Serializer}; +use std::collections::BTreeMap; +use std::ops::RangeInclusive; +use std::str::FromStr; + +mod load; + +#[derive(Debug)] +struct Blocks { + property_types: BTreeMap, + blocks: Vec, +} + +#[derive(Debug)] +pub struct Block { + /// Lowercase name of this block, minecraft: prefix removed. + name: Ident, + /// `name.to_camel_case()` + name_camel_case: Ident, + /// This block's properties. + properties: Vec, + /// Default state and its property values. + default_state: Vec<(String, String)>, + /// Block states mapped to vanilla state IDs. + ids: Vec<(Vec<(String, String)>, u16)>, + /// Strides and offset coefficients for each property of this block. + index_parameters: BTreeMap, +} + +#[derive(Debug)] +struct Property { + /// Name of this property, with Rust keywords removed. (e.g. "type" => "kind") + name: Ident, + /// Actual name of this property before Feather renaming is applied. + real_name: String, + /// CamelCase name of this property if it were a struct or enum. + /// + /// Often prefixed with the name of the block to which this property belongs. + _name_camel_case: Ident, + /// The kind of this property. + kind: PropertyKind, + /// Possible values of this property. + possible_values: Vec, +} + +impl Property { + /// Returns the tokens to create an instance of this property from a `u16`. + fn tokens_for_from_u16(&self, input: TokenStream) -> TokenStream { + match &self.kind { + PropertyKind::Integer { range } => { + let min = *range.start(); + quote! {{ #input as i32 + #min }} + } + PropertyKind::Boolean { .. } => quote! { if #input == 0 { false } else { true } }, + PropertyKind::Enum { name, .. } => { + quote! { #name::try_from(#input).expect("invalid block state") } + } + } + } + + fn tokens_for_to_u16(&self, input: TokenStream) -> TokenStream { + match &self.kind { + PropertyKind::Integer { range } => { + let min = *range.start() as u16; + quote! { + #input as u16 - #min + } + } + _ => quote! { #input as u16 }, + } + } + + fn tokens_for_as_str(&self, input: TokenStream) -> TokenStream { + match &self.kind { + PropertyKind::Integer { range } => { + let nums = range.clone().collect::>(); + let strs = range.clone().map(|x| x.to_string()).collect::>(); + + quote! { + match #input { + #( + #nums => #strs, + )* + _ => "unknown", + } + } + } + PropertyKind::Boolean => quote! { + match #input { + true => "true", + false => "false", + } + }, + PropertyKind::Enum { .. } => quote! { #input.as_str() }, + } + } + + fn tokens_for_from_str(&self, input: TokenStream) -> TokenStream { + match &self.kind { + PropertyKind::Integer { range } => { + let start = *range.start(); + let end = *range.end(); + quote! { + { + let x = i32::from_str(#input).ok()?; + if !(#start..=#end).contains(&x) { + return None; + } + x + } + } + } + PropertyKind::Boolean => quote! { + bool::from_str(#input).ok()? + }, + PropertyKind::Enum { name, .. } => quote! { #name::from_str(#input).ok()?}, + } + } + + /// Returns an expression for a value of this property. + fn expr_for_value(&self, value: &str) -> TokenStream { + match &self.kind { + PropertyKind::Integer { .. } => { + let value = i32::from_str(value).unwrap(); + quote! { #value } + } + PropertyKind::Boolean => { + let value = bool::from_str(value).unwrap(); + quote! { #value } + } + PropertyKind::Enum { name, .. } => { + let variant = ident(value.to_camel_case()); + quote! { #name::#variant } + } + } + } +} + +impl ToTokens for Property { + fn to_tokens(&self, tokens: &mut TokenStream) { + let x = match &self.kind { + PropertyKind::Integer { .. } => quote! { i32 }, + PropertyKind::Boolean => quote! { bool }, + PropertyKind::Enum { name, .. } => quote! { #name }, + }; + + tokens.extend(x); + } +} + +impl Property { + /// Returns the tokens necessary to define this property's type, + /// i.e. if it is an enum. + pub fn tokens_for_definition(&self) -> Option { + match &self.kind { + PropertyKind::Enum { name, variants } => Some({ + let definition = quote! { + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] + #[repr(u16)] + pub enum #name { + #( + #variants, + )* + } + }; + + let variant_indices: Vec<_> = (0..variants.len() as u16).collect(); + let try_from_error_msg = format!("invalid value {{}} for {}", name); + let as_str: Vec<_> = variants + .iter() + .map(|ident| ident.to_string()) + .map(|x| x.to_snake_case()) + .collect(); + + let imp = quote! { + impl TryFrom for #name { + type Error = anyhow::Error; + + fn try_from(value: u16) -> anyhow::Result { + match value { + #( + #variant_indices => Ok(#name::#variants), + )* + x => Err(anyhow::anyhow!(#try_from_error_msg, x)), + } + } + } + + impl FromStr for #name { + type Err = anyhow::Error; + + fn from_str(s: &str) -> anyhow::Result { + match s { + #( + #as_str => Ok(#name::#variants), + )* + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(#name))), + } + } + } + + impl #name { + pub fn as_str(self) -> &'static str { + match self { + #( + #name::#variants => #as_str, + )* + } + } + } + }; + + quote! { + #definition + #imp + } + }), + _ => None, + } + } +} + +#[derive(Debug)] +enum PropertyKind { + Integer { range: RangeInclusive }, + Boolean, + Enum { name: Ident, variants: Vec }, +} + +#[derive(Debug, Default)] +pub struct Output { + pub block_fns: String, + pub block_properties: String, + pub block_table: String, + pub block_table_serialized: Vec, + pub vanilla_ids_serialized: Vec, +} + +/// Generates code for the block report. +pub fn generate() -> anyhow::Result { + let blocks = load::load()?; + + let mut output = Output::default(); + + let table_src = generate_table(&blocks); + output.block_table.push_str(&table_src.to_string()); + let properties_src = generate_properties(&blocks); + output + .block_properties + .push_str(&properties_src.to_string()); + let block_fns_src = generate_block_fns(&blocks); + output.block_fns.push_str(&block_fns_src.to_string()); + + output.block_table_serialized = serialize_block_table(&blocks); + output.vanilla_ids_serialized = serialized_vanilla_ids(&blocks); + + Ok(output) +} + +/// Generates the `BlockTable` struct and its implementation. +fn generate_table(blocks: &Blocks) -> TokenStream { + let mut fields = vec![]; + let mut fns = vec![]; + let mut types = vec![]; + + for property in blocks.property_types.values() { + let name = &property.name; + + types.push(property.tokens_for_definition()); + + fields.push(quote! { + #name: Vec<(u16, u16)> + }); + + let from_u16 = property.tokens_for_from_u16(quote! { x }); + + let doc = format!( + "Retrieves the `{}` value for the given block kind with the given state value. + Returns the value of the property, or `None` if it does not exist.", + name + ); + fns.push(quote! { + #[doc = #doc] + pub fn #name(&self, kind: BlockKind, state: u16) -> Option<#property> { + let (offset_coefficient, stride) = self.#name[kind as u16 as usize]; + + if offset_coefficient == 0 { + return None; + } + + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(#from_u16) + } + }); + + let set = ident(format!("set_{}", name)); + let doc = format!("Updates the state value for the given block kind such that its `{}` value is updated. Returns the new state, + or `None` if the block does not have this property.", name); + let to_u16 = property.tokens_for_to_u16(quote! { value }); + fns.push(quote! { + #[doc = #doc] + pub fn #set(&self, kind: BlockKind, state: u16, value: #property) -> Option { + let (offset_coefficient, stride) = self.#name[kind as u16 as usize]; + + if offset_coefficient == 0 { + return None; + } + + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ #to_u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + }); + } + + quote! { + use crate::BlockKind; + use std::convert::TryFrom; + use std::str::FromStr; + use serde::Deserialize; + + #[derive(Debug, Deserialize)] + pub struct BlockTable { + #(#fields,)* + } + + impl BlockTable { + #(#fns)* + } + + #(#types)* + } +} + +/// Generated functions for `BlockId`. +fn generate_block_fns(blocks: &Blocks) -> TokenStream { + let mut fns = vec![]; + + for block in &blocks.blocks { + let name = &block.name; + let name_camel_case = &block.name_camel_case; + + let default_state = &block.default_state; + + let mut state_intializers = vec![]; + for (name, value) in default_state { + let value_expr = blocks.property_types[name].expr_for_value(value); + + let name_fn = ident(format!("set_{}", name)); + state_intializers.push(quote! { + block.#name_fn(#value_expr); + }); + } + + let mut doc = format!( + "Returns an instance of `{}` with default state values.", + block.name + ); + + if !default_state.is_empty() { + doc.push_str("\nThe default state values are as follows:\n"); + } + + for (name, value) in default_state { + doc.push_str(&format!("* `{}`: {}\n", name, value)); + } + + fns.push(quote! { + #[doc = #doc] + pub fn #name() -> Self { + let mut block = Self { + kind: BlockKind::#name_camel_case, + state: 0, + }; + #(#state_intializers)* + block + } + }) + } + + for property in blocks.property_types.values() { + let property_name = &property.name; + let set = ident(format!("set_{}", property_name)); + let with = ident(format!("with_{}", property_name)); + + let f = quote! { + pub fn #property_name(self) -> Option<#property> { + BLOCK_TABLE.#property_name(self.kind, self.state) + } + + pub fn #set(&mut self, #property_name: #property) -> bool { + match BLOCK_TABLE.#set(self.kind, self.state, #property_name) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + + pub fn #with(mut self, #property_name: #property) -> Self { + self.#set(#property_name); + self + } + }; + fns.push(f); + } + + fns.extend(generate_block_serializing_fns(blocks)); + + let res = quote! { + use std::collections::BTreeMap; + use std::str::FromStr; + use crate::*; + + impl BlockId { + #(#fns)* + } + }; + res +} + +/// Generates `BlockId::identifier()`, `BlockId::to_properties_map()`, and `BlockId::from_properties_and_identifier()`. +fn generate_block_serializing_fns(blocks: &Blocks) -> Vec { + let mut fns = vec![]; + + let mut identifier_fn_match_arms = vec![]; + for block in &blocks.blocks { + let name_camel_case = &block.name_camel_case; + + let name = format!("minecraft:{}", block.name); + + identifier_fn_match_arms.push(quote! { + BlockKind::#name_camel_case => #name + }); + } + + fns.push(quote! { + #[doc = "Returns the identifier of this block. For example, returns `minecraft::air` for an air block."] + pub fn identifier(self) -> &'static str { + match self.kind { + #(#identifier_fn_match_arms,)* + } + } + }); + + let mut to_properties_map_fn_match_arms = vec![]; + let mut to_properties_map_util_fns = vec![]; + for block in &blocks.blocks { + let name_camel_case = &block.name_camel_case; + let fn_to_call = ident(format!("{}_to_properties_map", block.name)); + + to_properties_map_fn_match_arms.push(quote! { + BlockKind::#name_camel_case => self.#fn_to_call() + }); + + let mut inserts = vec![]; + for property_name in &block.properties { + let property = &blocks.property_types[property_name]; + // Use the vanilla name of the property rather than our custom + // mapping, to ensure world saves are compatible with vanilla. + let property_real_name = &property.real_name; + + let name = &property.name; + let as_str = property.tokens_for_as_str(quote! { #name }); + + inserts.push(quote! { + let #name = self.#name().unwrap(); + map.insert(#property_real_name, { #as_str }); + }) + } + + to_properties_map_util_fns.push(quote! { + fn #fn_to_call(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + #(#inserts)* + map + } + }); + } + + fns.push(quote! { + #[doc = "Returns a mapping from property name to property value for this block. Used to serialize blocks in vanilla world saves."] + pub fn to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + match self.kind { + #(#to_properties_map_fn_match_arms,)* + } + } + + #(#to_properties_map_util_fns)* + }); + + let mut from_identifier_and_properties_fn_match_arms = vec![]; + let mut from_identifier_and_properties_util_fns = vec![]; + for block in &blocks.blocks { + let name = &block.name; + let name_str = format!("minecraft:{}", name); + let fn_to_call = ident(format!("{}_from_identifier_and_properties", block.name)); + + from_identifier_and_properties_fn_match_arms.push(quote! { + #name_str => Self::#fn_to_call(properties) + }); + + let mut retrievals = vec![]; + for property_name in &block.properties { + let property = &blocks.property_types[property_name]; + let property_real_name = &property.real_name; + + let name = &property.name; + let from_str = property.tokens_for_from_str(quote! { #name }); + let set_fn = ident(format!("set_{}", name)); + + retrievals.push(quote! { + let #name = map.get(#property_real_name)?; + let #name = #from_str; + block.#set_fn(#name); + }); + } + + from_identifier_and_properties_util_fns.push(quote! { + fn #fn_to_call(map: &BTreeMap) -> Option { + let mut block = BlockId::#name(); + #(#retrievals)* + Some(block) + } + }); + } + + fns.push(quote! { + #[doc = "Attempts to convert a block kind identifier (e.g. `minecraft::air`) and properties map to a `BlockId`."] + pub fn from_identifier_and_properties(identifier: &str, properties: &BTreeMap) -> Option { + match identifier { + #(#from_identifier_and_properties_fn_match_arms,)* + _ => None, + } + } + + #(#from_identifier_and_properties_util_fns)* + }); + + let mut from_identifier_and_default_props_match_arms = vec![]; + for block in &blocks.blocks { + let name_str = format!("minecraft:{}", block.name); + let name = &block.name; + + from_identifier_and_default_props_match_arms.push(quote! { + #name_str => Some(Self::#name()) + }); + } + fns.push(quote! { + #[doc = "Attempts to convert a block identifier to a block with default property values."] + pub fn from_identifier(identifier: &str) -> Option { + match identifier { + #(#from_identifier_and_default_props_match_arms,)* + _ => None, + } + } + }); + + fns +} + +/// Returns the serialized `BlockTable`. +fn serialize_block_table(blocks: &Blocks) -> Vec { + let table = BlockTableSerialize::new(&blocks.blocks, &blocks.property_types); + + bincode::serialize(&table).expect("bincode failed to serialize block table") +} + +/// Serializable form of the generated `BlockTable`. +#[derive(Debug)] +struct BlockTableSerialize { + fields: BTreeMap>, +} + +// custom serialize impl needed because of https://github.com/servo/bincode/issues/245 +impl Serialize for BlockTableSerialize { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + let mut state = serializer.serialize_struct("BlockTable", self.fields.len())?; + + for (name, value) in &self.fields { + // Leak memory! This is a build script; it doesn't matter. + let name = Box::leak(name.clone().into_boxed_str()); + state.serialize_field(name, value)?; + } + + state.end() + } +} + +impl BlockTableSerialize { + pub fn new(blocks: &[Block], property_types: &BTreeMap) -> Self { + let mut fields: BTreeMap> = BTreeMap::new(); + + for block in blocks { + for property_name in property_types.keys() { + let index_parameters = match block.index_parameters.get(property_name) { + Some(params) => *params, + None => (0, 0), + }; + + fields + .entry(property_name.clone()) + .or_default() + .push(index_parameters); + } + } + + assert!(fields.values().map(Vec::len).all(|len| len == blocks.len())); + + Self { fields } + } +} + +/// Returns the serialized state ID map. +fn serialized_vanilla_ids(blocks: &Blocks) -> Vec { + let table = VanillaStateIdSerialize::new(blocks); + + bincode::serialize(&table).expect("bincode failed to serialize vanilla ID table") +} + +/// Serializable state ID table. +#[derive(Debug)] +struct VanillaStateIdSerialize { + ids: Vec>, // indexed by [kind as u16 as usize][state as usize] +} + +impl Serialize for VanillaStateIdSerialize { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + let mut state = serializer.serialize_seq(Some(self.ids.len()))?; + + for id in &self.ids { + state.serialize_element(id)?; + } + + state.end() + } +} + +impl VanillaStateIdSerialize { + pub fn new(blocks: &Blocks) -> Self { + let mut ids: Vec> = std::iter::repeat_with(Vec::new) + .take(blocks.blocks.len()) + .collect(); + + for (i, block) in blocks.blocks.iter().enumerate() { + for (state, id) in &block.ids { + let mut internal_id = 0; + + for (property_name, property_value) in state { + let (offset_coefficient, stride) = block.index_parameters[property_name]; + + let index = blocks.property_types[property_name] + .possible_values + .iter() + .position(|val| val == property_value) + .unwrap(); + + let multiplier = internal_id / offset_coefficient; + let mut new = property_value_as_u16( + property_value, + index, + &blocks.property_types[property_name].kind, + ) * stride; + new += multiplier * offset_coefficient; + internal_id = new; + } + + let internal_id = internal_id as usize; + // pad with zeroes + if internal_id >= ids[i].len() { + let to_extend = internal_id - ids[i].len() + 1; + ids[i].extend(std::iter::repeat(0).take(to_extend)); + } + assert_eq!(ids[i][internal_id], 0, "failed for {}", block.name); + ids[i][internal_id] = *id; + } + } + + Self { ids } + } +} + +fn property_value_as_u16(value: &str, index: usize, kind: &PropertyKind) -> u16 { + let start = match kind { + PropertyKind::Integer { range } => *range.start() as u16, + _ => 0, + }; + + if let Ok(x) = i32::from_str(value) { + x as u16 - start + } else if let Ok(x) = bool::from_str(value) { + x as u16 + } else { + index as u16 + } +} + +fn generate_properties(blocks: &Blocks) -> TokenStream { + let mut fns = vec![]; + + for property in blocks.property_types.values() { + let name = &property.name; + + let doc = format!( + "Determines whether or not a block has the `{}` property.", + name + ); + + let kinds = blocks + .blocks + .iter() + .filter(|block| block.default_state.iter().any(|(prop, _)| name == prop)) + .map(|block| { + let name_camel_case = &block.name_camel_case; + + quote! { BlockKind::#name_camel_case } + }); + + let fn_name = ident(format!("has_{}", name)); + fns.push(quote! { + #[doc = #doc] + pub fn #fn_name(self) -> bool { + match self.kind() { + #(#kinds)|* => true, + _ => false + } + } + }); + } + + quote! { + use crate::{BlockId, BlockKind}; + + impl BlockId { + #(#fns)* + } + } +} diff --git a/feather/blocks/generator/src/load.rs b/feather/blocks/generator/src/load.rs new file mode 100644 index 000000000..10bd98909 --- /dev/null +++ b/feather/blocks/generator/src/load.rs @@ -0,0 +1,360 @@ +//! Loads the vanilla blocks.json report into a `BlocksReport`, then +//! converts this report into a `Blocks`. + +use crate::{Block, Blocks, Property, PropertyKind}; +use anyhow::Context; +use heck::CamelCase; +use indexmap::map::IndexMap; +use once_cell::sync::Lazy; +use proc_macro2::{Ident, Span}; +use serde::Deserialize; +use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::str::FromStr; + +/// Special property name overrides, to avoid names like "shape_neaaaassnn." +static NAME_OVERRIDES: Lazy> = Lazy::new(|| { + maplit::hashmap! { + "east_tf" => "east_connected", + "east_usn" => "east_wire", + "north_tf" => "north_connected", + "north_usn" => "north_wire", + "west_tf" => "west_connected", + "west_usn" => "west_wire", + "south_tf" => "south_connected", + "south_usn" => "south_wire", + "facing_dnswe" => "facing_cardinal_and_down", + "facing_neswud" => "facing_cubic", + "facing_nswe" => "facing_cardinal", + "half_ul" => "half_upper_lower", + "half_tb" => "half_top_bottom", + "kind_slr" => "chest_kind", + "kind_tbd" => "slab_kind", + "kind_ns" => "piston_kind", + "mode_cs" => "comparator_mode", + "mode_slcd" => "structure_block_mode", + "shape_neaaaa" => "powered_rail_shape", + "shape_siioo" => "stairs_shape", + "shape_neaaaassnn" => "rail_shape", + "level_0_3" => "cauldron_level", + "level_0_15" => "water_level", + "type_slr" => "chest_kind", + "type_tbd" => "slab_kind", + "type_ns" => "piston_kind", + } +}); + +#[derive(Debug, Deserialize)] +struct BlocksReport { + #[serde(flatten)] + blocks: IndexMap, +} + +#[derive(Debug, Deserialize)] +struct BlockDefinition { + states: Vec, + #[serde(default)] + properties: BTreeMap>, // map from property name => possible values +} + +#[derive(Debug, Deserialize)] +struct StateDefinition { + id: u16, + #[serde(default)] + default: bool, + #[serde(default)] + properties: BTreeMap, +} + +#[derive(Debug, Default, Clone)] +struct PropertyStore { + /// Mapping from property name to the set of different sets + /// of values known for this property. + properties: BTreeMap>>, +} + +impl PropertyStore { + fn register(&mut self, property: String, possible_values: impl IntoIterator) { + self.properties + .entry(property) + .or_default() + .insert(possible_values.into_iter().collect()); + } + + fn finish(self) -> BTreeMap { + let mut map = BTreeMap::new(); + + for (name, possible_value_sets) in self.properties { + let name = Self::update_name(&name); + + if possible_value_sets.len() == 1 { + let possible_values = possible_value_sets.into_iter().next().unwrap(); + map.insert( + name.to_owned(), + Self::prop_from_possible_values_and_name(name, name, possible_values), + ); + } else { + // There are multiple variants of this property, each with their own set of values. + // Create properties suffixed with an index to differentiate between these variants. + for possible_values in possible_value_sets { + // Name is the name of the property followed by the first letter of each possible value. + // If it's an integer, it is the range of possible values. + let new_name = if possible_values[0].parse::().is_ok() { + let as_integer = possible_values + .iter() + .map(String::as_str) + .map(i32::from_str) + .map(Result::unwrap) + .collect::>(); + + let min = *as_integer.iter().min().unwrap(); + let max = *as_integer.iter().max().unwrap(); + + format!("{}_{}_{}", name, min, max) + } else { + let mut name = format!("{}_", name); + for value in &possible_values { + name.push(value.chars().next().unwrap().to_ascii_lowercase()); + } + name + }; + + let new_name = Self::update_name(&new_name); + + map.insert( + new_name.to_owned(), + Self::prop_from_possible_values_and_name(new_name, name, possible_values), + ); + } + } + } + + map + } + + fn update_name(name: &str) -> &str { + match NAME_OVERRIDES.get(&name) { + Some(x) => *x, + None => name, + } + } + + fn prop_from_possible_values_and_name( + name: &str, + real_name: &str, + possible_values: Vec, + ) -> Property { + Property { + name: ident(name), + real_name: real_name.to_owned(), + _name_camel_case: ident(name.to_camel_case()), + kind: guess_property_kind(&possible_values, &name.to_camel_case()), + possible_values, + } + } +} + +/// Parses the vanilla blocks report, returning a `Blocks`. +pub(super) fn load() -> anyhow::Result { + let mut report = parse_report()?; + + let mut blocks = vec![]; + let properties = fix_property_names(&mut report); + + for (identifier, block) in &report.blocks { + if let Some(block) = load_block(identifier, block)? { + blocks.push(block); + } + } + + Ok(Blocks { + blocks, + property_types: properties.finish(), + }) +} + +fn fix_property_names(report: &mut BlocksReport) -> PropertyStore { + let mut store = PropertyStore::default(); + + for block in report.blocks.values() { + for (property_name, possible_values) in &block.properties { + store.register(property_name.to_owned(), possible_values.clone()); + } + } + + // Correct block property names + let result = store.clone().finish(); + + for block in report.blocks.values_mut() { + let block: &mut BlockDefinition = block; + let mut overrides = vec![]; + for (property_name, possible_values) in &mut block.properties { + if result.get(property_name).is_none() { + let name = if possible_values[0].parse::().is_ok() { + let as_integer = possible_values + .iter() + .map(String::as_str) + .map(i32::from_str) + .map(Result::unwrap) + .collect::>(); + + let min = *as_integer.iter().min().unwrap(); + let max = *as_integer.iter().max().unwrap(); + + format!("{}_{}_{}", property_name, min, max) + } else { + let mut name = format!("{}_", property_name); + for value in possible_values { + name.push(value.chars().next().unwrap().to_ascii_lowercase()); + } + name + }; + let name = if let Some(name) = NAME_OVERRIDES.get(&name.as_str()) { + (*name).to_owned() + } else { + name + }; + + overrides.push((property_name.to_owned(), name)); + } + } + + for (old_name, new_name) in overrides { + let old_values = block.properties.remove(&old_name).unwrap(); + block.properties.insert(new_name.clone(), old_values); + + for state in &mut block.states { + let old_value = state.properties.remove(&old_name).unwrap(); + state.properties.insert(new_name.clone(), old_value); + } + } + } + + store +} + +fn load_block(identifier: &str, block: &BlockDefinition) -> anyhow::Result> { + let identifier = strip_prefix(identifier)?; + + let name_camel_case = identifier.to_camel_case(); + + let properties = load_block_properties(block); + + let index_parameters = load_block_index_parameters(block, &properties); + + let ids = load_block_ids(block); + + let default_state = block + .states + .iter() + .find(|state| state.default) + .map(|state| state.properties.clone()) + .unwrap_or_default() + .into_iter() + .collect(); + + let block = Block { + name: ident(identifier), + name_camel_case: ident(name_camel_case), + properties, + ids, + default_state, + index_parameters, + }; + + Ok(Some(block)) +} + +fn load_block_properties(block: &BlockDefinition) -> Vec { + let mut props = vec![]; + + for identifier in block.properties.keys() { + props.push(identifier.to_owned()); + } + + props +} + +fn load_block_index_parameters( + block: &BlockDefinition, + block_props: &[String], +) -> BTreeMap { + let mut map = BTreeMap::new(); + + let possible_values = block_props + .iter() + .map(|block_prop| block.properties.get(block_prop).map(Vec::len).unwrap_or(0)) + .map(|x| x as u16) + .collect::>(); + + for (i, block_prop) in block_props.iter().enumerate() { + let stride = possible_values.iter().skip(i + 1).product::(); + let offset_coefficient = stride * possible_values[i]; + + map.insert(block_prop.clone(), (offset_coefficient, stride)); + } + + map +} + +fn load_block_ids(block: &BlockDefinition) -> Vec<(Vec<(String, String)>, u16)> { + let mut res: Vec<(Vec<(String, String)>, u16)> = vec![]; + + for state in &block.states { + let properties = state.properties.clone().into_iter().collect(); + + res.push((properties, state.id)); + } + + res +} + +fn guess_property_kind(possible_values: &[String], property_struct_name: &str) -> PropertyKind { + let first = &possible_values[0]; + + if i32::from_str(first).is_ok() { + // integer + let as_integer: Vec<_> = possible_values + .iter() + .map(|x| i32::from_str(x).unwrap()) + .collect(); + + let min = *as_integer.iter().min().unwrap(); + let max = *as_integer.iter().max().unwrap(); + + PropertyKind::Integer { range: min..=max } + } else if bool::from_str(first).is_ok() { + // boolean + PropertyKind::Boolean + } else { + // enum + let name = ident(property_struct_name); + let variants: Vec<_> = possible_values + .iter() + .map(|variant| variant.to_camel_case()) + .map(ident) + .collect(); + PropertyKind::Enum { name, variants } + } +} + +/// Strips the minecraft: prefix from a block identifier. +fn strip_prefix(x: &str) -> anyhow::Result<&str> { + const PREFIX: &str = "minecraft:"; + + if x.len() <= PREFIX.len() { + anyhow::bail!("missing minecraft: prefix for block {}", x); + } + + Ok(&x[PREFIX.len()..]) +} + +pub fn ident(x: impl AsRef) -> Ident { + Ident::new(x.as_ref(), Span::call_site()) // span doesn't matter as this is not a proc macro +} + +fn parse_report() -> anyhow::Result { + let report = std::fs::read_to_string("blocks.json") + .context("failed to load blocks report. Please run the vanilla data generator and copy blocks.json to the current directory")?; + + Ok(serde_json::from_str(&report)?) +} diff --git a/feather/blocks/generator/src/main.rs b/feather/blocks/generator/src/main.rs new file mode 100644 index 000000000..3f30d7e07 --- /dev/null +++ b/feather/blocks/generator/src/main.rs @@ -0,0 +1,49 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::process::Command; + +fn main() { + match feather_blocks_generator::generate() { + Ok(code) => { + let base = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/generated"); + + let _ = std::fs::create_dir_all(base); + + let block_fns = format!("{}/block_fns.rs", base); + let props = format!("{}/properties.rs", base); + let table = format!("{}/table.rs", base); + + write_to_file(&block_fns, &code.block_fns); + write_to_file(&props, &code.block_properties); + write_to_file(&table, &code.block_table); + + [block_fns, props, table].iter().for_each(|path| { + let _ = Command::new("rustfmt").arg(path).output(); + }); + + let data = format!("{}/table.dat", base); + File::create(&data) + .unwrap() + .write_all(&code.block_table_serialized) + .unwrap(); + + let data = format!("{}/vanilla_ids.dat", base); + File::create(&data) + .unwrap() + .write_all(&code.vanilla_ids_serialized) + .unwrap(); + } + Err(e) => { + eprintln!("An error occurred: {}", e); + std::process::exit(1); + } + } +} + +fn write_to_file(path: impl AsRef, s: impl AsRef) { + File::create(path.as_ref()) + .unwrap() + .write_all(s.as_ref().as_bytes()) + .unwrap(); +} diff --git a/feather/blocks/src/categories.rs b/feather/blocks/src/categories.rs new file mode 100644 index 000000000..16920fddf --- /dev/null +++ b/feather/blocks/src/categories.rs @@ -0,0 +1,214 @@ +use crate::{BlockId, BlockKind}; +use libcraft_blocks::SimplifiedBlockKind; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum PlacementType { + TargetedFace, + PlayerDirection, + PlayerDirectionRightAngle, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum SupportType { + OnSolid, + OnDesertBlocks, + OnDirtBlocks, + OnFarmland, + OnSoulSand, + OnWater, + + FacingSolid, + FacingJungleWood, + + OnOrFacingSolid, + + CactusLike, + ChorusFlowerLike, + ChorusPlantLike, + MushroomLike, + SnowLike, + SugarCaneLike, + TripwireHookLike, + VineLike, +} + +impl BlockId { + #[inline] + pub fn is_solid(self) -> bool { + self.kind().solid() + } + + #[inline] + pub fn is_opaque(self) -> bool { + !self.kind().transparent() + } + + #[inline] + pub fn is_air(self) -> bool { + self.simplified_kind() == SimplifiedBlockKind::Air + } + + #[inline] + pub fn is_fluid(self) -> bool { + matches!( + self.simplified_kind(), + SimplifiedBlockKind::Water | SimplifiedBlockKind::Lava + ) + } + + #[inline] + pub fn is_replaceable(self) -> bool { + matches!( + self.simplified_kind(), + SimplifiedBlockKind::Air + | SimplifiedBlockKind::Water + | SimplifiedBlockKind::Lava + | SimplifiedBlockKind::Grass + | SimplifiedBlockKind::TallGrass + | SimplifiedBlockKind::Snow + | SimplifiedBlockKind::Vine + | SimplifiedBlockKind::DeadBush + ) + } + + #[inline] + pub fn light_emission(self) -> u8 { + match self.kind() { + BlockKind::Beacon + | BlockKind::EndGateway + | BlockKind::EndPortal + | BlockKind::Fire + | BlockKind::Glowstone + | BlockKind::JackOLantern + | BlockKind::Lava + | BlockKind::SeaLantern + | BlockKind::Conduit => 15, + BlockKind::RedstoneLamp => { + if self.lit().unwrap() { + 15 + } else { + 0 + } + } + BlockKind::EndRod | BlockKind::Torch => 14, + BlockKind::Furnace => 13, + BlockKind::NetherPortal => 11, + BlockKind::EnderChest | BlockKind::RedstoneTorch => 7, + BlockKind::SeaPickle => 6, + BlockKind::MagmaBlock => 3, + BlockKind::BrewingStand + | BlockKind::BrownMushroom + | BlockKind::DragonEgg + | BlockKind::EndPortalFrame => 1, + _ => 0, + } + } + + #[inline] + pub fn can_fall(self) -> bool { + matches!( + self.simplified_kind(), + SimplifiedBlockKind::Sand + | SimplifiedBlockKind::Gravel + | SimplifiedBlockKind::RedSand + | SimplifiedBlockKind::Anvil + ) + } + + #[inline] + pub fn support_type(self) -> Option { + Some(match self.simplified_kind() { + SimplifiedBlockKind::Torch + | SimplifiedBlockKind::RedstoneTorch + | SimplifiedBlockKind::RedstoneWire + | SimplifiedBlockKind::Repeater + | SimplifiedBlockKind::Rail + | SimplifiedBlockKind::ActivatorRail + | SimplifiedBlockKind::DetectorRail + | SimplifiedBlockKind::PoweredRail + | SimplifiedBlockKind::Comparator + | SimplifiedBlockKind::Seagrass + | SimplifiedBlockKind::TallSeagrass + | SimplifiedBlockKind::Kelp + | SimplifiedBlockKind::KelpPlant + | SimplifiedBlockKind::Sign + | SimplifiedBlockKind::Coral + | SimplifiedBlockKind::CoralFan + | SimplifiedBlockKind::Banner + | SimplifiedBlockKind::Carpet + | SimplifiedBlockKind::WoodenDoor + | SimplifiedBlockKind::IronDoor + | SimplifiedBlockKind::StonePressurePlate + | SimplifiedBlockKind::WoodenPressurePlate + | SimplifiedBlockKind::HeavyWeightedPressurePlate + | SimplifiedBlockKind::LightWeightedPressurePlate => SupportType::OnSolid, + SimplifiedBlockKind::WallTorch + | SimplifiedBlockKind::RedstoneWallTorch + | SimplifiedBlockKind::Ladder + | SimplifiedBlockKind::WallSign + | SimplifiedBlockKind::CoralWallFan + | SimplifiedBlockKind::WallBanner => SupportType::FacingSolid, + SimplifiedBlockKind::Lever + | SimplifiedBlockKind::StoneButton + | SimplifiedBlockKind::WoodenButton => SupportType::OnOrFacingSolid, + SimplifiedBlockKind::TripwireHook => SupportType::TripwireHookLike, + SimplifiedBlockKind::AttachedMelonStem + | SimplifiedBlockKind::AttachedPumpkinStem + | SimplifiedBlockKind::MelonStem + | SimplifiedBlockKind::PumpkinStem + | SimplifiedBlockKind::Carrots + | SimplifiedBlockKind::Potatoes + | SimplifiedBlockKind::Beetroots + | SimplifiedBlockKind::Wheat => SupportType::OnFarmland, + SimplifiedBlockKind::Snow => SupportType::SnowLike, + SimplifiedBlockKind::LilyPad => SupportType::OnWater, + SimplifiedBlockKind::Cocoa => SupportType::FacingJungleWood, + SimplifiedBlockKind::Grass + | SimplifiedBlockKind::Fern + | SimplifiedBlockKind::Sunflower + | SimplifiedBlockKind::Lilac + | SimplifiedBlockKind::RoseBush + | SimplifiedBlockKind::Peony + | SimplifiedBlockKind::TallGrass + | SimplifiedBlockKind::LargeFern + | SimplifiedBlockKind::Sapling + | SimplifiedBlockKind::Flower => SupportType::OnDirtBlocks, + SimplifiedBlockKind::Mushroom => SupportType::MushroomLike, + SimplifiedBlockKind::DeadBush => SupportType::OnDesertBlocks, + SimplifiedBlockKind::SugarCane => SupportType::SugarCaneLike, + SimplifiedBlockKind::Vine => SupportType::VineLike, + SimplifiedBlockKind::Cactus => SupportType::CactusLike, + SimplifiedBlockKind::NetherWart => SupportType::OnSoulSand, + SimplifiedBlockKind::ChorusFlower => SupportType::ChorusFlowerLike, + SimplifiedBlockKind::ChorusPlant => SupportType::ChorusPlantLike, + _ => return None, + }) + } + + #[inline] + pub fn placement_type(self) -> Option { + match self.simplified_kind() { + SimplifiedBlockKind::WallTorch + | SimplifiedBlockKind::RedstoneWallTorch + | SimplifiedBlockKind::Lever + | SimplifiedBlockKind::EndRod + | SimplifiedBlockKind::StoneButton + | SimplifiedBlockKind::WoodenButton + | SimplifiedBlockKind::ShulkerBox => Some(PlacementType::TargetedFace), + SimplifiedBlockKind::Observer + | SimplifiedBlockKind::Bed + | SimplifiedBlockKind::Fence + | SimplifiedBlockKind::FenceGate + | SimplifiedBlockKind::IronDoor + | SimplifiedBlockKind::Stairs + | SimplifiedBlockKind::WoodenDoor => Some(PlacementType::PlayerDirection), + SimplifiedBlockKind::Anvil => Some(PlacementType::PlayerDirectionRightAngle), + _ => None, + } + } + + #[inline] + pub fn is_full_block(self) -> bool { + self.kind().solid() + } +} diff --git a/feather/blocks/src/directions.rs b/feather/blocks/src/directions.rs new file mode 100644 index 000000000..a4c9d164e --- /dev/null +++ b/feather/blocks/src/directions.rs @@ -0,0 +1,162 @@ +use crate::{AxisXyz, FacingCardinal, FacingCardinalAndDown, FacingCubic}; +use vek::Vec3; + +impl FacingCardinal { + pub fn opposite(self) -> FacingCardinal { + match self { + FacingCardinal::North => FacingCardinal::South, + FacingCardinal::East => FacingCardinal::West, + FacingCardinal::South => FacingCardinal::North, + FacingCardinal::West => FacingCardinal::East, + } + } + + pub fn right(self) -> FacingCardinal { + match self { + FacingCardinal::North => FacingCardinal::East, + FacingCardinal::East => FacingCardinal::South, + FacingCardinal::South => FacingCardinal::West, + FacingCardinal::West => FacingCardinal::North, + } + } + + pub fn left(self) -> FacingCardinal { + match self { + FacingCardinal::North => FacingCardinal::West, + FacingCardinal::East => FacingCardinal::North, + FacingCardinal::South => FacingCardinal::East, + FacingCardinal::West => FacingCardinal::South, + } + } + + pub fn is_horizontal(self) -> bool { + true + } + + pub fn to_facing_cardinal_and_down(self) -> FacingCardinalAndDown { + match self { + FacingCardinal::North => FacingCardinalAndDown::North, + FacingCardinal::East => FacingCardinalAndDown::East, + FacingCardinal::South => FacingCardinalAndDown::South, + FacingCardinal::West => FacingCardinalAndDown::West, + } + } + + pub fn to_facing_cubic(self) -> FacingCubic { + match self { + FacingCardinal::North => FacingCubic::North, + FacingCardinal::East => FacingCubic::East, + FacingCardinal::South => FacingCubic::South, + FacingCardinal::West => FacingCubic::West, + } + } + + pub fn axis(self) -> AxisXyz { + self.to_facing_cubic().axis() + } + + pub fn offset(self) -> Vec3 { + self.to_facing_cubic().offset() + } +} + +impl FacingCardinalAndDown { + pub fn opposite(self) -> Option { + match self { + FacingCardinalAndDown::North => Some(FacingCardinalAndDown::South), + FacingCardinalAndDown::East => Some(FacingCardinalAndDown::West), + FacingCardinalAndDown::South => Some(FacingCardinalAndDown::North), + FacingCardinalAndDown::West => Some(FacingCardinalAndDown::East), + _ => None, + } + } + + pub fn is_horizontal(self) -> bool { + self != FacingCardinalAndDown::Down + } + + pub fn to_facing_cardinal(self) -> Option { + match self { + FacingCardinalAndDown::North => Some(FacingCardinal::North), + FacingCardinalAndDown::East => Some(FacingCardinal::East), + FacingCardinalAndDown::South => Some(FacingCardinal::South), + FacingCardinalAndDown::West => Some(FacingCardinal::West), + _ => None, + } + } + + pub fn to_facing_cubic(self) -> FacingCubic { + match self { + FacingCardinalAndDown::North => FacingCubic::North, + FacingCardinalAndDown::East => FacingCubic::East, + FacingCardinalAndDown::South => FacingCubic::South, + FacingCardinalAndDown::West => FacingCubic::West, + FacingCardinalAndDown::Down => FacingCubic::Down, + } + } + + pub fn axis(self) -> AxisXyz { + self.to_facing_cubic().axis() + } + + pub fn offset(self) -> Vec3 { + self.to_facing_cubic().offset() + } +} + +impl FacingCubic { + pub fn opposite(self) -> FacingCubic { + match self { + FacingCubic::North => FacingCubic::South, + FacingCubic::East => FacingCubic::West, + FacingCubic::South => FacingCubic::North, + FacingCubic::West => FacingCubic::East, + FacingCubic::Up => FacingCubic::Down, + FacingCubic::Down => FacingCubic::Up, + } + } + + pub fn is_horizontal(self) -> bool { + !matches!(self, FacingCubic::Up | FacingCubic::Down) + } + + pub fn to_facing_cardinal(self) -> Option { + match self { + FacingCubic::North => Some(FacingCardinal::North), + FacingCubic::East => Some(FacingCardinal::East), + FacingCubic::South => Some(FacingCardinal::South), + FacingCubic::West => Some(FacingCardinal::West), + _ => None, + } + } + + pub fn to_facing_cardinal_and_down(self) -> Option { + match self { + FacingCubic::North => Some(FacingCardinalAndDown::North), + FacingCubic::East => Some(FacingCardinalAndDown::East), + FacingCubic::South => Some(FacingCardinalAndDown::South), + FacingCubic::West => Some(FacingCardinalAndDown::West), + FacingCubic::Down => Some(FacingCardinalAndDown::Down), + _ => None, + } + } + + pub fn axis(self) -> AxisXyz { + match self { + FacingCubic::East | FacingCubic::West => AxisXyz::X, + FacingCubic::Up | FacingCubic::Down => AxisXyz::Y, + FacingCubic::North | FacingCubic::South => AxisXyz::Z, + } + } + + pub fn offset(self) -> Vec3 { + match self { + FacingCubic::North => Vec3 { x: 0, y: 0, z: -1 }, + FacingCubic::East => Vec3 { x: 1, y: 0, z: 0 }, + FacingCubic::South => Vec3 { x: 0, y: 0, z: 1 }, + FacingCubic::West => Vec3 { x: -1, y: 0, z: 0 }, + FacingCubic::Up => Vec3 { x: 0, y: 1, z: 0 }, + FacingCubic::Down => Vec3 { x: 0, y: -1, z: 0 }, + } + } +} diff --git a/feather/blocks/src/generated/block_fns.rs b/feather/blocks/src/generated/block_fns.rs new file mode 100644 index 000000000..f3eaaa1ad --- /dev/null +++ b/feather/blocks/src/generated/block_fns.rs @@ -0,0 +1,29645 @@ +use crate::*; +use std::collections::BTreeMap; +use std::str::FromStr; +impl BlockId { + #[doc = "Returns an instance of `air` with default state values."] + pub fn air() -> Self { + let mut block = Self { + kind: BlockKind::Air, + state: 0, + }; + block + } + #[doc = "Returns an instance of `stone` with default state values."] + pub fn stone() -> Self { + let mut block = Self { + kind: BlockKind::Stone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `granite` with default state values."] + pub fn granite() -> Self { + let mut block = Self { + kind: BlockKind::Granite, + state: 0, + }; + block + } + #[doc = "Returns an instance of `polished_granite` with default state values."] + pub fn polished_granite() -> Self { + let mut block = Self { + kind: BlockKind::PolishedGranite, + state: 0, + }; + block + } + #[doc = "Returns an instance of `diorite` with default state values."] + pub fn diorite() -> Self { + let mut block = Self { + kind: BlockKind::Diorite, + state: 0, + }; + block + } + #[doc = "Returns an instance of `polished_diorite` with default state values."] + pub fn polished_diorite() -> Self { + let mut block = Self { + kind: BlockKind::PolishedDiorite, + state: 0, + }; + block + } + #[doc = "Returns an instance of `andesite` with default state values."] + pub fn andesite() -> Self { + let mut block = Self { + kind: BlockKind::Andesite, + state: 0, + }; + block + } + #[doc = "Returns an instance of `polished_andesite` with default state values."] + pub fn polished_andesite() -> Self { + let mut block = Self { + kind: BlockKind::PolishedAndesite, + state: 0, + }; + block + } + #[doc = "Returns an instance of `grass_block` with default state values.\nThe default state values are as follows:\n* `snowy`: false\n"] + pub fn grass_block() -> Self { + let mut block = Self { + kind: BlockKind::GrassBlock, + state: 0, + }; + block.set_snowy(false); + block + } + #[doc = "Returns an instance of `dirt` with default state values."] + pub fn dirt() -> Self { + let mut block = Self { + kind: BlockKind::Dirt, + state: 0, + }; + block + } + #[doc = "Returns an instance of `coarse_dirt` with default state values."] + pub fn coarse_dirt() -> Self { + let mut block = Self { + kind: BlockKind::CoarseDirt, + state: 0, + }; + block + } + #[doc = "Returns an instance of `podzol` with default state values.\nThe default state values are as follows:\n* `snowy`: false\n"] + pub fn podzol() -> Self { + let mut block = Self { + kind: BlockKind::Podzol, + state: 0, + }; + block.set_snowy(false); + block + } + #[doc = "Returns an instance of `cobblestone` with default state values."] + pub fn cobblestone() -> Self { + let mut block = Self { + kind: BlockKind::Cobblestone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `oak_planks` with default state values."] + pub fn oak_planks() -> Self { + let mut block = Self { + kind: BlockKind::OakPlanks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `spruce_planks` with default state values."] + pub fn spruce_planks() -> Self { + let mut block = Self { + kind: BlockKind::SprucePlanks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `birch_planks` with default state values."] + pub fn birch_planks() -> Self { + let mut block = Self { + kind: BlockKind::BirchPlanks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `jungle_planks` with default state values."] + pub fn jungle_planks() -> Self { + let mut block = Self { + kind: BlockKind::JunglePlanks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `acacia_planks` with default state values."] + pub fn acacia_planks() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaPlanks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dark_oak_planks` with default state values."] + pub fn dark_oak_planks() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakPlanks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `oak_sapling` with default state values.\nThe default state values are as follows:\n* `stage`: 0\n"] + pub fn oak_sapling() -> Self { + let mut block = Self { + kind: BlockKind::OakSapling, + state: 0, + }; + block.set_stage(0i32); + block + } + #[doc = "Returns an instance of `spruce_sapling` with default state values.\nThe default state values are as follows:\n* `stage`: 0\n"] + pub fn spruce_sapling() -> Self { + let mut block = Self { + kind: BlockKind::SpruceSapling, + state: 0, + }; + block.set_stage(0i32); + block + } + #[doc = "Returns an instance of `birch_sapling` with default state values.\nThe default state values are as follows:\n* `stage`: 0\n"] + pub fn birch_sapling() -> Self { + let mut block = Self { + kind: BlockKind::BirchSapling, + state: 0, + }; + block.set_stage(0i32); + block + } + #[doc = "Returns an instance of `jungle_sapling` with default state values.\nThe default state values are as follows:\n* `stage`: 0\n"] + pub fn jungle_sapling() -> Self { + let mut block = Self { + kind: BlockKind::JungleSapling, + state: 0, + }; + block.set_stage(0i32); + block + } + #[doc = "Returns an instance of `acacia_sapling` with default state values.\nThe default state values are as follows:\n* `stage`: 0\n"] + pub fn acacia_sapling() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaSapling, + state: 0, + }; + block.set_stage(0i32); + block + } + #[doc = "Returns an instance of `dark_oak_sapling` with default state values.\nThe default state values are as follows:\n* `stage`: 0\n"] + pub fn dark_oak_sapling() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakSapling, + state: 0, + }; + block.set_stage(0i32); + block + } + #[doc = "Returns an instance of `bedrock` with default state values."] + pub fn bedrock() -> Self { + let mut block = Self { + kind: BlockKind::Bedrock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `water` with default state values.\nThe default state values are as follows:\n* `water_level`: 0\n"] + pub fn water() -> Self { + let mut block = Self { + kind: BlockKind::Water, + state: 0, + }; + block.set_water_level(0i32); + block + } + #[doc = "Returns an instance of `lava` with default state values.\nThe default state values are as follows:\n* `water_level`: 0\n"] + pub fn lava() -> Self { + let mut block = Self { + kind: BlockKind::Lava, + state: 0, + }; + block.set_water_level(0i32); + block + } + #[doc = "Returns an instance of `sand` with default state values."] + pub fn sand() -> Self { + let mut block = Self { + kind: BlockKind::Sand, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_sand` with default state values."] + pub fn red_sand() -> Self { + let mut block = Self { + kind: BlockKind::RedSand, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gravel` with default state values."] + pub fn gravel() -> Self { + let mut block = Self { + kind: BlockKind::Gravel, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gold_ore` with default state values."] + pub fn gold_ore() -> Self { + let mut block = Self { + kind: BlockKind::GoldOre, + state: 0, + }; + block + } + #[doc = "Returns an instance of `iron_ore` with default state values."] + pub fn iron_ore() -> Self { + let mut block = Self { + kind: BlockKind::IronOre, + state: 0, + }; + block + } + #[doc = "Returns an instance of `coal_ore` with default state values."] + pub fn coal_ore() -> Self { + let mut block = Self { + kind: BlockKind::CoalOre, + state: 0, + }; + block + } + #[doc = "Returns an instance of `nether_gold_ore` with default state values."] + pub fn nether_gold_ore() -> Self { + let mut block = Self { + kind: BlockKind::NetherGoldOre, + state: 0, + }; + block + } + #[doc = "Returns an instance of `oak_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn oak_log() -> Self { + let mut block = Self { + kind: BlockKind::OakLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `spruce_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn spruce_log() -> Self { + let mut block = Self { + kind: BlockKind::SpruceLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `birch_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn birch_log() -> Self { + let mut block = Self { + kind: BlockKind::BirchLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `jungle_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn jungle_log() -> Self { + let mut block = Self { + kind: BlockKind::JungleLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `acacia_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn acacia_log() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `dark_oak_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn dark_oak_log() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_spruce_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_spruce_log() -> Self { + let mut block = Self { + kind: BlockKind::StrippedSpruceLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_birch_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_birch_log() -> Self { + let mut block = Self { + kind: BlockKind::StrippedBirchLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_jungle_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_jungle_log() -> Self { + let mut block = Self { + kind: BlockKind::StrippedJungleLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_acacia_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_acacia_log() -> Self { + let mut block = Self { + kind: BlockKind::StrippedAcaciaLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_dark_oak_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_dark_oak_log() -> Self { + let mut block = Self { + kind: BlockKind::StrippedDarkOakLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_oak_log` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_oak_log() -> Self { + let mut block = Self { + kind: BlockKind::StrippedOakLog, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `oak_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn oak_wood() -> Self { + let mut block = Self { + kind: BlockKind::OakWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `spruce_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn spruce_wood() -> Self { + let mut block = Self { + kind: BlockKind::SpruceWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `birch_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn birch_wood() -> Self { + let mut block = Self { + kind: BlockKind::BirchWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `jungle_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn jungle_wood() -> Self { + let mut block = Self { + kind: BlockKind::JungleWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `acacia_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn acacia_wood() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `dark_oak_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn dark_oak_wood() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_oak_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_oak_wood() -> Self { + let mut block = Self { + kind: BlockKind::StrippedOakWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_spruce_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_spruce_wood() -> Self { + let mut block = Self { + kind: BlockKind::StrippedSpruceWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_birch_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_birch_wood() -> Self { + let mut block = Self { + kind: BlockKind::StrippedBirchWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_jungle_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_jungle_wood() -> Self { + let mut block = Self { + kind: BlockKind::StrippedJungleWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_acacia_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_acacia_wood() -> Self { + let mut block = Self { + kind: BlockKind::StrippedAcaciaWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_dark_oak_wood` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_dark_oak_wood() -> Self { + let mut block = Self { + kind: BlockKind::StrippedDarkOakWood, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `oak_leaves` with default state values.\nThe default state values are as follows:\n* `distance_1_7`: 7\n* `persistent`: false\n"] + pub fn oak_leaves() -> Self { + let mut block = Self { + kind: BlockKind::OakLeaves, + state: 0, + }; + block.set_distance_1_7(7i32); + block.set_persistent(false); + block + } + #[doc = "Returns an instance of `spruce_leaves` with default state values.\nThe default state values are as follows:\n* `distance_1_7`: 7\n* `persistent`: false\n"] + pub fn spruce_leaves() -> Self { + let mut block = Self { + kind: BlockKind::SpruceLeaves, + state: 0, + }; + block.set_distance_1_7(7i32); + block.set_persistent(false); + block + } + #[doc = "Returns an instance of `birch_leaves` with default state values.\nThe default state values are as follows:\n* `distance_1_7`: 7\n* `persistent`: false\n"] + pub fn birch_leaves() -> Self { + let mut block = Self { + kind: BlockKind::BirchLeaves, + state: 0, + }; + block.set_distance_1_7(7i32); + block.set_persistent(false); + block + } + #[doc = "Returns an instance of `jungle_leaves` with default state values.\nThe default state values are as follows:\n* `distance_1_7`: 7\n* `persistent`: false\n"] + pub fn jungle_leaves() -> Self { + let mut block = Self { + kind: BlockKind::JungleLeaves, + state: 0, + }; + block.set_distance_1_7(7i32); + block.set_persistent(false); + block + } + #[doc = "Returns an instance of `acacia_leaves` with default state values.\nThe default state values are as follows:\n* `distance_1_7`: 7\n* `persistent`: false\n"] + pub fn acacia_leaves() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaLeaves, + state: 0, + }; + block.set_distance_1_7(7i32); + block.set_persistent(false); + block + } + #[doc = "Returns an instance of `dark_oak_leaves` with default state values.\nThe default state values are as follows:\n* `distance_1_7`: 7\n* `persistent`: false\n"] + pub fn dark_oak_leaves() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakLeaves, + state: 0, + }; + block.set_distance_1_7(7i32); + block.set_persistent(false); + block + } + #[doc = "Returns an instance of `sponge` with default state values."] + pub fn sponge() -> Self { + let mut block = Self { + kind: BlockKind::Sponge, + state: 0, + }; + block + } + #[doc = "Returns an instance of `wet_sponge` with default state values."] + pub fn wet_sponge() -> Self { + let mut block = Self { + kind: BlockKind::WetSponge, + state: 0, + }; + block + } + #[doc = "Returns an instance of `glass` with default state values."] + pub fn glass() -> Self { + let mut block = Self { + kind: BlockKind::Glass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lapis_ore` with default state values."] + pub fn lapis_ore() -> Self { + let mut block = Self { + kind: BlockKind::LapisOre, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lapis_block` with default state values."] + pub fn lapis_block() -> Self { + let mut block = Self { + kind: BlockKind::LapisBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dispenser` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: north\n* `triggered`: false\n"] + pub fn dispenser() -> Self { + let mut block = Self { + kind: BlockKind::Dispenser, + state: 0, + }; + block.set_facing_cubic(FacingCubic::North); + block.set_triggered(false); + block + } + #[doc = "Returns an instance of `sandstone` with default state values."] + pub fn sandstone() -> Self { + let mut block = Self { + kind: BlockKind::Sandstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `chiseled_sandstone` with default state values."] + pub fn chiseled_sandstone() -> Self { + let mut block = Self { + kind: BlockKind::ChiseledSandstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cut_sandstone` with default state values."] + pub fn cut_sandstone() -> Self { + let mut block = Self { + kind: BlockKind::CutSandstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `note_block` with default state values.\nThe default state values are as follows:\n* `instrument`: harp\n* `note`: 0\n* `powered`: false\n"] + pub fn note_block() -> Self { + let mut block = Self { + kind: BlockKind::NoteBlock, + state: 0, + }; + block.set_instrument(Instrument::Harp); + block.set_note(0i32); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `white_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn white_bed() -> Self { + let mut block = Self { + kind: BlockKind::WhiteBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `orange_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn orange_bed() -> Self { + let mut block = Self { + kind: BlockKind::OrangeBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `magenta_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn magenta_bed() -> Self { + let mut block = Self { + kind: BlockKind::MagentaBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `light_blue_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn light_blue_bed() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `yellow_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn yellow_bed() -> Self { + let mut block = Self { + kind: BlockKind::YellowBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `lime_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn lime_bed() -> Self { + let mut block = Self { + kind: BlockKind::LimeBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `pink_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn pink_bed() -> Self { + let mut block = Self { + kind: BlockKind::PinkBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `gray_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn gray_bed() -> Self { + let mut block = Self { + kind: BlockKind::GrayBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `light_gray_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn light_gray_bed() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `cyan_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn cyan_bed() -> Self { + let mut block = Self { + kind: BlockKind::CyanBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `purple_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn purple_bed() -> Self { + let mut block = Self { + kind: BlockKind::PurpleBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `blue_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn blue_bed() -> Self { + let mut block = Self { + kind: BlockKind::BlueBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `brown_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn brown_bed() -> Self { + let mut block = Self { + kind: BlockKind::BrownBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `green_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn green_bed() -> Self { + let mut block = Self { + kind: BlockKind::GreenBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `red_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn red_bed() -> Self { + let mut block = Self { + kind: BlockKind::RedBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `black_bed` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `occupied`: false\n* `part`: foot\n"] + pub fn black_bed() -> Self { + let mut block = Self { + kind: BlockKind::BlackBed, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_occupied(false); + block.set_part(Part::Foot); + block + } + #[doc = "Returns an instance of `powered_rail` with default state values.\nThe default state values are as follows:\n* `powered`: false\n* `powered_rail_shape`: north_south\n"] + pub fn powered_rail() -> Self { + let mut block = Self { + kind: BlockKind::PoweredRail, + state: 0, + }; + block.set_powered(false); + block.set_powered_rail_shape(PoweredRailShape::NorthSouth); + block + } + #[doc = "Returns an instance of `detector_rail` with default state values.\nThe default state values are as follows:\n* `powered`: false\n* `powered_rail_shape`: north_south\n"] + pub fn detector_rail() -> Self { + let mut block = Self { + kind: BlockKind::DetectorRail, + state: 0, + }; + block.set_powered(false); + block.set_powered_rail_shape(PoweredRailShape::NorthSouth); + block + } + #[doc = "Returns an instance of `sticky_piston` with default state values.\nThe default state values are as follows:\n* `extended`: false\n* `facing_cubic`: north\n"] + pub fn sticky_piston() -> Self { + let mut block = Self { + kind: BlockKind::StickyPiston, + state: 0, + }; + block.set_extended(false); + block.set_facing_cubic(FacingCubic::North); + block + } + #[doc = "Returns an instance of `cobweb` with default state values."] + pub fn cobweb() -> Self { + let mut block = Self { + kind: BlockKind::Cobweb, + state: 0, + }; + block + } + #[doc = "Returns an instance of `grass` with default state values."] + pub fn grass() -> Self { + let mut block = Self { + kind: BlockKind::Grass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `fern` with default state values."] + pub fn fern() -> Self { + let mut block = Self { + kind: BlockKind::Fern, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dead_bush` with default state values."] + pub fn dead_bush() -> Self { + let mut block = Self { + kind: BlockKind::DeadBush, + state: 0, + }; + block + } + #[doc = "Returns an instance of `seagrass` with default state values."] + pub fn seagrass() -> Self { + let mut block = Self { + kind: BlockKind::Seagrass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `tall_seagrass` with default state values.\nThe default state values are as follows:\n* `half_upper_lower`: lower\n"] + pub fn tall_seagrass() -> Self { + let mut block = Self { + kind: BlockKind::TallSeagrass, + state: 0, + }; + block.set_half_upper_lower(HalfUpperLower::Lower); + block + } + #[doc = "Returns an instance of `piston` with default state values.\nThe default state values are as follows:\n* `extended`: false\n* `facing_cubic`: north\n"] + pub fn piston() -> Self { + let mut block = Self { + kind: BlockKind::Piston, + state: 0, + }; + block.set_extended(false); + block.set_facing_cubic(FacingCubic::North); + block + } + #[doc = "Returns an instance of `piston_head` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: north\n* `piston_kind`: normal\n* `short`: false\n"] + pub fn piston_head() -> Self { + let mut block = Self { + kind: BlockKind::PistonHead, + state: 0, + }; + block.set_facing_cubic(FacingCubic::North); + block.set_piston_kind(PistonKind::Normal); + block.set_short(false); + block + } + #[doc = "Returns an instance of `white_wool` with default state values."] + pub fn white_wool() -> Self { + let mut block = Self { + kind: BlockKind::WhiteWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `orange_wool` with default state values."] + pub fn orange_wool() -> Self { + let mut block = Self { + kind: BlockKind::OrangeWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `magenta_wool` with default state values."] + pub fn magenta_wool() -> Self { + let mut block = Self { + kind: BlockKind::MagentaWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_blue_wool` with default state values."] + pub fn light_blue_wool() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `yellow_wool` with default state values."] + pub fn yellow_wool() -> Self { + let mut block = Self { + kind: BlockKind::YellowWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lime_wool` with default state values."] + pub fn lime_wool() -> Self { + let mut block = Self { + kind: BlockKind::LimeWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `pink_wool` with default state values."] + pub fn pink_wool() -> Self { + let mut block = Self { + kind: BlockKind::PinkWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gray_wool` with default state values."] + pub fn gray_wool() -> Self { + let mut block = Self { + kind: BlockKind::GrayWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_gray_wool` with default state values."] + pub fn light_gray_wool() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cyan_wool` with default state values."] + pub fn cyan_wool() -> Self { + let mut block = Self { + kind: BlockKind::CyanWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `purple_wool` with default state values."] + pub fn purple_wool() -> Self { + let mut block = Self { + kind: BlockKind::PurpleWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blue_wool` with default state values."] + pub fn blue_wool() -> Self { + let mut block = Self { + kind: BlockKind::BlueWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brown_wool` with default state values."] + pub fn brown_wool() -> Self { + let mut block = Self { + kind: BlockKind::BrownWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `green_wool` with default state values."] + pub fn green_wool() -> Self { + let mut block = Self { + kind: BlockKind::GreenWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_wool` with default state values."] + pub fn red_wool() -> Self { + let mut block = Self { + kind: BlockKind::RedWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `black_wool` with default state values."] + pub fn black_wool() -> Self { + let mut block = Self { + kind: BlockKind::BlackWool, + state: 0, + }; + block + } + #[doc = "Returns an instance of `moving_piston` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: north\n* `piston_kind`: normal\n"] + pub fn moving_piston() -> Self { + let mut block = Self { + kind: BlockKind::MovingPiston, + state: 0, + }; + block.set_facing_cubic(FacingCubic::North); + block.set_piston_kind(PistonKind::Normal); + block + } + #[doc = "Returns an instance of `dandelion` with default state values."] + pub fn dandelion() -> Self { + let mut block = Self { + kind: BlockKind::Dandelion, + state: 0, + }; + block + } + #[doc = "Returns an instance of `poppy` with default state values."] + pub fn poppy() -> Self { + let mut block = Self { + kind: BlockKind::Poppy, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blue_orchid` with default state values."] + pub fn blue_orchid() -> Self { + let mut block = Self { + kind: BlockKind::BlueOrchid, + state: 0, + }; + block + } + #[doc = "Returns an instance of `allium` with default state values."] + pub fn allium() -> Self { + let mut block = Self { + kind: BlockKind::Allium, + state: 0, + }; + block + } + #[doc = "Returns an instance of `azure_bluet` with default state values."] + pub fn azure_bluet() -> Self { + let mut block = Self { + kind: BlockKind::AzureBluet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_tulip` with default state values."] + pub fn red_tulip() -> Self { + let mut block = Self { + kind: BlockKind::RedTulip, + state: 0, + }; + block + } + #[doc = "Returns an instance of `orange_tulip` with default state values."] + pub fn orange_tulip() -> Self { + let mut block = Self { + kind: BlockKind::OrangeTulip, + state: 0, + }; + block + } + #[doc = "Returns an instance of `white_tulip` with default state values."] + pub fn white_tulip() -> Self { + let mut block = Self { + kind: BlockKind::WhiteTulip, + state: 0, + }; + block + } + #[doc = "Returns an instance of `pink_tulip` with default state values."] + pub fn pink_tulip() -> Self { + let mut block = Self { + kind: BlockKind::PinkTulip, + state: 0, + }; + block + } + #[doc = "Returns an instance of `oxeye_daisy` with default state values."] + pub fn oxeye_daisy() -> Self { + let mut block = Self { + kind: BlockKind::OxeyeDaisy, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cornflower` with default state values."] + pub fn cornflower() -> Self { + let mut block = Self { + kind: BlockKind::Cornflower, + state: 0, + }; + block + } + #[doc = "Returns an instance of `wither_rose` with default state values."] + pub fn wither_rose() -> Self { + let mut block = Self { + kind: BlockKind::WitherRose, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lily_of_the_valley` with default state values."] + pub fn lily_of_the_valley() -> Self { + let mut block = Self { + kind: BlockKind::LilyOfTheValley, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brown_mushroom` with default state values."] + pub fn brown_mushroom() -> Self { + let mut block = Self { + kind: BlockKind::BrownMushroom, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_mushroom` with default state values."] + pub fn red_mushroom() -> Self { + let mut block = Self { + kind: BlockKind::RedMushroom, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gold_block` with default state values."] + pub fn gold_block() -> Self { + let mut block = Self { + kind: BlockKind::GoldBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `iron_block` with default state values."] + pub fn iron_block() -> Self { + let mut block = Self { + kind: BlockKind::IronBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `bricks` with default state values."] + pub fn bricks() -> Self { + let mut block = Self { + kind: BlockKind::Bricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `tnt` with default state values.\nThe default state values are as follows:\n* `unstable`: false\n"] + pub fn tnt() -> Self { + let mut block = Self { + kind: BlockKind::Tnt, + state: 0, + }; + block.set_unstable(false); + block + } + #[doc = "Returns an instance of `bookshelf` with default state values."] + pub fn bookshelf() -> Self { + let mut block = Self { + kind: BlockKind::Bookshelf, + state: 0, + }; + block + } + #[doc = "Returns an instance of `mossy_cobblestone` with default state values."] + pub fn mossy_cobblestone() -> Self { + let mut block = Self { + kind: BlockKind::MossyCobblestone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `obsidian` with default state values."] + pub fn obsidian() -> Self { + let mut block = Self { + kind: BlockKind::Obsidian, + state: 0, + }; + block + } + #[doc = "Returns an instance of `torch` with default state values."] + pub fn torch() -> Self { + let mut block = Self { + kind: BlockKind::Torch, + state: 0, + }; + block + } + #[doc = "Returns an instance of `wall_torch` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn wall_torch() -> Self { + let mut block = Self { + kind: BlockKind::WallTorch, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `fire` with default state values.\nThe default state values are as follows:\n* `age_0_15`: 0\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `up`: false\n* `west_connected`: false\n"] + pub fn fire() -> Self { + let mut block = Self { + kind: BlockKind::Fire, + state: 0, + }; + block.set_age_0_15(0i32); + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_up(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `soul_fire` with default state values."] + pub fn soul_fire() -> Self { + let mut block = Self { + kind: BlockKind::SoulFire, + state: 0, + }; + block + } + #[doc = "Returns an instance of `spawner` with default state values."] + pub fn spawner() -> Self { + let mut block = Self { + kind: BlockKind::Spawner, + state: 0, + }; + block + } + #[doc = "Returns an instance of `oak_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn oak_stairs() -> Self { + let mut block = Self { + kind: BlockKind::OakStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `chest` with default state values.\nThe default state values are as follows:\n* `chest_kind`: single\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn chest() -> Self { + let mut block = Self { + kind: BlockKind::Chest, + state: 0, + }; + block.set_chest_kind(ChestKind::Single); + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `redstone_wire` with default state values.\nThe default state values are as follows:\n* `east_wire`: none\n* `north_wire`: none\n* `power`: 0\n* `south_wire`: none\n* `west_wire`: none\n"] + pub fn redstone_wire() -> Self { + let mut block = Self { + kind: BlockKind::RedstoneWire, + state: 0, + }; + block.set_east_wire(EastWire::None); + block.set_north_wire(NorthWire::None); + block.set_power(0i32); + block.set_south_wire(SouthWire::None); + block.set_west_wire(WestWire::None); + block + } + #[doc = "Returns an instance of `diamond_ore` with default state values."] + pub fn diamond_ore() -> Self { + let mut block = Self { + kind: BlockKind::DiamondOre, + state: 0, + }; + block + } + #[doc = "Returns an instance of `diamond_block` with default state values."] + pub fn diamond_block() -> Self { + let mut block = Self { + kind: BlockKind::DiamondBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `crafting_table` with default state values."] + pub fn crafting_table() -> Self { + let mut block = Self { + kind: BlockKind::CraftingTable, + state: 0, + }; + block + } + #[doc = "Returns an instance of `wheat` with default state values.\nThe default state values are as follows:\n* `age_0_7`: 0\n"] + pub fn wheat() -> Self { + let mut block = Self { + kind: BlockKind::Wheat, + state: 0, + }; + block.set_age_0_7(0i32); + block + } + #[doc = "Returns an instance of `farmland` with default state values.\nThe default state values are as follows:\n* `moisture`: 0\n"] + pub fn farmland() -> Self { + let mut block = Self { + kind: BlockKind::Farmland, + state: 0, + }; + block.set_moisture(0i32); + block + } + #[doc = "Returns an instance of `furnace` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `lit`: false\n"] + pub fn furnace() -> Self { + let mut block = Self { + kind: BlockKind::Furnace, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_lit(false); + block + } + #[doc = "Returns an instance of `oak_sign` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n* `waterlogged`: false\n"] + pub fn oak_sign() -> Self { + let mut block = Self { + kind: BlockKind::OakSign, + state: 0, + }; + block.set_rotation(0i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `spruce_sign` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n* `waterlogged`: false\n"] + pub fn spruce_sign() -> Self { + let mut block = Self { + kind: BlockKind::SpruceSign, + state: 0, + }; + block.set_rotation(0i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `birch_sign` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n* `waterlogged`: false\n"] + pub fn birch_sign() -> Self { + let mut block = Self { + kind: BlockKind::BirchSign, + state: 0, + }; + block.set_rotation(0i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `acacia_sign` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n* `waterlogged`: false\n"] + pub fn acacia_sign() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaSign, + state: 0, + }; + block.set_rotation(0i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `jungle_sign` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n* `waterlogged`: false\n"] + pub fn jungle_sign() -> Self { + let mut block = Self { + kind: BlockKind::JungleSign, + state: 0, + }; + block.set_rotation(0i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `dark_oak_sign` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n* `waterlogged`: false\n"] + pub fn dark_oak_sign() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakSign, + state: 0, + }; + block.set_rotation(0i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `oak_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn oak_door() -> Self { + let mut block = Self { + kind: BlockKind::OakDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `ladder` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn ladder() -> Self { + let mut block = Self { + kind: BlockKind::Ladder, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `rail` with default state values.\nThe default state values are as follows:\n* `rail_shape`: north_south\n"] + pub fn rail() -> Self { + let mut block = Self { + kind: BlockKind::Rail, + state: 0, + }; + block.set_rail_shape(RailShape::NorthSouth); + block + } + #[doc = "Returns an instance of `cobblestone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn cobblestone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::CobblestoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `oak_wall_sign` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn oak_wall_sign() -> Self { + let mut block = Self { + kind: BlockKind::OakWallSign, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `spruce_wall_sign` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn spruce_wall_sign() -> Self { + let mut block = Self { + kind: BlockKind::SpruceWallSign, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `birch_wall_sign` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn birch_wall_sign() -> Self { + let mut block = Self { + kind: BlockKind::BirchWallSign, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `acacia_wall_sign` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn acacia_wall_sign() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaWallSign, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `jungle_wall_sign` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn jungle_wall_sign() -> Self { + let mut block = Self { + kind: BlockKind::JungleWallSign, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `dark_oak_wall_sign` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn dark_oak_wall_sign() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakWallSign, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `lever` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn lever() -> Self { + let mut block = Self { + kind: BlockKind::Lever, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `stone_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn stone_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::StonePressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `iron_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn iron_door() -> Self { + let mut block = Self { + kind: BlockKind::IronDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `oak_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn oak_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::OakPressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `spruce_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn spruce_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::SprucePressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `birch_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn birch_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::BirchPressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `jungle_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn jungle_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::JunglePressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `acacia_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn acacia_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaPressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `dark_oak_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn dark_oak_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakPressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `redstone_ore` with default state values.\nThe default state values are as follows:\n* `lit`: false\n"] + pub fn redstone_ore() -> Self { + let mut block = Self { + kind: BlockKind::RedstoneOre, + state: 0, + }; + block.set_lit(false); + block + } + #[doc = "Returns an instance of `redstone_torch` with default state values.\nThe default state values are as follows:\n* `lit`: true\n"] + pub fn redstone_torch() -> Self { + let mut block = Self { + kind: BlockKind::RedstoneTorch, + state: 0, + }; + block.set_lit(true); + block + } + #[doc = "Returns an instance of `redstone_wall_torch` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `lit`: true\n"] + pub fn redstone_wall_torch() -> Self { + let mut block = Self { + kind: BlockKind::RedstoneWallTorch, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_lit(true); + block + } + #[doc = "Returns an instance of `stone_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn stone_button() -> Self { + let mut block = Self { + kind: BlockKind::StoneButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `snow` with default state values.\nThe default state values are as follows:\n* `layers`: 1\n"] + pub fn snow() -> Self { + let mut block = Self { + kind: BlockKind::Snow, + state: 0, + }; + block.set_layers(1i32); + block + } + #[doc = "Returns an instance of `ice` with default state values."] + pub fn ice() -> Self { + let mut block = Self { + kind: BlockKind::Ice, + state: 0, + }; + block + } + #[doc = "Returns an instance of `snow_block` with default state values."] + pub fn snow_block() -> Self { + let mut block = Self { + kind: BlockKind::SnowBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cactus` with default state values.\nThe default state values are as follows:\n* `age_0_15`: 0\n"] + pub fn cactus() -> Self { + let mut block = Self { + kind: BlockKind::Cactus, + state: 0, + }; + block.set_age_0_15(0i32); + block + } + #[doc = "Returns an instance of `clay` with default state values."] + pub fn clay() -> Self { + let mut block = Self { + kind: BlockKind::Clay, + state: 0, + }; + block + } + #[doc = "Returns an instance of `sugar_cane` with default state values.\nThe default state values are as follows:\n* `age_0_15`: 0\n"] + pub fn sugar_cane() -> Self { + let mut block = Self { + kind: BlockKind::SugarCane, + state: 0, + }; + block.set_age_0_15(0i32); + block + } + #[doc = "Returns an instance of `jukebox` with default state values.\nThe default state values are as follows:\n* `has_record`: false\n"] + pub fn jukebox() -> Self { + let mut block = Self { + kind: BlockKind::Jukebox, + state: 0, + }; + block.set_has_record(false); + block + } + #[doc = "Returns an instance of `oak_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn oak_fence() -> Self { + let mut block = Self { + kind: BlockKind::OakFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `pumpkin` with default state values."] + pub fn pumpkin() -> Self { + let mut block = Self { + kind: BlockKind::Pumpkin, + state: 0, + }; + block + } + #[doc = "Returns an instance of `netherrack` with default state values."] + pub fn netherrack() -> Self { + let mut block = Self { + kind: BlockKind::Netherrack, + state: 0, + }; + block + } + #[doc = "Returns an instance of `soul_sand` with default state values."] + pub fn soul_sand() -> Self { + let mut block = Self { + kind: BlockKind::SoulSand, + state: 0, + }; + block + } + #[doc = "Returns an instance of `soul_soil` with default state values."] + pub fn soul_soil() -> Self { + let mut block = Self { + kind: BlockKind::SoulSoil, + state: 0, + }; + block + } + #[doc = "Returns an instance of `basalt` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn basalt() -> Self { + let mut block = Self { + kind: BlockKind::Basalt, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `polished_basalt` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn polished_basalt() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBasalt, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `soul_torch` with default state values."] + pub fn soul_torch() -> Self { + let mut block = Self { + kind: BlockKind::SoulTorch, + state: 0, + }; + block + } + #[doc = "Returns an instance of `soul_wall_torch` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn soul_wall_torch() -> Self { + let mut block = Self { + kind: BlockKind::SoulWallTorch, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `glowstone` with default state values."] + pub fn glowstone() -> Self { + let mut block = Self { + kind: BlockKind::Glowstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `nether_portal` with default state values.\nThe default state values are as follows:\n* `axis_xz`: x\n"] + pub fn nether_portal() -> Self { + let mut block = Self { + kind: BlockKind::NetherPortal, + state: 0, + }; + block.set_axis_xz(AxisXz::X); + block + } + #[doc = "Returns an instance of `carved_pumpkin` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn carved_pumpkin() -> Self { + let mut block = Self { + kind: BlockKind::CarvedPumpkin, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `jack_o_lantern` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn jack_o_lantern() -> Self { + let mut block = Self { + kind: BlockKind::JackOLantern, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `cake` with default state values.\nThe default state values are as follows:\n* `bites`: 0\n"] + pub fn cake() -> Self { + let mut block = Self { + kind: BlockKind::Cake, + state: 0, + }; + block.set_bites(0i32); + block + } + #[doc = "Returns an instance of `repeater` with default state values.\nThe default state values are as follows:\n* `delay`: 1\n* `facing_cardinal`: north\n* `locked`: false\n* `powered`: false\n"] + pub fn repeater() -> Self { + let mut block = Self { + kind: BlockKind::Repeater, + state: 0, + }; + block.set_delay(1i32); + block.set_facing_cardinal(FacingCardinal::North); + block.set_locked(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `white_stained_glass` with default state values."] + pub fn white_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::WhiteStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `orange_stained_glass` with default state values."] + pub fn orange_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::OrangeStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `magenta_stained_glass` with default state values."] + pub fn magenta_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::MagentaStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_blue_stained_glass` with default state values."] + pub fn light_blue_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `yellow_stained_glass` with default state values."] + pub fn yellow_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::YellowStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lime_stained_glass` with default state values."] + pub fn lime_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::LimeStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `pink_stained_glass` with default state values."] + pub fn pink_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::PinkStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gray_stained_glass` with default state values."] + pub fn gray_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::GrayStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_gray_stained_glass` with default state values."] + pub fn light_gray_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cyan_stained_glass` with default state values."] + pub fn cyan_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::CyanStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `purple_stained_glass` with default state values."] + pub fn purple_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::PurpleStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blue_stained_glass` with default state values."] + pub fn blue_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::BlueStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brown_stained_glass` with default state values."] + pub fn brown_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::BrownStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `green_stained_glass` with default state values."] + pub fn green_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::GreenStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_stained_glass` with default state values."] + pub fn red_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::RedStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `black_stained_glass` with default state values."] + pub fn black_stained_glass() -> Self { + let mut block = Self { + kind: BlockKind::BlackStainedGlass, + state: 0, + }; + block + } + #[doc = "Returns an instance of `oak_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn oak_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::OakTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `spruce_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn spruce_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::SpruceTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `birch_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn birch_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::BirchTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `jungle_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn jungle_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::JungleTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `acacia_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn acacia_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `dark_oak_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn dark_oak_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `stone_bricks` with default state values."] + pub fn stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::StoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `mossy_stone_bricks` with default state values."] + pub fn mossy_stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::MossyStoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cracked_stone_bricks` with default state values."] + pub fn cracked_stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::CrackedStoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `chiseled_stone_bricks` with default state values."] + pub fn chiseled_stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::ChiseledStoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `infested_stone` with default state values."] + pub fn infested_stone() -> Self { + let mut block = Self { + kind: BlockKind::InfestedStone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `infested_cobblestone` with default state values."] + pub fn infested_cobblestone() -> Self { + let mut block = Self { + kind: BlockKind::InfestedCobblestone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `infested_stone_bricks` with default state values."] + pub fn infested_stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::InfestedStoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `infested_mossy_stone_bricks` with default state values."] + pub fn infested_mossy_stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::InfestedMossyStoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `infested_cracked_stone_bricks` with default state values."] + pub fn infested_cracked_stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::InfestedCrackedStoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `infested_chiseled_stone_bricks` with default state values."] + pub fn infested_chiseled_stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::InfestedChiseledStoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brown_mushroom_block` with default state values.\nThe default state values are as follows:\n* `down`: true\n* `east_connected`: true\n* `north_connected`: true\n* `south_connected`: true\n* `up`: true\n* `west_connected`: true\n"] + pub fn brown_mushroom_block() -> Self { + let mut block = Self { + kind: BlockKind::BrownMushroomBlock, + state: 0, + }; + block.set_down(true); + block.set_east_connected(true); + block.set_north_connected(true); + block.set_south_connected(true); + block.set_up(true); + block.set_west_connected(true); + block + } + #[doc = "Returns an instance of `red_mushroom_block` with default state values.\nThe default state values are as follows:\n* `down`: true\n* `east_connected`: true\n* `north_connected`: true\n* `south_connected`: true\n* `up`: true\n* `west_connected`: true\n"] + pub fn red_mushroom_block() -> Self { + let mut block = Self { + kind: BlockKind::RedMushroomBlock, + state: 0, + }; + block.set_down(true); + block.set_east_connected(true); + block.set_north_connected(true); + block.set_south_connected(true); + block.set_up(true); + block.set_west_connected(true); + block + } + #[doc = "Returns an instance of `mushroom_stem` with default state values.\nThe default state values are as follows:\n* `down`: true\n* `east_connected`: true\n* `north_connected`: true\n* `south_connected`: true\n* `up`: true\n* `west_connected`: true\n"] + pub fn mushroom_stem() -> Self { + let mut block = Self { + kind: BlockKind::MushroomStem, + state: 0, + }; + block.set_down(true); + block.set_east_connected(true); + block.set_north_connected(true); + block.set_south_connected(true); + block.set_up(true); + block.set_west_connected(true); + block + } + #[doc = "Returns an instance of `iron_bars` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn iron_bars() -> Self { + let mut block = Self { + kind: BlockKind::IronBars, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `chain` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n* `waterlogged`: false\n"] + pub fn chain() -> Self { + let mut block = Self { + kind: BlockKind::Chain, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::GlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `melon` with default state values."] + pub fn melon() -> Self { + let mut block = Self { + kind: BlockKind::Melon, + state: 0, + }; + block + } + #[doc = "Returns an instance of `attached_pumpkin_stem` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn attached_pumpkin_stem() -> Self { + let mut block = Self { + kind: BlockKind::AttachedPumpkinStem, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `attached_melon_stem` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn attached_melon_stem() -> Self { + let mut block = Self { + kind: BlockKind::AttachedMelonStem, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `pumpkin_stem` with default state values.\nThe default state values are as follows:\n* `age_0_7`: 0\n"] + pub fn pumpkin_stem() -> Self { + let mut block = Self { + kind: BlockKind::PumpkinStem, + state: 0, + }; + block.set_age_0_7(0i32); + block + } + #[doc = "Returns an instance of `melon_stem` with default state values.\nThe default state values are as follows:\n* `age_0_7`: 0\n"] + pub fn melon_stem() -> Self { + let mut block = Self { + kind: BlockKind::MelonStem, + state: 0, + }; + block.set_age_0_7(0i32); + block + } + #[doc = "Returns an instance of `vine` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `up`: false\n* `west_connected`: false\n"] + pub fn vine() -> Self { + let mut block = Self { + kind: BlockKind::Vine, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_up(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `oak_fence_gate` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `in_wall`: false\n* `open`: false\n* `powered`: false\n"] + pub fn oak_fence_gate() -> Self { + let mut block = Self { + kind: BlockKind::OakFenceGate, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_in_wall(false); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `brick_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn brick_stairs() -> Self { + let mut block = Self { + kind: BlockKind::BrickStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `stone_brick_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn stone_brick_stairs() -> Self { + let mut block = Self { + kind: BlockKind::StoneBrickStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `mycelium` with default state values.\nThe default state values are as follows:\n* `snowy`: false\n"] + pub fn mycelium() -> Self { + let mut block = Self { + kind: BlockKind::Mycelium, + state: 0, + }; + block.set_snowy(false); + block + } + #[doc = "Returns an instance of `lily_pad` with default state values."] + pub fn lily_pad() -> Self { + let mut block = Self { + kind: BlockKind::LilyPad, + state: 0, + }; + block + } + #[doc = "Returns an instance of `nether_bricks` with default state values."] + pub fn nether_bricks() -> Self { + let mut block = Self { + kind: BlockKind::NetherBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `nether_brick_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn nether_brick_fence() -> Self { + let mut block = Self { + kind: BlockKind::NetherBrickFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `nether_brick_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn nether_brick_stairs() -> Self { + let mut block = Self { + kind: BlockKind::NetherBrickStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `nether_wart` with default state values.\nThe default state values are as follows:\n* `age_0_3`: 0\n"] + pub fn nether_wart() -> Self { + let mut block = Self { + kind: BlockKind::NetherWart, + state: 0, + }; + block.set_age_0_3(0i32); + block + } + #[doc = "Returns an instance of `enchanting_table` with default state values."] + pub fn enchanting_table() -> Self { + let mut block = Self { + kind: BlockKind::EnchantingTable, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brewing_stand` with default state values.\nThe default state values are as follows:\n* `has_bottle_0`: false\n* `has_bottle_1`: false\n* `has_bottle_2`: false\n"] + pub fn brewing_stand() -> Self { + let mut block = Self { + kind: BlockKind::BrewingStand, + state: 0, + }; + block.set_has_bottle_0(false); + block.set_has_bottle_1(false); + block.set_has_bottle_2(false); + block + } + #[doc = "Returns an instance of `cauldron` with default state values.\nThe default state values are as follows:\n* `cauldron_level`: 0\n"] + pub fn cauldron() -> Self { + let mut block = Self { + kind: BlockKind::Cauldron, + state: 0, + }; + block.set_cauldron_level(0i32); + block + } + #[doc = "Returns an instance of `end_portal` with default state values."] + pub fn end_portal() -> Self { + let mut block = Self { + kind: BlockKind::EndPortal, + state: 0, + }; + block + } + #[doc = "Returns an instance of `end_portal_frame` with default state values.\nThe default state values are as follows:\n* `eye`: false\n* `facing_cardinal`: north\n"] + pub fn end_portal_frame() -> Self { + let mut block = Self { + kind: BlockKind::EndPortalFrame, + state: 0, + }; + block.set_eye(false); + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `end_stone` with default state values."] + pub fn end_stone() -> Self { + let mut block = Self { + kind: BlockKind::EndStone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dragon_egg` with default state values."] + pub fn dragon_egg() -> Self { + let mut block = Self { + kind: BlockKind::DragonEgg, + state: 0, + }; + block + } + #[doc = "Returns an instance of `redstone_lamp` with default state values.\nThe default state values are as follows:\n* `lit`: false\n"] + pub fn redstone_lamp() -> Self { + let mut block = Self { + kind: BlockKind::RedstoneLamp, + state: 0, + }; + block.set_lit(false); + block + } + #[doc = "Returns an instance of `cocoa` with default state values.\nThe default state values are as follows:\n* `age_0_2`: 0\n* `facing_cardinal`: north\n"] + pub fn cocoa() -> Self { + let mut block = Self { + kind: BlockKind::Cocoa, + state: 0, + }; + block.set_age_0_2(0i32); + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `sandstone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn sandstone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::SandstoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `emerald_ore` with default state values."] + pub fn emerald_ore() -> Self { + let mut block = Self { + kind: BlockKind::EmeraldOre, + state: 0, + }; + block + } + #[doc = "Returns an instance of `ender_chest` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn ender_chest() -> Self { + let mut block = Self { + kind: BlockKind::EnderChest, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `tripwire_hook` with default state values.\nThe default state values are as follows:\n* `attached`: false\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn tripwire_hook() -> Self { + let mut block = Self { + kind: BlockKind::TripwireHook, + state: 0, + }; + block.set_attached(false); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `tripwire` with default state values.\nThe default state values are as follows:\n* `attached`: false\n* `disarmed`: false\n* `east_connected`: false\n* `north_connected`: false\n* `powered`: false\n* `south_connected`: false\n* `west_connected`: false\n"] + pub fn tripwire() -> Self { + let mut block = Self { + kind: BlockKind::Tripwire, + state: 0, + }; + block.set_attached(false); + block.set_disarmed(false); + block.set_east_connected(false); + block.set_north_connected(false); + block.set_powered(false); + block.set_south_connected(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `emerald_block` with default state values."] + pub fn emerald_block() -> Self { + let mut block = Self { + kind: BlockKind::EmeraldBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `spruce_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn spruce_stairs() -> Self { + let mut block = Self { + kind: BlockKind::SpruceStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `birch_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn birch_stairs() -> Self { + let mut block = Self { + kind: BlockKind::BirchStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `jungle_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn jungle_stairs() -> Self { + let mut block = Self { + kind: BlockKind::JungleStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `command_block` with default state values.\nThe default state values are as follows:\n* `conditional`: false\n* `facing_cubic`: north\n"] + pub fn command_block() -> Self { + let mut block = Self { + kind: BlockKind::CommandBlock, + state: 0, + }; + block.set_conditional(false); + block.set_facing_cubic(FacingCubic::North); + block + } + #[doc = "Returns an instance of `beacon` with default state values."] + pub fn beacon() -> Self { + let mut block = Self { + kind: BlockKind::Beacon, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cobblestone_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn cobblestone_wall() -> Self { + let mut block = Self { + kind: BlockKind::CobblestoneWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `mossy_cobblestone_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn mossy_cobblestone_wall() -> Self { + let mut block = Self { + kind: BlockKind::MossyCobblestoneWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `flower_pot` with default state values."] + pub fn flower_pot() -> Self { + let mut block = Self { + kind: BlockKind::FlowerPot, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_oak_sapling` with default state values."] + pub fn potted_oak_sapling() -> Self { + let mut block = Self { + kind: BlockKind::PottedOakSapling, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_spruce_sapling` with default state values."] + pub fn potted_spruce_sapling() -> Self { + let mut block = Self { + kind: BlockKind::PottedSpruceSapling, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_birch_sapling` with default state values."] + pub fn potted_birch_sapling() -> Self { + let mut block = Self { + kind: BlockKind::PottedBirchSapling, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_jungle_sapling` with default state values."] + pub fn potted_jungle_sapling() -> Self { + let mut block = Self { + kind: BlockKind::PottedJungleSapling, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_acacia_sapling` with default state values."] + pub fn potted_acacia_sapling() -> Self { + let mut block = Self { + kind: BlockKind::PottedAcaciaSapling, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_dark_oak_sapling` with default state values."] + pub fn potted_dark_oak_sapling() -> Self { + let mut block = Self { + kind: BlockKind::PottedDarkOakSapling, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_fern` with default state values."] + pub fn potted_fern() -> Self { + let mut block = Self { + kind: BlockKind::PottedFern, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_dandelion` with default state values."] + pub fn potted_dandelion() -> Self { + let mut block = Self { + kind: BlockKind::PottedDandelion, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_poppy` with default state values."] + pub fn potted_poppy() -> Self { + let mut block = Self { + kind: BlockKind::PottedPoppy, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_blue_orchid` with default state values."] + pub fn potted_blue_orchid() -> Self { + let mut block = Self { + kind: BlockKind::PottedBlueOrchid, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_allium` with default state values."] + pub fn potted_allium() -> Self { + let mut block = Self { + kind: BlockKind::PottedAllium, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_azure_bluet` with default state values."] + pub fn potted_azure_bluet() -> Self { + let mut block = Self { + kind: BlockKind::PottedAzureBluet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_red_tulip` with default state values."] + pub fn potted_red_tulip() -> Self { + let mut block = Self { + kind: BlockKind::PottedRedTulip, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_orange_tulip` with default state values."] + pub fn potted_orange_tulip() -> Self { + let mut block = Self { + kind: BlockKind::PottedOrangeTulip, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_white_tulip` with default state values."] + pub fn potted_white_tulip() -> Self { + let mut block = Self { + kind: BlockKind::PottedWhiteTulip, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_pink_tulip` with default state values."] + pub fn potted_pink_tulip() -> Self { + let mut block = Self { + kind: BlockKind::PottedPinkTulip, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_oxeye_daisy` with default state values."] + pub fn potted_oxeye_daisy() -> Self { + let mut block = Self { + kind: BlockKind::PottedOxeyeDaisy, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_cornflower` with default state values."] + pub fn potted_cornflower() -> Self { + let mut block = Self { + kind: BlockKind::PottedCornflower, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_lily_of_the_valley` with default state values."] + pub fn potted_lily_of_the_valley() -> Self { + let mut block = Self { + kind: BlockKind::PottedLilyOfTheValley, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_wither_rose` with default state values."] + pub fn potted_wither_rose() -> Self { + let mut block = Self { + kind: BlockKind::PottedWitherRose, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_red_mushroom` with default state values."] + pub fn potted_red_mushroom() -> Self { + let mut block = Self { + kind: BlockKind::PottedRedMushroom, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_brown_mushroom` with default state values."] + pub fn potted_brown_mushroom() -> Self { + let mut block = Self { + kind: BlockKind::PottedBrownMushroom, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_dead_bush` with default state values."] + pub fn potted_dead_bush() -> Self { + let mut block = Self { + kind: BlockKind::PottedDeadBush, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_cactus` with default state values."] + pub fn potted_cactus() -> Self { + let mut block = Self { + kind: BlockKind::PottedCactus, + state: 0, + }; + block + } + #[doc = "Returns an instance of `carrots` with default state values.\nThe default state values are as follows:\n* `age_0_7`: 0\n"] + pub fn carrots() -> Self { + let mut block = Self { + kind: BlockKind::Carrots, + state: 0, + }; + block.set_age_0_7(0i32); + block + } + #[doc = "Returns an instance of `potatoes` with default state values.\nThe default state values are as follows:\n* `age_0_7`: 0\n"] + pub fn potatoes() -> Self { + let mut block = Self { + kind: BlockKind::Potatoes, + state: 0, + }; + block.set_age_0_7(0i32); + block + } + #[doc = "Returns an instance of `oak_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn oak_button() -> Self { + let mut block = Self { + kind: BlockKind::OakButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `spruce_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn spruce_button() -> Self { + let mut block = Self { + kind: BlockKind::SpruceButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `birch_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn birch_button() -> Self { + let mut block = Self { + kind: BlockKind::BirchButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `jungle_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn jungle_button() -> Self { + let mut block = Self { + kind: BlockKind::JungleButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `acacia_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn acacia_button() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `dark_oak_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn dark_oak_button() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `skeleton_skull` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn skeleton_skull() -> Self { + let mut block = Self { + kind: BlockKind::SkeletonSkull, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `skeleton_wall_skull` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn skeleton_wall_skull() -> Self { + let mut block = Self { + kind: BlockKind::SkeletonWallSkull, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `wither_skeleton_skull` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn wither_skeleton_skull() -> Self { + let mut block = Self { + kind: BlockKind::WitherSkeletonSkull, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `wither_skeleton_wall_skull` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn wither_skeleton_wall_skull() -> Self { + let mut block = Self { + kind: BlockKind::WitherSkeletonWallSkull, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `zombie_head` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn zombie_head() -> Self { + let mut block = Self { + kind: BlockKind::ZombieHead, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `zombie_wall_head` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn zombie_wall_head() -> Self { + let mut block = Self { + kind: BlockKind::ZombieWallHead, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `player_head` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn player_head() -> Self { + let mut block = Self { + kind: BlockKind::PlayerHead, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `player_wall_head` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn player_wall_head() -> Self { + let mut block = Self { + kind: BlockKind::PlayerWallHead, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `creeper_head` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn creeper_head() -> Self { + let mut block = Self { + kind: BlockKind::CreeperHead, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `creeper_wall_head` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn creeper_wall_head() -> Self { + let mut block = Self { + kind: BlockKind::CreeperWallHead, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `dragon_head` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn dragon_head() -> Self { + let mut block = Self { + kind: BlockKind::DragonHead, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `dragon_wall_head` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn dragon_wall_head() -> Self { + let mut block = Self { + kind: BlockKind::DragonWallHead, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `anvil` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn anvil() -> Self { + let mut block = Self { + kind: BlockKind::Anvil, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `chipped_anvil` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn chipped_anvil() -> Self { + let mut block = Self { + kind: BlockKind::ChippedAnvil, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `damaged_anvil` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn damaged_anvil() -> Self { + let mut block = Self { + kind: BlockKind::DamagedAnvil, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `trapped_chest` with default state values.\nThe default state values are as follows:\n* `chest_kind`: single\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn trapped_chest() -> Self { + let mut block = Self { + kind: BlockKind::TrappedChest, + state: 0, + }; + block.set_chest_kind(ChestKind::Single); + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `light_weighted_pressure_plate` with default state values.\nThe default state values are as follows:\n* `power`: 0\n"] + pub fn light_weighted_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::LightWeightedPressurePlate, + state: 0, + }; + block.set_power(0i32); + block + } + #[doc = "Returns an instance of `heavy_weighted_pressure_plate` with default state values.\nThe default state values are as follows:\n* `power`: 0\n"] + pub fn heavy_weighted_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::HeavyWeightedPressurePlate, + state: 0, + }; + block.set_power(0i32); + block + } + #[doc = "Returns an instance of `comparator` with default state values.\nThe default state values are as follows:\n* `comparator_mode`: compare\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn comparator() -> Self { + let mut block = Self { + kind: BlockKind::Comparator, + state: 0, + }; + block.set_comparator_mode(ComparatorMode::Compare); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `daylight_detector` with default state values.\nThe default state values are as follows:\n* `inverted`: false\n* `power`: 0\n"] + pub fn daylight_detector() -> Self { + let mut block = Self { + kind: BlockKind::DaylightDetector, + state: 0, + }; + block.set_inverted(false); + block.set_power(0i32); + block + } + #[doc = "Returns an instance of `redstone_block` with default state values."] + pub fn redstone_block() -> Self { + let mut block = Self { + kind: BlockKind::RedstoneBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `nether_quartz_ore` with default state values."] + pub fn nether_quartz_ore() -> Self { + let mut block = Self { + kind: BlockKind::NetherQuartzOre, + state: 0, + }; + block + } + #[doc = "Returns an instance of `hopper` with default state values.\nThe default state values are as follows:\n* `enabled`: true\n* `facing_cardinal_and_down`: down\n"] + pub fn hopper() -> Self { + let mut block = Self { + kind: BlockKind::Hopper, + state: 0, + }; + block.set_enabled(true); + block.set_facing_cardinal_and_down(FacingCardinalAndDown::Down); + block + } + #[doc = "Returns an instance of `quartz_block` with default state values."] + pub fn quartz_block() -> Self { + let mut block = Self { + kind: BlockKind::QuartzBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `chiseled_quartz_block` with default state values."] + pub fn chiseled_quartz_block() -> Self { + let mut block = Self { + kind: BlockKind::ChiseledQuartzBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `quartz_pillar` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn quartz_pillar() -> Self { + let mut block = Self { + kind: BlockKind::QuartzPillar, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `quartz_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn quartz_stairs() -> Self { + let mut block = Self { + kind: BlockKind::QuartzStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `activator_rail` with default state values.\nThe default state values are as follows:\n* `powered`: false\n* `powered_rail_shape`: north_south\n"] + pub fn activator_rail() -> Self { + let mut block = Self { + kind: BlockKind::ActivatorRail, + state: 0, + }; + block.set_powered(false); + block.set_powered_rail_shape(PoweredRailShape::NorthSouth); + block + } + #[doc = "Returns an instance of `dropper` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: north\n* `triggered`: false\n"] + pub fn dropper() -> Self { + let mut block = Self { + kind: BlockKind::Dropper, + state: 0, + }; + block.set_facing_cubic(FacingCubic::North); + block.set_triggered(false); + block + } + #[doc = "Returns an instance of `white_terracotta` with default state values."] + pub fn white_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::WhiteTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `orange_terracotta` with default state values."] + pub fn orange_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::OrangeTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `magenta_terracotta` with default state values."] + pub fn magenta_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::MagentaTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_blue_terracotta` with default state values."] + pub fn light_blue_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `yellow_terracotta` with default state values."] + pub fn yellow_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::YellowTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lime_terracotta` with default state values."] + pub fn lime_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::LimeTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `pink_terracotta` with default state values."] + pub fn pink_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::PinkTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gray_terracotta` with default state values."] + pub fn gray_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::GrayTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_gray_terracotta` with default state values."] + pub fn light_gray_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cyan_terracotta` with default state values."] + pub fn cyan_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::CyanTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `purple_terracotta` with default state values."] + pub fn purple_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::PurpleTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blue_terracotta` with default state values."] + pub fn blue_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::BlueTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brown_terracotta` with default state values."] + pub fn brown_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::BrownTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `green_terracotta` with default state values."] + pub fn green_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::GreenTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_terracotta` with default state values."] + pub fn red_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::RedTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `black_terracotta` with default state values."] + pub fn black_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::BlackTerracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `white_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn white_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::WhiteStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `orange_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn orange_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::OrangeStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `magenta_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn magenta_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::MagentaStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `light_blue_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn light_blue_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `yellow_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn yellow_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::YellowStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `lime_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn lime_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::LimeStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `pink_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn pink_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::PinkStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `gray_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn gray_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::GrayStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `light_gray_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn light_gray_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `cyan_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn cyan_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::CyanStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `purple_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn purple_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::PurpleStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `blue_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn blue_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::BlueStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `brown_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn brown_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::BrownStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `green_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn green_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::GreenStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `red_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn red_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::RedStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `black_stained_glass_pane` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn black_stained_glass_pane() -> Self { + let mut block = Self { + kind: BlockKind::BlackStainedGlassPane, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `acacia_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn acacia_stairs() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `dark_oak_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn dark_oak_stairs() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `slime_block` with default state values."] + pub fn slime_block() -> Self { + let mut block = Self { + kind: BlockKind::SlimeBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `barrier` with default state values."] + pub fn barrier() -> Self { + let mut block = Self { + kind: BlockKind::Barrier, + state: 0, + }; + block + } + #[doc = "Returns an instance of `iron_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn iron_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::IronTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `prismarine` with default state values."] + pub fn prismarine() -> Self { + let mut block = Self { + kind: BlockKind::Prismarine, + state: 0, + }; + block + } + #[doc = "Returns an instance of `prismarine_bricks` with default state values."] + pub fn prismarine_bricks() -> Self { + let mut block = Self { + kind: BlockKind::PrismarineBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dark_prismarine` with default state values."] + pub fn dark_prismarine() -> Self { + let mut block = Self { + kind: BlockKind::DarkPrismarine, + state: 0, + }; + block + } + #[doc = "Returns an instance of `prismarine_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn prismarine_stairs() -> Self { + let mut block = Self { + kind: BlockKind::PrismarineStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `prismarine_brick_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn prismarine_brick_stairs() -> Self { + let mut block = Self { + kind: BlockKind::PrismarineBrickStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `dark_prismarine_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn dark_prismarine_stairs() -> Self { + let mut block = Self { + kind: BlockKind::DarkPrismarineStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `prismarine_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn prismarine_slab() -> Self { + let mut block = Self { + kind: BlockKind::PrismarineSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `prismarine_brick_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn prismarine_brick_slab() -> Self { + let mut block = Self { + kind: BlockKind::PrismarineBrickSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `dark_prismarine_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn dark_prismarine_slab() -> Self { + let mut block = Self { + kind: BlockKind::DarkPrismarineSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `sea_lantern` with default state values."] + pub fn sea_lantern() -> Self { + let mut block = Self { + kind: BlockKind::SeaLantern, + state: 0, + }; + block + } + #[doc = "Returns an instance of `hay_block` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn hay_block() -> Self { + let mut block = Self { + kind: BlockKind::HayBlock, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `white_carpet` with default state values."] + pub fn white_carpet() -> Self { + let mut block = Self { + kind: BlockKind::WhiteCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `orange_carpet` with default state values."] + pub fn orange_carpet() -> Self { + let mut block = Self { + kind: BlockKind::OrangeCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `magenta_carpet` with default state values."] + pub fn magenta_carpet() -> Self { + let mut block = Self { + kind: BlockKind::MagentaCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_blue_carpet` with default state values."] + pub fn light_blue_carpet() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `yellow_carpet` with default state values."] + pub fn yellow_carpet() -> Self { + let mut block = Self { + kind: BlockKind::YellowCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lime_carpet` with default state values."] + pub fn lime_carpet() -> Self { + let mut block = Self { + kind: BlockKind::LimeCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `pink_carpet` with default state values."] + pub fn pink_carpet() -> Self { + let mut block = Self { + kind: BlockKind::PinkCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gray_carpet` with default state values."] + pub fn gray_carpet() -> Self { + let mut block = Self { + kind: BlockKind::GrayCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_gray_carpet` with default state values."] + pub fn light_gray_carpet() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cyan_carpet` with default state values."] + pub fn cyan_carpet() -> Self { + let mut block = Self { + kind: BlockKind::CyanCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `purple_carpet` with default state values."] + pub fn purple_carpet() -> Self { + let mut block = Self { + kind: BlockKind::PurpleCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blue_carpet` with default state values."] + pub fn blue_carpet() -> Self { + let mut block = Self { + kind: BlockKind::BlueCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brown_carpet` with default state values."] + pub fn brown_carpet() -> Self { + let mut block = Self { + kind: BlockKind::BrownCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `green_carpet` with default state values."] + pub fn green_carpet() -> Self { + let mut block = Self { + kind: BlockKind::GreenCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_carpet` with default state values."] + pub fn red_carpet() -> Self { + let mut block = Self { + kind: BlockKind::RedCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `black_carpet` with default state values."] + pub fn black_carpet() -> Self { + let mut block = Self { + kind: BlockKind::BlackCarpet, + state: 0, + }; + block + } + #[doc = "Returns an instance of `terracotta` with default state values."] + pub fn terracotta() -> Self { + let mut block = Self { + kind: BlockKind::Terracotta, + state: 0, + }; + block + } + #[doc = "Returns an instance of `coal_block` with default state values."] + pub fn coal_block() -> Self { + let mut block = Self { + kind: BlockKind::CoalBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `packed_ice` with default state values."] + pub fn packed_ice() -> Self { + let mut block = Self { + kind: BlockKind::PackedIce, + state: 0, + }; + block + } + #[doc = "Returns an instance of `sunflower` with default state values.\nThe default state values are as follows:\n* `half_upper_lower`: lower\n"] + pub fn sunflower() -> Self { + let mut block = Self { + kind: BlockKind::Sunflower, + state: 0, + }; + block.set_half_upper_lower(HalfUpperLower::Lower); + block + } + #[doc = "Returns an instance of `lilac` with default state values.\nThe default state values are as follows:\n* `half_upper_lower`: lower\n"] + pub fn lilac() -> Self { + let mut block = Self { + kind: BlockKind::Lilac, + state: 0, + }; + block.set_half_upper_lower(HalfUpperLower::Lower); + block + } + #[doc = "Returns an instance of `rose_bush` with default state values.\nThe default state values are as follows:\n* `half_upper_lower`: lower\n"] + pub fn rose_bush() -> Self { + let mut block = Self { + kind: BlockKind::RoseBush, + state: 0, + }; + block.set_half_upper_lower(HalfUpperLower::Lower); + block + } + #[doc = "Returns an instance of `peony` with default state values.\nThe default state values are as follows:\n* `half_upper_lower`: lower\n"] + pub fn peony() -> Self { + let mut block = Self { + kind: BlockKind::Peony, + state: 0, + }; + block.set_half_upper_lower(HalfUpperLower::Lower); + block + } + #[doc = "Returns an instance of `tall_grass` with default state values.\nThe default state values are as follows:\n* `half_upper_lower`: lower\n"] + pub fn tall_grass() -> Self { + let mut block = Self { + kind: BlockKind::TallGrass, + state: 0, + }; + block.set_half_upper_lower(HalfUpperLower::Lower); + block + } + #[doc = "Returns an instance of `large_fern` with default state values.\nThe default state values are as follows:\n* `half_upper_lower`: lower\n"] + pub fn large_fern() -> Self { + let mut block = Self { + kind: BlockKind::LargeFern, + state: 0, + }; + block.set_half_upper_lower(HalfUpperLower::Lower); + block + } + #[doc = "Returns an instance of `white_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn white_banner() -> Self { + let mut block = Self { + kind: BlockKind::WhiteBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `orange_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn orange_banner() -> Self { + let mut block = Self { + kind: BlockKind::OrangeBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `magenta_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn magenta_banner() -> Self { + let mut block = Self { + kind: BlockKind::MagentaBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `light_blue_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn light_blue_banner() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `yellow_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn yellow_banner() -> Self { + let mut block = Self { + kind: BlockKind::YellowBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `lime_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn lime_banner() -> Self { + let mut block = Self { + kind: BlockKind::LimeBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `pink_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn pink_banner() -> Self { + let mut block = Self { + kind: BlockKind::PinkBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `gray_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn gray_banner() -> Self { + let mut block = Self { + kind: BlockKind::GrayBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `light_gray_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn light_gray_banner() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `cyan_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn cyan_banner() -> Self { + let mut block = Self { + kind: BlockKind::CyanBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `purple_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn purple_banner() -> Self { + let mut block = Self { + kind: BlockKind::PurpleBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `blue_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn blue_banner() -> Self { + let mut block = Self { + kind: BlockKind::BlueBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `brown_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn brown_banner() -> Self { + let mut block = Self { + kind: BlockKind::BrownBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `green_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn green_banner() -> Self { + let mut block = Self { + kind: BlockKind::GreenBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `red_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn red_banner() -> Self { + let mut block = Self { + kind: BlockKind::RedBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `black_banner` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n"] + pub fn black_banner() -> Self { + let mut block = Self { + kind: BlockKind::BlackBanner, + state: 0, + }; + block.set_rotation(0i32); + block + } + #[doc = "Returns an instance of `white_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn white_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::WhiteWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `orange_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn orange_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::OrangeWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `magenta_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn magenta_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::MagentaWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `light_blue_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn light_blue_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `yellow_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn yellow_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::YellowWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `lime_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn lime_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::LimeWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `pink_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn pink_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::PinkWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `gray_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn gray_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::GrayWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `light_gray_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn light_gray_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `cyan_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn cyan_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::CyanWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `purple_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn purple_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::PurpleWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `blue_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn blue_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::BlueWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `brown_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn brown_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::BrownWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `green_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn green_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::GreenWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `red_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn red_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::RedWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `black_wall_banner` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn black_wall_banner() -> Self { + let mut block = Self { + kind: BlockKind::BlackWallBanner, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `red_sandstone` with default state values."] + pub fn red_sandstone() -> Self { + let mut block = Self { + kind: BlockKind::RedSandstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `chiseled_red_sandstone` with default state values."] + pub fn chiseled_red_sandstone() -> Self { + let mut block = Self { + kind: BlockKind::ChiseledRedSandstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cut_red_sandstone` with default state values."] + pub fn cut_red_sandstone() -> Self { + let mut block = Self { + kind: BlockKind::CutRedSandstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_sandstone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn red_sandstone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::RedSandstoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `oak_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn oak_slab() -> Self { + let mut block = Self { + kind: BlockKind::OakSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `spruce_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn spruce_slab() -> Self { + let mut block = Self { + kind: BlockKind::SpruceSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `birch_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn birch_slab() -> Self { + let mut block = Self { + kind: BlockKind::BirchSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `jungle_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn jungle_slab() -> Self { + let mut block = Self { + kind: BlockKind::JungleSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `acacia_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn acacia_slab() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `dark_oak_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn dark_oak_slab() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `stone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn stone_slab() -> Self { + let mut block = Self { + kind: BlockKind::StoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `smooth_stone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn smooth_stone_slab() -> Self { + let mut block = Self { + kind: BlockKind::SmoothStoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `sandstone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn sandstone_slab() -> Self { + let mut block = Self { + kind: BlockKind::SandstoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `cut_sandstone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn cut_sandstone_slab() -> Self { + let mut block = Self { + kind: BlockKind::CutSandstoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `petrified_oak_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn petrified_oak_slab() -> Self { + let mut block = Self { + kind: BlockKind::PetrifiedOakSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `cobblestone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn cobblestone_slab() -> Self { + let mut block = Self { + kind: BlockKind::CobblestoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `brick_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn brick_slab() -> Self { + let mut block = Self { + kind: BlockKind::BrickSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `stone_brick_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn stone_brick_slab() -> Self { + let mut block = Self { + kind: BlockKind::StoneBrickSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `nether_brick_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn nether_brick_slab() -> Self { + let mut block = Self { + kind: BlockKind::NetherBrickSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `quartz_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn quartz_slab() -> Self { + let mut block = Self { + kind: BlockKind::QuartzSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `red_sandstone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn red_sandstone_slab() -> Self { + let mut block = Self { + kind: BlockKind::RedSandstoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `cut_red_sandstone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn cut_red_sandstone_slab() -> Self { + let mut block = Self { + kind: BlockKind::CutRedSandstoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `purpur_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn purpur_slab() -> Self { + let mut block = Self { + kind: BlockKind::PurpurSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `smooth_stone` with default state values."] + pub fn smooth_stone() -> Self { + let mut block = Self { + kind: BlockKind::SmoothStone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `smooth_sandstone` with default state values."] + pub fn smooth_sandstone() -> Self { + let mut block = Self { + kind: BlockKind::SmoothSandstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `smooth_quartz` with default state values."] + pub fn smooth_quartz() -> Self { + let mut block = Self { + kind: BlockKind::SmoothQuartz, + state: 0, + }; + block + } + #[doc = "Returns an instance of `smooth_red_sandstone` with default state values."] + pub fn smooth_red_sandstone() -> Self { + let mut block = Self { + kind: BlockKind::SmoothRedSandstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `spruce_fence_gate` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `in_wall`: false\n* `open`: false\n* `powered`: false\n"] + pub fn spruce_fence_gate() -> Self { + let mut block = Self { + kind: BlockKind::SpruceFenceGate, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_in_wall(false); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `birch_fence_gate` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `in_wall`: false\n* `open`: false\n* `powered`: false\n"] + pub fn birch_fence_gate() -> Self { + let mut block = Self { + kind: BlockKind::BirchFenceGate, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_in_wall(false); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `jungle_fence_gate` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `in_wall`: false\n* `open`: false\n* `powered`: false\n"] + pub fn jungle_fence_gate() -> Self { + let mut block = Self { + kind: BlockKind::JungleFenceGate, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_in_wall(false); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `acacia_fence_gate` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `in_wall`: false\n* `open`: false\n* `powered`: false\n"] + pub fn acacia_fence_gate() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaFenceGate, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_in_wall(false); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `dark_oak_fence_gate` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `in_wall`: false\n* `open`: false\n* `powered`: false\n"] + pub fn dark_oak_fence_gate() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakFenceGate, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_in_wall(false); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `spruce_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn spruce_fence() -> Self { + let mut block = Self { + kind: BlockKind::SpruceFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `birch_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn birch_fence() -> Self { + let mut block = Self { + kind: BlockKind::BirchFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `jungle_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn jungle_fence() -> Self { + let mut block = Self { + kind: BlockKind::JungleFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `acacia_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn acacia_fence() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `dark_oak_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn dark_oak_fence() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `spruce_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn spruce_door() -> Self { + let mut block = Self { + kind: BlockKind::SpruceDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `birch_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn birch_door() -> Self { + let mut block = Self { + kind: BlockKind::BirchDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `jungle_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn jungle_door() -> Self { + let mut block = Self { + kind: BlockKind::JungleDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `acacia_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn acacia_door() -> Self { + let mut block = Self { + kind: BlockKind::AcaciaDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `dark_oak_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn dark_oak_door() -> Self { + let mut block = Self { + kind: BlockKind::DarkOakDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `end_rod` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn end_rod() -> Self { + let mut block = Self { + kind: BlockKind::EndRod, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `chorus_plant` with default state values.\nThe default state values are as follows:\n* `down`: false\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `up`: false\n* `west_connected`: false\n"] + pub fn chorus_plant() -> Self { + let mut block = Self { + kind: BlockKind::ChorusPlant, + state: 0, + }; + block.set_down(false); + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_up(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `chorus_flower` with default state values.\nThe default state values are as follows:\n* `age_0_5`: 0\n"] + pub fn chorus_flower() -> Self { + let mut block = Self { + kind: BlockKind::ChorusFlower, + state: 0, + }; + block.set_age_0_5(0i32); + block + } + #[doc = "Returns an instance of `purpur_block` with default state values."] + pub fn purpur_block() -> Self { + let mut block = Self { + kind: BlockKind::PurpurBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `purpur_pillar` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn purpur_pillar() -> Self { + let mut block = Self { + kind: BlockKind::PurpurPillar, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `purpur_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn purpur_stairs() -> Self { + let mut block = Self { + kind: BlockKind::PurpurStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `end_stone_bricks` with default state values."] + pub fn end_stone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::EndStoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `beetroots` with default state values.\nThe default state values are as follows:\n* `age_0_3`: 0\n"] + pub fn beetroots() -> Self { + let mut block = Self { + kind: BlockKind::Beetroots, + state: 0, + }; + block.set_age_0_3(0i32); + block + } + #[doc = "Returns an instance of `grass_path` with default state values."] + pub fn grass_path() -> Self { + let mut block = Self { + kind: BlockKind::GrassPath, + state: 0, + }; + block + } + #[doc = "Returns an instance of `end_gateway` with default state values."] + pub fn end_gateway() -> Self { + let mut block = Self { + kind: BlockKind::EndGateway, + state: 0, + }; + block + } + #[doc = "Returns an instance of `repeating_command_block` with default state values.\nThe default state values are as follows:\n* `conditional`: false\n* `facing_cubic`: north\n"] + pub fn repeating_command_block() -> Self { + let mut block = Self { + kind: BlockKind::RepeatingCommandBlock, + state: 0, + }; + block.set_conditional(false); + block.set_facing_cubic(FacingCubic::North); + block + } + #[doc = "Returns an instance of `chain_command_block` with default state values.\nThe default state values are as follows:\n* `conditional`: false\n* `facing_cubic`: north\n"] + pub fn chain_command_block() -> Self { + let mut block = Self { + kind: BlockKind::ChainCommandBlock, + state: 0, + }; + block.set_conditional(false); + block.set_facing_cubic(FacingCubic::North); + block + } + #[doc = "Returns an instance of `frosted_ice` with default state values.\nThe default state values are as follows:\n* `age_0_3`: 0\n"] + pub fn frosted_ice() -> Self { + let mut block = Self { + kind: BlockKind::FrostedIce, + state: 0, + }; + block.set_age_0_3(0i32); + block + } + #[doc = "Returns an instance of `magma_block` with default state values."] + pub fn magma_block() -> Self { + let mut block = Self { + kind: BlockKind::MagmaBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `nether_wart_block` with default state values."] + pub fn nether_wart_block() -> Self { + let mut block = Self { + kind: BlockKind::NetherWartBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_nether_bricks` with default state values."] + pub fn red_nether_bricks() -> Self { + let mut block = Self { + kind: BlockKind::RedNetherBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `bone_block` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn bone_block() -> Self { + let mut block = Self { + kind: BlockKind::BoneBlock, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `structure_void` with default state values."] + pub fn structure_void() -> Self { + let mut block = Self { + kind: BlockKind::StructureVoid, + state: 0, + }; + block + } + #[doc = "Returns an instance of `observer` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: south\n* `powered`: false\n"] + pub fn observer() -> Self { + let mut block = Self { + kind: BlockKind::Observer, + state: 0, + }; + block.set_facing_cubic(FacingCubic::South); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::ShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `white_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn white_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::WhiteShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `orange_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn orange_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::OrangeShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `magenta_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn magenta_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::MagentaShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `light_blue_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn light_blue_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `yellow_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn yellow_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::YellowShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `lime_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn lime_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::LimeShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `pink_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn pink_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::PinkShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `gray_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn gray_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::GrayShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `light_gray_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn light_gray_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `cyan_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn cyan_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::CyanShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `purple_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn purple_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::PurpleShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `blue_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn blue_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::BlueShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `brown_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn brown_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::BrownShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `green_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn green_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::GreenShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `red_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn red_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::RedShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `black_shulker_box` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: up\n"] + pub fn black_shulker_box() -> Self { + let mut block = Self { + kind: BlockKind::BlackShulkerBox, + state: 0, + }; + block.set_facing_cubic(FacingCubic::Up); + block + } + #[doc = "Returns an instance of `white_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn white_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::WhiteGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `orange_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn orange_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::OrangeGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `magenta_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn magenta_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::MagentaGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `light_blue_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn light_blue_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `yellow_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn yellow_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::YellowGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `lime_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn lime_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::LimeGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `pink_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn pink_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::PinkGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `gray_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn gray_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::GrayGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `light_gray_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn light_gray_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `cyan_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn cyan_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::CyanGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `purple_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn purple_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::PurpleGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `blue_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn blue_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::BlueGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `brown_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn brown_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::BrownGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `green_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn green_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::GreenGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `red_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn red_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::RedGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `black_glazed_terracotta` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn black_glazed_terracotta() -> Self { + let mut block = Self { + kind: BlockKind::BlackGlazedTerracotta, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `white_concrete` with default state values."] + pub fn white_concrete() -> Self { + let mut block = Self { + kind: BlockKind::WhiteConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `orange_concrete` with default state values."] + pub fn orange_concrete() -> Self { + let mut block = Self { + kind: BlockKind::OrangeConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `magenta_concrete` with default state values."] + pub fn magenta_concrete() -> Self { + let mut block = Self { + kind: BlockKind::MagentaConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_blue_concrete` with default state values."] + pub fn light_blue_concrete() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `yellow_concrete` with default state values."] + pub fn yellow_concrete() -> Self { + let mut block = Self { + kind: BlockKind::YellowConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lime_concrete` with default state values."] + pub fn lime_concrete() -> Self { + let mut block = Self { + kind: BlockKind::LimeConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `pink_concrete` with default state values."] + pub fn pink_concrete() -> Self { + let mut block = Self { + kind: BlockKind::PinkConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gray_concrete` with default state values."] + pub fn gray_concrete() -> Self { + let mut block = Self { + kind: BlockKind::GrayConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_gray_concrete` with default state values."] + pub fn light_gray_concrete() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cyan_concrete` with default state values."] + pub fn cyan_concrete() -> Self { + let mut block = Self { + kind: BlockKind::CyanConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `purple_concrete` with default state values."] + pub fn purple_concrete() -> Self { + let mut block = Self { + kind: BlockKind::PurpleConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blue_concrete` with default state values."] + pub fn blue_concrete() -> Self { + let mut block = Self { + kind: BlockKind::BlueConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brown_concrete` with default state values."] + pub fn brown_concrete() -> Self { + let mut block = Self { + kind: BlockKind::BrownConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `green_concrete` with default state values."] + pub fn green_concrete() -> Self { + let mut block = Self { + kind: BlockKind::GreenConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_concrete` with default state values."] + pub fn red_concrete() -> Self { + let mut block = Self { + kind: BlockKind::RedConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `black_concrete` with default state values."] + pub fn black_concrete() -> Self { + let mut block = Self { + kind: BlockKind::BlackConcrete, + state: 0, + }; + block + } + #[doc = "Returns an instance of `white_concrete_powder` with default state values."] + pub fn white_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::WhiteConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `orange_concrete_powder` with default state values."] + pub fn orange_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::OrangeConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `magenta_concrete_powder` with default state values."] + pub fn magenta_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::MagentaConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_blue_concrete_powder` with default state values."] + pub fn light_blue_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::LightBlueConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `yellow_concrete_powder` with default state values."] + pub fn yellow_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::YellowConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lime_concrete_powder` with default state values."] + pub fn lime_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::LimeConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `pink_concrete_powder` with default state values."] + pub fn pink_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::PinkConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `gray_concrete_powder` with default state values."] + pub fn gray_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::GrayConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `light_gray_concrete_powder` with default state values."] + pub fn light_gray_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::LightGrayConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cyan_concrete_powder` with default state values."] + pub fn cyan_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::CyanConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `purple_concrete_powder` with default state values."] + pub fn purple_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::PurpleConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blue_concrete_powder` with default state values."] + pub fn blue_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::BlueConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brown_concrete_powder` with default state values."] + pub fn brown_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::BrownConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `green_concrete_powder` with default state values."] + pub fn green_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::GreenConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `red_concrete_powder` with default state values."] + pub fn red_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::RedConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `black_concrete_powder` with default state values."] + pub fn black_concrete_powder() -> Self { + let mut block = Self { + kind: BlockKind::BlackConcretePowder, + state: 0, + }; + block + } + #[doc = "Returns an instance of `kelp` with default state values.\nThe default state values are as follows:\n* `age_0_25`: 0\n"] + pub fn kelp() -> Self { + let mut block = Self { + kind: BlockKind::Kelp, + state: 0, + }; + block.set_age_0_25(0i32); + block + } + #[doc = "Returns an instance of `kelp_plant` with default state values."] + pub fn kelp_plant() -> Self { + let mut block = Self { + kind: BlockKind::KelpPlant, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dried_kelp_block` with default state values."] + pub fn dried_kelp_block() -> Self { + let mut block = Self { + kind: BlockKind::DriedKelpBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `turtle_egg` with default state values.\nThe default state values are as follows:\n* `eggs`: 1\n* `hatch`: 0\n"] + pub fn turtle_egg() -> Self { + let mut block = Self { + kind: BlockKind::TurtleEgg, + state: 0, + }; + block.set_eggs(1i32); + block.set_hatch(0i32); + block + } + #[doc = "Returns an instance of `dead_tube_coral_block` with default state values."] + pub fn dead_tube_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::DeadTubeCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dead_brain_coral_block` with default state values."] + pub fn dead_brain_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::DeadBrainCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dead_bubble_coral_block` with default state values."] + pub fn dead_bubble_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::DeadBubbleCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dead_fire_coral_block` with default state values."] + pub fn dead_fire_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::DeadFireCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dead_horn_coral_block` with default state values."] + pub fn dead_horn_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::DeadHornCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `tube_coral_block` with default state values."] + pub fn tube_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::TubeCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `brain_coral_block` with default state values."] + pub fn brain_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::BrainCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `bubble_coral_block` with default state values."] + pub fn bubble_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::BubbleCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `fire_coral_block` with default state values."] + pub fn fire_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::FireCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `horn_coral_block` with default state values."] + pub fn horn_coral_block() -> Self { + let mut block = Self { + kind: BlockKind::HornCoralBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `dead_tube_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_tube_coral() -> Self { + let mut block = Self { + kind: BlockKind::DeadTubeCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_brain_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_brain_coral() -> Self { + let mut block = Self { + kind: BlockKind::DeadBrainCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_bubble_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_bubble_coral() -> Self { + let mut block = Self { + kind: BlockKind::DeadBubbleCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_fire_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_fire_coral() -> Self { + let mut block = Self { + kind: BlockKind::DeadFireCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_horn_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_horn_coral() -> Self { + let mut block = Self { + kind: BlockKind::DeadHornCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `tube_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn tube_coral() -> Self { + let mut block = Self { + kind: BlockKind::TubeCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `brain_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn brain_coral() -> Self { + let mut block = Self { + kind: BlockKind::BrainCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `bubble_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn bubble_coral() -> Self { + let mut block = Self { + kind: BlockKind::BubbleCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `fire_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn fire_coral() -> Self { + let mut block = Self { + kind: BlockKind::FireCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `horn_coral` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn horn_coral() -> Self { + let mut block = Self { + kind: BlockKind::HornCoral, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_tube_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_tube_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadTubeCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_brain_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_brain_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadBrainCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_bubble_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_bubble_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadBubbleCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_fire_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_fire_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadFireCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_horn_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn dead_horn_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadHornCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `tube_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn tube_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::TubeCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `brain_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn brain_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::BrainCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `bubble_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn bubble_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::BubbleCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `fire_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn fire_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::FireCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `horn_coral_fan` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn horn_coral_fan() -> Self { + let mut block = Self { + kind: BlockKind::HornCoralFan, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_tube_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn dead_tube_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadTubeCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_brain_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn dead_brain_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadBrainCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_bubble_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn dead_bubble_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadBubbleCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_fire_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn dead_fire_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadFireCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `dead_horn_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn dead_horn_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::DeadHornCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `tube_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn tube_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::TubeCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `brain_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn brain_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::BrainCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `bubble_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn bubble_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::BubbleCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `fire_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn fire_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::FireCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `horn_coral_wall_fan` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: true\n"] + pub fn horn_coral_wall_fan() -> Self { + let mut block = Self { + kind: BlockKind::HornCoralWallFan, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `sea_pickle` with default state values.\nThe default state values are as follows:\n* `pickles`: 1\n* `waterlogged`: true\n"] + pub fn sea_pickle() -> Self { + let mut block = Self { + kind: BlockKind::SeaPickle, + state: 0, + }; + block.set_pickles(1i32); + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `blue_ice` with default state values."] + pub fn blue_ice() -> Self { + let mut block = Self { + kind: BlockKind::BlueIce, + state: 0, + }; + block + } + #[doc = "Returns an instance of `conduit` with default state values.\nThe default state values are as follows:\n* `waterlogged`: true\n"] + pub fn conduit() -> Self { + let mut block = Self { + kind: BlockKind::Conduit, + state: 0, + }; + block.set_waterlogged(true); + block + } + #[doc = "Returns an instance of `bamboo_sapling` with default state values."] + pub fn bamboo_sapling() -> Self { + let mut block = Self { + kind: BlockKind::BambooSapling, + state: 0, + }; + block + } + #[doc = "Returns an instance of `bamboo` with default state values.\nThe default state values are as follows:\n* `age_0_1`: 0\n* `leaves`: none\n* `stage`: 0\n"] + pub fn bamboo() -> Self { + let mut block = Self { + kind: BlockKind::Bamboo, + state: 0, + }; + block.set_age_0_1(0i32); + block.set_leaves(Leaves::None); + block.set_stage(0i32); + block + } + #[doc = "Returns an instance of `potted_bamboo` with default state values."] + pub fn potted_bamboo() -> Self { + let mut block = Self { + kind: BlockKind::PottedBamboo, + state: 0, + }; + block + } + #[doc = "Returns an instance of `void_air` with default state values."] + pub fn void_air() -> Self { + let mut block = Self { + kind: BlockKind::VoidAir, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cave_air` with default state values."] + pub fn cave_air() -> Self { + let mut block = Self { + kind: BlockKind::CaveAir, + state: 0, + }; + block + } + #[doc = "Returns an instance of `bubble_column` with default state values.\nThe default state values are as follows:\n* `drag`: true\n"] + pub fn bubble_column() -> Self { + let mut block = Self { + kind: BlockKind::BubbleColumn, + state: 0, + }; + block.set_drag(true); + block + } + #[doc = "Returns an instance of `polished_granite_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn polished_granite_stairs() -> Self { + let mut block = Self { + kind: BlockKind::PolishedGraniteStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `smooth_red_sandstone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn smooth_red_sandstone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::SmoothRedSandstoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `mossy_stone_brick_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn mossy_stone_brick_stairs() -> Self { + let mut block = Self { + kind: BlockKind::MossyStoneBrickStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_diorite_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn polished_diorite_stairs() -> Self { + let mut block = Self { + kind: BlockKind::PolishedDioriteStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `mossy_cobblestone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn mossy_cobblestone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::MossyCobblestoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `end_stone_brick_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn end_stone_brick_stairs() -> Self { + let mut block = Self { + kind: BlockKind::EndStoneBrickStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `stone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn stone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::StoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `smooth_sandstone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn smooth_sandstone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::SmoothSandstoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `smooth_quartz_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn smooth_quartz_stairs() -> Self { + let mut block = Self { + kind: BlockKind::SmoothQuartzStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `granite_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn granite_stairs() -> Self { + let mut block = Self { + kind: BlockKind::GraniteStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `andesite_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn andesite_stairs() -> Self { + let mut block = Self { + kind: BlockKind::AndesiteStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `red_nether_brick_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn red_nether_brick_stairs() -> Self { + let mut block = Self { + kind: BlockKind::RedNetherBrickStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_andesite_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn polished_andesite_stairs() -> Self { + let mut block = Self { + kind: BlockKind::PolishedAndesiteStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `diorite_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn diorite_stairs() -> Self { + let mut block = Self { + kind: BlockKind::DioriteStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_granite_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn polished_granite_slab() -> Self { + let mut block = Self { + kind: BlockKind::PolishedGraniteSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `smooth_red_sandstone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn smooth_red_sandstone_slab() -> Self { + let mut block = Self { + kind: BlockKind::SmoothRedSandstoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `mossy_stone_brick_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn mossy_stone_brick_slab() -> Self { + let mut block = Self { + kind: BlockKind::MossyStoneBrickSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_diorite_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn polished_diorite_slab() -> Self { + let mut block = Self { + kind: BlockKind::PolishedDioriteSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `mossy_cobblestone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn mossy_cobblestone_slab() -> Self { + let mut block = Self { + kind: BlockKind::MossyCobblestoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `end_stone_brick_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn end_stone_brick_slab() -> Self { + let mut block = Self { + kind: BlockKind::EndStoneBrickSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `smooth_sandstone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn smooth_sandstone_slab() -> Self { + let mut block = Self { + kind: BlockKind::SmoothSandstoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `smooth_quartz_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn smooth_quartz_slab() -> Self { + let mut block = Self { + kind: BlockKind::SmoothQuartzSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `granite_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn granite_slab() -> Self { + let mut block = Self { + kind: BlockKind::GraniteSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `andesite_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn andesite_slab() -> Self { + let mut block = Self { + kind: BlockKind::AndesiteSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `red_nether_brick_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn red_nether_brick_slab() -> Self { + let mut block = Self { + kind: BlockKind::RedNetherBrickSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_andesite_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn polished_andesite_slab() -> Self { + let mut block = Self { + kind: BlockKind::PolishedAndesiteSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `diorite_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn diorite_slab() -> Self { + let mut block = Self { + kind: BlockKind::DioriteSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `brick_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn brick_wall() -> Self { + let mut block = Self { + kind: BlockKind::BrickWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `prismarine_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn prismarine_wall() -> Self { + let mut block = Self { + kind: BlockKind::PrismarineWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `red_sandstone_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn red_sandstone_wall() -> Self { + let mut block = Self { + kind: BlockKind::RedSandstoneWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `mossy_stone_brick_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn mossy_stone_brick_wall() -> Self { + let mut block = Self { + kind: BlockKind::MossyStoneBrickWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `granite_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn granite_wall() -> Self { + let mut block = Self { + kind: BlockKind::GraniteWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `stone_brick_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn stone_brick_wall() -> Self { + let mut block = Self { + kind: BlockKind::StoneBrickWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `nether_brick_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn nether_brick_wall() -> Self { + let mut block = Self { + kind: BlockKind::NetherBrickWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `andesite_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn andesite_wall() -> Self { + let mut block = Self { + kind: BlockKind::AndesiteWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `red_nether_brick_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn red_nether_brick_wall() -> Self { + let mut block = Self { + kind: BlockKind::RedNetherBrickWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `sandstone_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn sandstone_wall() -> Self { + let mut block = Self { + kind: BlockKind::SandstoneWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `end_stone_brick_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn end_stone_brick_wall() -> Self { + let mut block = Self { + kind: BlockKind::EndStoneBrickWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `diorite_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn diorite_wall() -> Self { + let mut block = Self { + kind: BlockKind::DioriteWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `scaffolding` with default state values.\nThe default state values are as follows:\n* `bottom`: false\n* `distance_0_7`: 7\n* `waterlogged`: false\n"] + pub fn scaffolding() -> Self { + let mut block = Self { + kind: BlockKind::Scaffolding, + state: 0, + }; + block.set_bottom(false); + block.set_distance_0_7(7i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `loom` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn loom() -> Self { + let mut block = Self { + kind: BlockKind::Loom, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `barrel` with default state values.\nThe default state values are as follows:\n* `facing_cubic`: north\n* `open`: false\n"] + pub fn barrel() -> Self { + let mut block = Self { + kind: BlockKind::Barrel, + state: 0, + }; + block.set_facing_cubic(FacingCubic::North); + block.set_open(false); + block + } + #[doc = "Returns an instance of `smoker` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `lit`: false\n"] + pub fn smoker() -> Self { + let mut block = Self { + kind: BlockKind::Smoker, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_lit(false); + block + } + #[doc = "Returns an instance of `blast_furnace` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `lit`: false\n"] + pub fn blast_furnace() -> Self { + let mut block = Self { + kind: BlockKind::BlastFurnace, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_lit(false); + block + } + #[doc = "Returns an instance of `cartography_table` with default state values."] + pub fn cartography_table() -> Self { + let mut block = Self { + kind: BlockKind::CartographyTable, + state: 0, + }; + block + } + #[doc = "Returns an instance of `fletching_table` with default state values."] + pub fn fletching_table() -> Self { + let mut block = Self { + kind: BlockKind::FletchingTable, + state: 0, + }; + block + } + #[doc = "Returns an instance of `grindstone` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n"] + pub fn grindstone() -> Self { + let mut block = Self { + kind: BlockKind::Grindstone, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `lectern` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `has_book`: false\n* `powered`: false\n"] + pub fn lectern() -> Self { + let mut block = Self { + kind: BlockKind::Lectern, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_has_book(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `smithing_table` with default state values."] + pub fn smithing_table() -> Self { + let mut block = Self { + kind: BlockKind::SmithingTable, + state: 0, + }; + block + } + #[doc = "Returns an instance of `stonecutter` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n"] + pub fn stonecutter() -> Self { + let mut block = Self { + kind: BlockKind::Stonecutter, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block + } + #[doc = "Returns an instance of `bell` with default state values.\nThe default state values are as follows:\n* `attachment`: floor\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn bell() -> Self { + let mut block = Self { + kind: BlockKind::Bell, + state: 0, + }; + block.set_attachment(Attachment::Floor); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `lantern` with default state values.\nThe default state values are as follows:\n* `hanging`: false\n* `waterlogged`: false\n"] + pub fn lantern() -> Self { + let mut block = Self { + kind: BlockKind::Lantern, + state: 0, + }; + block.set_hanging(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `soul_lantern` with default state values.\nThe default state values are as follows:\n* `hanging`: false\n* `waterlogged`: false\n"] + pub fn soul_lantern() -> Self { + let mut block = Self { + kind: BlockKind::SoulLantern, + state: 0, + }; + block.set_hanging(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `campfire` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `lit`: true\n* `signal_fire`: false\n* `waterlogged`: false\n"] + pub fn campfire() -> Self { + let mut block = Self { + kind: BlockKind::Campfire, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_lit(true); + block.set_signal_fire(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `soul_campfire` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `lit`: true\n* `signal_fire`: false\n* `waterlogged`: false\n"] + pub fn soul_campfire() -> Self { + let mut block = Self { + kind: BlockKind::SoulCampfire, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_lit(true); + block.set_signal_fire(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `sweet_berry_bush` with default state values.\nThe default state values are as follows:\n* `age_0_3`: 0\n"] + pub fn sweet_berry_bush() -> Self { + let mut block = Self { + kind: BlockKind::SweetBerryBush, + state: 0, + }; + block.set_age_0_3(0i32); + block + } + #[doc = "Returns an instance of `warped_stem` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn warped_stem() -> Self { + let mut block = Self { + kind: BlockKind::WarpedStem, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_warped_stem` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_warped_stem() -> Self { + let mut block = Self { + kind: BlockKind::StrippedWarpedStem, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `warped_hyphae` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn warped_hyphae() -> Self { + let mut block = Self { + kind: BlockKind::WarpedHyphae, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_warped_hyphae` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_warped_hyphae() -> Self { + let mut block = Self { + kind: BlockKind::StrippedWarpedHyphae, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `warped_nylium` with default state values."] + pub fn warped_nylium() -> Self { + let mut block = Self { + kind: BlockKind::WarpedNylium, + state: 0, + }; + block + } + #[doc = "Returns an instance of `warped_fungus` with default state values."] + pub fn warped_fungus() -> Self { + let mut block = Self { + kind: BlockKind::WarpedFungus, + state: 0, + }; + block + } + #[doc = "Returns an instance of `warped_wart_block` with default state values."] + pub fn warped_wart_block() -> Self { + let mut block = Self { + kind: BlockKind::WarpedWartBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `warped_roots` with default state values."] + pub fn warped_roots() -> Self { + let mut block = Self { + kind: BlockKind::WarpedRoots, + state: 0, + }; + block + } + #[doc = "Returns an instance of `nether_sprouts` with default state values."] + pub fn nether_sprouts() -> Self { + let mut block = Self { + kind: BlockKind::NetherSprouts, + state: 0, + }; + block + } + #[doc = "Returns an instance of `crimson_stem` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn crimson_stem() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonStem, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_crimson_stem` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_crimson_stem() -> Self { + let mut block = Self { + kind: BlockKind::StrippedCrimsonStem, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `crimson_hyphae` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn crimson_hyphae() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonHyphae, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `stripped_crimson_hyphae` with default state values.\nThe default state values are as follows:\n* `axis_xyz`: y\n"] + pub fn stripped_crimson_hyphae() -> Self { + let mut block = Self { + kind: BlockKind::StrippedCrimsonHyphae, + state: 0, + }; + block.set_axis_xyz(AxisXyz::Y); + block + } + #[doc = "Returns an instance of `crimson_nylium` with default state values."] + pub fn crimson_nylium() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonNylium, + state: 0, + }; + block + } + #[doc = "Returns an instance of `crimson_fungus` with default state values."] + pub fn crimson_fungus() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonFungus, + state: 0, + }; + block + } + #[doc = "Returns an instance of `shroomlight` with default state values."] + pub fn shroomlight() -> Self { + let mut block = Self { + kind: BlockKind::Shroomlight, + state: 0, + }; + block + } + #[doc = "Returns an instance of `weeping_vines` with default state values.\nThe default state values are as follows:\n* `age_0_25`: 0\n"] + pub fn weeping_vines() -> Self { + let mut block = Self { + kind: BlockKind::WeepingVines, + state: 0, + }; + block.set_age_0_25(0i32); + block + } + #[doc = "Returns an instance of `weeping_vines_plant` with default state values."] + pub fn weeping_vines_plant() -> Self { + let mut block = Self { + kind: BlockKind::WeepingVinesPlant, + state: 0, + }; + block + } + #[doc = "Returns an instance of `twisting_vines` with default state values.\nThe default state values are as follows:\n* `age_0_25`: 0\n"] + pub fn twisting_vines() -> Self { + let mut block = Self { + kind: BlockKind::TwistingVines, + state: 0, + }; + block.set_age_0_25(0i32); + block + } + #[doc = "Returns an instance of `twisting_vines_plant` with default state values."] + pub fn twisting_vines_plant() -> Self { + let mut block = Self { + kind: BlockKind::TwistingVinesPlant, + state: 0, + }; + block + } + #[doc = "Returns an instance of `crimson_roots` with default state values."] + pub fn crimson_roots() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonRoots, + state: 0, + }; + block + } + #[doc = "Returns an instance of `crimson_planks` with default state values."] + pub fn crimson_planks() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonPlanks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `warped_planks` with default state values."] + pub fn warped_planks() -> Self { + let mut block = Self { + kind: BlockKind::WarpedPlanks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `crimson_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn crimson_slab() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `warped_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn warped_slab() -> Self { + let mut block = Self { + kind: BlockKind::WarpedSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `crimson_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn crimson_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonPressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `warped_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn warped_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::WarpedPressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `crimson_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn crimson_fence() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `warped_fence` with default state values.\nThe default state values are as follows:\n* `east_connected`: false\n* `north_connected`: false\n* `south_connected`: false\n* `waterlogged`: false\n* `west_connected`: false\n"] + pub fn warped_fence() -> Self { + let mut block = Self { + kind: BlockKind::WarpedFence, + state: 0, + }; + block.set_east_connected(false); + block.set_north_connected(false); + block.set_south_connected(false); + block.set_waterlogged(false); + block.set_west_connected(false); + block + } + #[doc = "Returns an instance of `crimson_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn crimson_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `warped_trapdoor` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `open`: false\n* `powered`: false\n* `waterlogged`: false\n"] + pub fn warped_trapdoor() -> Self { + let mut block = Self { + kind: BlockKind::WarpedTrapdoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_open(false); + block.set_powered(false); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `crimson_fence_gate` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `in_wall`: false\n* `open`: false\n* `powered`: false\n"] + pub fn crimson_fence_gate() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonFenceGate, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_in_wall(false); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `warped_fence_gate` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `in_wall`: false\n* `open`: false\n* `powered`: false\n"] + pub fn warped_fence_gate() -> Self { + let mut block = Self { + kind: BlockKind::WarpedFenceGate, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_in_wall(false); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `crimson_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn crimson_stairs() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `warped_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn warped_stairs() -> Self { + let mut block = Self { + kind: BlockKind::WarpedStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `crimson_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn crimson_button() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `warped_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn warped_button() -> Self { + let mut block = Self { + kind: BlockKind::WarpedButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `crimson_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn crimson_door() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `warped_door` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_upper_lower`: lower\n* `hinge`: left\n* `open`: false\n* `powered`: false\n"] + pub fn warped_door() -> Self { + let mut block = Self { + kind: BlockKind::WarpedDoor, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_upper_lower(HalfUpperLower::Lower); + block.set_hinge(Hinge::Left); + block.set_open(false); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `crimson_sign` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n* `waterlogged`: false\n"] + pub fn crimson_sign() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonSign, + state: 0, + }; + block.set_rotation(0i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `warped_sign` with default state values.\nThe default state values are as follows:\n* `rotation`: 0\n* `waterlogged`: false\n"] + pub fn warped_sign() -> Self { + let mut block = Self { + kind: BlockKind::WarpedSign, + state: 0, + }; + block.set_rotation(0i32); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `crimson_wall_sign` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn crimson_wall_sign() -> Self { + let mut block = Self { + kind: BlockKind::CrimsonWallSign, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `warped_wall_sign` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `waterlogged`: false\n"] + pub fn warped_wall_sign() -> Self { + let mut block = Self { + kind: BlockKind::WarpedWallSign, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `structure_block` with default state values.\nThe default state values are as follows:\n* `structure_block_mode`: save\n"] + pub fn structure_block() -> Self { + let mut block = Self { + kind: BlockKind::StructureBlock, + state: 0, + }; + block.set_structure_block_mode(StructureBlockMode::Save); + block + } + #[doc = "Returns an instance of `jigsaw` with default state values.\nThe default state values are as follows:\n* `orientation`: north_up\n"] + pub fn jigsaw() -> Self { + let mut block = Self { + kind: BlockKind::Jigsaw, + state: 0, + }; + block.set_orientation(Orientation::NorthUp); + block + } + #[doc = "Returns an instance of `composter` with default state values.\nThe default state values are as follows:\n* `level_0_8`: 0\n"] + pub fn composter() -> Self { + let mut block = Self { + kind: BlockKind::Composter, + state: 0, + }; + block.set_level_0_8(0i32); + block + } + #[doc = "Returns an instance of `target` with default state values.\nThe default state values are as follows:\n* `power`: 0\n"] + pub fn target() -> Self { + let mut block = Self { + kind: BlockKind::Target, + state: 0, + }; + block.set_power(0i32); + block + } + #[doc = "Returns an instance of `bee_nest` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `honey_level`: 0\n"] + pub fn bee_nest() -> Self { + let mut block = Self { + kind: BlockKind::BeeNest, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_honey_level(0i32); + block + } + #[doc = "Returns an instance of `beehive` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `honey_level`: 0\n"] + pub fn beehive() -> Self { + let mut block = Self { + kind: BlockKind::Beehive, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_honey_level(0i32); + block + } + #[doc = "Returns an instance of `honey_block` with default state values."] + pub fn honey_block() -> Self { + let mut block = Self { + kind: BlockKind::HoneyBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `honeycomb_block` with default state values."] + pub fn honeycomb_block() -> Self { + let mut block = Self { + kind: BlockKind::HoneycombBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `netherite_block` with default state values."] + pub fn netherite_block() -> Self { + let mut block = Self { + kind: BlockKind::NetheriteBlock, + state: 0, + }; + block + } + #[doc = "Returns an instance of `ancient_debris` with default state values."] + pub fn ancient_debris() -> Self { + let mut block = Self { + kind: BlockKind::AncientDebris, + state: 0, + }; + block + } + #[doc = "Returns an instance of `crying_obsidian` with default state values."] + pub fn crying_obsidian() -> Self { + let mut block = Self { + kind: BlockKind::CryingObsidian, + state: 0, + }; + block + } + #[doc = "Returns an instance of `respawn_anchor` with default state values.\nThe default state values are as follows:\n* `charges`: 0\n"] + pub fn respawn_anchor() -> Self { + let mut block = Self { + kind: BlockKind::RespawnAnchor, + state: 0, + }; + block.set_charges(0i32); + block + } + #[doc = "Returns an instance of `potted_crimson_fungus` with default state values."] + pub fn potted_crimson_fungus() -> Self { + let mut block = Self { + kind: BlockKind::PottedCrimsonFungus, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_warped_fungus` with default state values."] + pub fn potted_warped_fungus() -> Self { + let mut block = Self { + kind: BlockKind::PottedWarpedFungus, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_crimson_roots` with default state values."] + pub fn potted_crimson_roots() -> Self { + let mut block = Self { + kind: BlockKind::PottedCrimsonRoots, + state: 0, + }; + block + } + #[doc = "Returns an instance of `potted_warped_roots` with default state values."] + pub fn potted_warped_roots() -> Self { + let mut block = Self { + kind: BlockKind::PottedWarpedRoots, + state: 0, + }; + block + } + #[doc = "Returns an instance of `lodestone` with default state values."] + pub fn lodestone() -> Self { + let mut block = Self { + kind: BlockKind::Lodestone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blackstone` with default state values."] + pub fn blackstone() -> Self { + let mut block = Self { + kind: BlockKind::Blackstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `blackstone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn blackstone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::BlackstoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `blackstone_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn blackstone_wall() -> Self { + let mut block = Self { + kind: BlockKind::BlackstoneWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `blackstone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn blackstone_slab() -> Self { + let mut block = Self { + kind: BlockKind::BlackstoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_blackstone` with default state values."] + pub fn polished_blackstone() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `polished_blackstone_bricks` with default state values."] + pub fn polished_blackstone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cracked_polished_blackstone_bricks` with default state values."] + pub fn cracked_polished_blackstone_bricks() -> Self { + let mut block = Self { + kind: BlockKind::CrackedPolishedBlackstoneBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `chiseled_polished_blackstone` with default state values."] + pub fn chiseled_polished_blackstone() -> Self { + let mut block = Self { + kind: BlockKind::ChiseledPolishedBlackstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `polished_blackstone_brick_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn polished_blackstone_brick_slab() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstoneBrickSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_blackstone_brick_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn polished_blackstone_brick_stairs() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstoneBrickStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_blackstone_brick_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn polished_blackstone_brick_wall() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstoneBrickWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `gilded_blackstone` with default state values."] + pub fn gilded_blackstone() -> Self { + let mut block = Self { + kind: BlockKind::GildedBlackstone, + state: 0, + }; + block + } + #[doc = "Returns an instance of `polished_blackstone_stairs` with default state values.\nThe default state values are as follows:\n* `facing_cardinal`: north\n* `half_top_bottom`: bottom\n* `stairs_shape`: straight\n* `waterlogged`: false\n"] + pub fn polished_blackstone_stairs() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstoneStairs, + state: 0, + }; + block.set_facing_cardinal(FacingCardinal::North); + block.set_half_top_bottom(HalfTopBottom::Bottom); + block.set_stairs_shape(StairsShape::Straight); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_blackstone_slab` with default state values.\nThe default state values are as follows:\n* `slab_kind`: bottom\n* `waterlogged`: false\n"] + pub fn polished_blackstone_slab() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstoneSlab, + state: 0, + }; + block.set_slab_kind(SlabKind::Bottom); + block.set_waterlogged(false); + block + } + #[doc = "Returns an instance of `polished_blackstone_pressure_plate` with default state values.\nThe default state values are as follows:\n* `powered`: false\n"] + pub fn polished_blackstone_pressure_plate() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstonePressurePlate, + state: 0, + }; + block.set_powered(false); + block + } + #[doc = "Returns an instance of `polished_blackstone_button` with default state values.\nThe default state values are as follows:\n* `face`: wall\n* `facing_cardinal`: north\n* `powered`: false\n"] + pub fn polished_blackstone_button() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstoneButton, + state: 0, + }; + block.set_face(Face::Wall); + block.set_facing_cardinal(FacingCardinal::North); + block.set_powered(false); + block + } + #[doc = "Returns an instance of `polished_blackstone_wall` with default state values.\nThe default state values are as follows:\n* `east_nlt`: none\n* `north_nlt`: none\n* `south_nlt`: none\n* `up`: true\n* `waterlogged`: false\n* `west_nlt`: none\n"] + pub fn polished_blackstone_wall() -> Self { + let mut block = Self { + kind: BlockKind::PolishedBlackstoneWall, + state: 0, + }; + block.set_east_nlt(EastNlt::None); + block.set_north_nlt(NorthNlt::None); + block.set_south_nlt(SouthNlt::None); + block.set_up(true); + block.set_waterlogged(false); + block.set_west_nlt(WestNlt::None); + block + } + #[doc = "Returns an instance of `chiseled_nether_bricks` with default state values."] + pub fn chiseled_nether_bricks() -> Self { + let mut block = Self { + kind: BlockKind::ChiseledNetherBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `cracked_nether_bricks` with default state values."] + pub fn cracked_nether_bricks() -> Self { + let mut block = Self { + kind: BlockKind::CrackedNetherBricks, + state: 0, + }; + block + } + #[doc = "Returns an instance of `quartz_bricks` with default state values."] + pub fn quartz_bricks() -> Self { + let mut block = Self { + kind: BlockKind::QuartzBricks, + state: 0, + }; + block + } + pub fn age_0_1(self) -> Option { + BLOCK_TABLE.age_0_1(self.kind, self.state) + } + pub fn set_age_0_1(&mut self, age_0_1: i32) -> bool { + match BLOCK_TABLE.set_age_0_1(self.kind, self.state, age_0_1) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_age_0_1(mut self, age_0_1: i32) -> Self { + self.set_age_0_1(age_0_1); + self + } + pub fn age_0_15(self) -> Option { + BLOCK_TABLE.age_0_15(self.kind, self.state) + } + pub fn set_age_0_15(&mut self, age_0_15: i32) -> bool { + match BLOCK_TABLE.set_age_0_15(self.kind, self.state, age_0_15) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_age_0_15(mut self, age_0_15: i32) -> Self { + self.set_age_0_15(age_0_15); + self + } + pub fn age_0_2(self) -> Option { + BLOCK_TABLE.age_0_2(self.kind, self.state) + } + pub fn set_age_0_2(&mut self, age_0_2: i32) -> bool { + match BLOCK_TABLE.set_age_0_2(self.kind, self.state, age_0_2) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_age_0_2(mut self, age_0_2: i32) -> Self { + self.set_age_0_2(age_0_2); + self + } + pub fn age_0_25(self) -> Option { + BLOCK_TABLE.age_0_25(self.kind, self.state) + } + pub fn set_age_0_25(&mut self, age_0_25: i32) -> bool { + match BLOCK_TABLE.set_age_0_25(self.kind, self.state, age_0_25) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_age_0_25(mut self, age_0_25: i32) -> Self { + self.set_age_0_25(age_0_25); + self + } + pub fn age_0_3(self) -> Option { + BLOCK_TABLE.age_0_3(self.kind, self.state) + } + pub fn set_age_0_3(&mut self, age_0_3: i32) -> bool { + match BLOCK_TABLE.set_age_0_3(self.kind, self.state, age_0_3) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_age_0_3(mut self, age_0_3: i32) -> Self { + self.set_age_0_3(age_0_3); + self + } + pub fn age_0_5(self) -> Option { + BLOCK_TABLE.age_0_5(self.kind, self.state) + } + pub fn set_age_0_5(&mut self, age_0_5: i32) -> bool { + match BLOCK_TABLE.set_age_0_5(self.kind, self.state, age_0_5) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_age_0_5(mut self, age_0_5: i32) -> Self { + self.set_age_0_5(age_0_5); + self + } + pub fn age_0_7(self) -> Option { + BLOCK_TABLE.age_0_7(self.kind, self.state) + } + pub fn set_age_0_7(&mut self, age_0_7: i32) -> bool { + match BLOCK_TABLE.set_age_0_7(self.kind, self.state, age_0_7) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_age_0_7(mut self, age_0_7: i32) -> Self { + self.set_age_0_7(age_0_7); + self + } + pub fn attached(self) -> Option { + BLOCK_TABLE.attached(self.kind, self.state) + } + pub fn set_attached(&mut self, attached: bool) -> bool { + match BLOCK_TABLE.set_attached(self.kind, self.state, attached) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_attached(mut self, attached: bool) -> Self { + self.set_attached(attached); + self + } + pub fn attachment(self) -> Option { + BLOCK_TABLE.attachment(self.kind, self.state) + } + pub fn set_attachment(&mut self, attachment: Attachment) -> bool { + match BLOCK_TABLE.set_attachment(self.kind, self.state, attachment) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_attachment(mut self, attachment: Attachment) -> Self { + self.set_attachment(attachment); + self + } + pub fn axis_xyz(self) -> Option { + BLOCK_TABLE.axis_xyz(self.kind, self.state) + } + pub fn set_axis_xyz(&mut self, axis_xyz: AxisXyz) -> bool { + match BLOCK_TABLE.set_axis_xyz(self.kind, self.state, axis_xyz) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_axis_xyz(mut self, axis_xyz: AxisXyz) -> Self { + self.set_axis_xyz(axis_xyz); + self + } + pub fn axis_xz(self) -> Option { + BLOCK_TABLE.axis_xz(self.kind, self.state) + } + pub fn set_axis_xz(&mut self, axis_xz: AxisXz) -> bool { + match BLOCK_TABLE.set_axis_xz(self.kind, self.state, axis_xz) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_axis_xz(mut self, axis_xz: AxisXz) -> Self { + self.set_axis_xz(axis_xz); + self + } + pub fn bites(self) -> Option { + BLOCK_TABLE.bites(self.kind, self.state) + } + pub fn set_bites(&mut self, bites: i32) -> bool { + match BLOCK_TABLE.set_bites(self.kind, self.state, bites) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_bites(mut self, bites: i32) -> Self { + self.set_bites(bites); + self + } + pub fn bottom(self) -> Option { + BLOCK_TABLE.bottom(self.kind, self.state) + } + pub fn set_bottom(&mut self, bottom: bool) -> bool { + match BLOCK_TABLE.set_bottom(self.kind, self.state, bottom) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_bottom(mut self, bottom: bool) -> Self { + self.set_bottom(bottom); + self + } + pub fn cauldron_level(self) -> Option { + BLOCK_TABLE.cauldron_level(self.kind, self.state) + } + pub fn set_cauldron_level(&mut self, cauldron_level: i32) -> bool { + match BLOCK_TABLE.set_cauldron_level(self.kind, self.state, cauldron_level) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_cauldron_level(mut self, cauldron_level: i32) -> Self { + self.set_cauldron_level(cauldron_level); + self + } + pub fn charges(self) -> Option { + BLOCK_TABLE.charges(self.kind, self.state) + } + pub fn set_charges(&mut self, charges: i32) -> bool { + match BLOCK_TABLE.set_charges(self.kind, self.state, charges) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_charges(mut self, charges: i32) -> Self { + self.set_charges(charges); + self + } + pub fn chest_kind(self) -> Option { + BLOCK_TABLE.chest_kind(self.kind, self.state) + } + pub fn set_chest_kind(&mut self, chest_kind: ChestKind) -> bool { + match BLOCK_TABLE.set_chest_kind(self.kind, self.state, chest_kind) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_chest_kind(mut self, chest_kind: ChestKind) -> Self { + self.set_chest_kind(chest_kind); + self + } + pub fn comparator_mode(self) -> Option { + BLOCK_TABLE.comparator_mode(self.kind, self.state) + } + pub fn set_comparator_mode(&mut self, comparator_mode: ComparatorMode) -> bool { + match BLOCK_TABLE.set_comparator_mode(self.kind, self.state, comparator_mode) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_comparator_mode(mut self, comparator_mode: ComparatorMode) -> Self { + self.set_comparator_mode(comparator_mode); + self + } + pub fn conditional(self) -> Option { + BLOCK_TABLE.conditional(self.kind, self.state) + } + pub fn set_conditional(&mut self, conditional: bool) -> bool { + match BLOCK_TABLE.set_conditional(self.kind, self.state, conditional) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_conditional(mut self, conditional: bool) -> Self { + self.set_conditional(conditional); + self + } + pub fn delay(self) -> Option { + BLOCK_TABLE.delay(self.kind, self.state) + } + pub fn set_delay(&mut self, delay: i32) -> bool { + match BLOCK_TABLE.set_delay(self.kind, self.state, delay) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_delay(mut self, delay: i32) -> Self { + self.set_delay(delay); + self + } + pub fn disarmed(self) -> Option { + BLOCK_TABLE.disarmed(self.kind, self.state) + } + pub fn set_disarmed(&mut self, disarmed: bool) -> bool { + match BLOCK_TABLE.set_disarmed(self.kind, self.state, disarmed) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_disarmed(mut self, disarmed: bool) -> Self { + self.set_disarmed(disarmed); + self + } + pub fn distance_0_7(self) -> Option { + BLOCK_TABLE.distance_0_7(self.kind, self.state) + } + pub fn set_distance_0_7(&mut self, distance_0_7: i32) -> bool { + match BLOCK_TABLE.set_distance_0_7(self.kind, self.state, distance_0_7) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_distance_0_7(mut self, distance_0_7: i32) -> Self { + self.set_distance_0_7(distance_0_7); + self + } + pub fn distance_1_7(self) -> Option { + BLOCK_TABLE.distance_1_7(self.kind, self.state) + } + pub fn set_distance_1_7(&mut self, distance_1_7: i32) -> bool { + match BLOCK_TABLE.set_distance_1_7(self.kind, self.state, distance_1_7) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_distance_1_7(mut self, distance_1_7: i32) -> Self { + self.set_distance_1_7(distance_1_7); + self + } + pub fn down(self) -> Option { + BLOCK_TABLE.down(self.kind, self.state) + } + pub fn set_down(&mut self, down: bool) -> bool { + match BLOCK_TABLE.set_down(self.kind, self.state, down) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_down(mut self, down: bool) -> Self { + self.set_down(down); + self + } + pub fn drag(self) -> Option { + BLOCK_TABLE.drag(self.kind, self.state) + } + pub fn set_drag(&mut self, drag: bool) -> bool { + match BLOCK_TABLE.set_drag(self.kind, self.state, drag) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_drag(mut self, drag: bool) -> Self { + self.set_drag(drag); + self + } + pub fn east_connected(self) -> Option { + BLOCK_TABLE.east_connected(self.kind, self.state) + } + pub fn set_east_connected(&mut self, east_connected: bool) -> bool { + match BLOCK_TABLE.set_east_connected(self.kind, self.state, east_connected) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_east_connected(mut self, east_connected: bool) -> Self { + self.set_east_connected(east_connected); + self + } + pub fn east_nlt(self) -> Option { + BLOCK_TABLE.east_nlt(self.kind, self.state) + } + pub fn set_east_nlt(&mut self, east_nlt: EastNlt) -> bool { + match BLOCK_TABLE.set_east_nlt(self.kind, self.state, east_nlt) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_east_nlt(mut self, east_nlt: EastNlt) -> Self { + self.set_east_nlt(east_nlt); + self + } + pub fn east_wire(self) -> Option { + BLOCK_TABLE.east_wire(self.kind, self.state) + } + pub fn set_east_wire(&mut self, east_wire: EastWire) -> bool { + match BLOCK_TABLE.set_east_wire(self.kind, self.state, east_wire) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_east_wire(mut self, east_wire: EastWire) -> Self { + self.set_east_wire(east_wire); + self + } + pub fn eggs(self) -> Option { + BLOCK_TABLE.eggs(self.kind, self.state) + } + pub fn set_eggs(&mut self, eggs: i32) -> bool { + match BLOCK_TABLE.set_eggs(self.kind, self.state, eggs) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_eggs(mut self, eggs: i32) -> Self { + self.set_eggs(eggs); + self + } + pub fn enabled(self) -> Option { + BLOCK_TABLE.enabled(self.kind, self.state) + } + pub fn set_enabled(&mut self, enabled: bool) -> bool { + match BLOCK_TABLE.set_enabled(self.kind, self.state, enabled) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_enabled(mut self, enabled: bool) -> Self { + self.set_enabled(enabled); + self + } + pub fn extended(self) -> Option { + BLOCK_TABLE.extended(self.kind, self.state) + } + pub fn set_extended(&mut self, extended: bool) -> bool { + match BLOCK_TABLE.set_extended(self.kind, self.state, extended) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_extended(mut self, extended: bool) -> Self { + self.set_extended(extended); + self + } + pub fn eye(self) -> Option { + BLOCK_TABLE.eye(self.kind, self.state) + } + pub fn set_eye(&mut self, eye: bool) -> bool { + match BLOCK_TABLE.set_eye(self.kind, self.state, eye) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_eye(mut self, eye: bool) -> Self { + self.set_eye(eye); + self + } + pub fn face(self) -> Option { + BLOCK_TABLE.face(self.kind, self.state) + } + pub fn set_face(&mut self, face: Face) -> bool { + match BLOCK_TABLE.set_face(self.kind, self.state, face) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_face(mut self, face: Face) -> Self { + self.set_face(face); + self + } + pub fn facing_cardinal(self) -> Option { + BLOCK_TABLE.facing_cardinal(self.kind, self.state) + } + pub fn set_facing_cardinal(&mut self, facing_cardinal: FacingCardinal) -> bool { + match BLOCK_TABLE.set_facing_cardinal(self.kind, self.state, facing_cardinal) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_facing_cardinal(mut self, facing_cardinal: FacingCardinal) -> Self { + self.set_facing_cardinal(facing_cardinal); + self + } + pub fn facing_cardinal_and_down(self) -> Option { + BLOCK_TABLE.facing_cardinal_and_down(self.kind, self.state) + } + pub fn set_facing_cardinal_and_down( + &mut self, + facing_cardinal_and_down: FacingCardinalAndDown, + ) -> bool { + match BLOCK_TABLE.set_facing_cardinal_and_down( + self.kind, + self.state, + facing_cardinal_and_down, + ) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_facing_cardinal_and_down( + mut self, + facing_cardinal_and_down: FacingCardinalAndDown, + ) -> Self { + self.set_facing_cardinal_and_down(facing_cardinal_and_down); + self + } + pub fn facing_cubic(self) -> Option { + BLOCK_TABLE.facing_cubic(self.kind, self.state) + } + pub fn set_facing_cubic(&mut self, facing_cubic: FacingCubic) -> bool { + match BLOCK_TABLE.set_facing_cubic(self.kind, self.state, facing_cubic) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_facing_cubic(mut self, facing_cubic: FacingCubic) -> Self { + self.set_facing_cubic(facing_cubic); + self + } + pub fn half_top_bottom(self) -> Option { + BLOCK_TABLE.half_top_bottom(self.kind, self.state) + } + pub fn set_half_top_bottom(&mut self, half_top_bottom: HalfTopBottom) -> bool { + match BLOCK_TABLE.set_half_top_bottom(self.kind, self.state, half_top_bottom) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_half_top_bottom(mut self, half_top_bottom: HalfTopBottom) -> Self { + self.set_half_top_bottom(half_top_bottom); + self + } + pub fn half_upper_lower(self) -> Option { + BLOCK_TABLE.half_upper_lower(self.kind, self.state) + } + pub fn set_half_upper_lower(&mut self, half_upper_lower: HalfUpperLower) -> bool { + match BLOCK_TABLE.set_half_upper_lower(self.kind, self.state, half_upper_lower) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_half_upper_lower(mut self, half_upper_lower: HalfUpperLower) -> Self { + self.set_half_upper_lower(half_upper_lower); + self + } + pub fn hanging(self) -> Option { + BLOCK_TABLE.hanging(self.kind, self.state) + } + pub fn set_hanging(&mut self, hanging: bool) -> bool { + match BLOCK_TABLE.set_hanging(self.kind, self.state, hanging) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_hanging(mut self, hanging: bool) -> Self { + self.set_hanging(hanging); + self + } + pub fn has_book(self) -> Option { + BLOCK_TABLE.has_book(self.kind, self.state) + } + pub fn set_has_book(&mut self, has_book: bool) -> bool { + match BLOCK_TABLE.set_has_book(self.kind, self.state, has_book) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_has_book(mut self, has_book: bool) -> Self { + self.set_has_book(has_book); + self + } + pub fn has_bottle_0(self) -> Option { + BLOCK_TABLE.has_bottle_0(self.kind, self.state) + } + pub fn set_has_bottle_0(&mut self, has_bottle_0: bool) -> bool { + match BLOCK_TABLE.set_has_bottle_0(self.kind, self.state, has_bottle_0) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_has_bottle_0(mut self, has_bottle_0: bool) -> Self { + self.set_has_bottle_0(has_bottle_0); + self + } + pub fn has_bottle_1(self) -> Option { + BLOCK_TABLE.has_bottle_1(self.kind, self.state) + } + pub fn set_has_bottle_1(&mut self, has_bottle_1: bool) -> bool { + match BLOCK_TABLE.set_has_bottle_1(self.kind, self.state, has_bottle_1) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_has_bottle_1(mut self, has_bottle_1: bool) -> Self { + self.set_has_bottle_1(has_bottle_1); + self + } + pub fn has_bottle_2(self) -> Option { + BLOCK_TABLE.has_bottle_2(self.kind, self.state) + } + pub fn set_has_bottle_2(&mut self, has_bottle_2: bool) -> bool { + match BLOCK_TABLE.set_has_bottle_2(self.kind, self.state, has_bottle_2) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_has_bottle_2(mut self, has_bottle_2: bool) -> Self { + self.set_has_bottle_2(has_bottle_2); + self + } + pub fn has_record(self) -> Option { + BLOCK_TABLE.has_record(self.kind, self.state) + } + pub fn set_has_record(&mut self, has_record: bool) -> bool { + match BLOCK_TABLE.set_has_record(self.kind, self.state, has_record) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_has_record(mut self, has_record: bool) -> Self { + self.set_has_record(has_record); + self + } + pub fn hatch(self) -> Option { + BLOCK_TABLE.hatch(self.kind, self.state) + } + pub fn set_hatch(&mut self, hatch: i32) -> bool { + match BLOCK_TABLE.set_hatch(self.kind, self.state, hatch) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_hatch(mut self, hatch: i32) -> Self { + self.set_hatch(hatch); + self + } + pub fn hinge(self) -> Option { + BLOCK_TABLE.hinge(self.kind, self.state) + } + pub fn set_hinge(&mut self, hinge: Hinge) -> bool { + match BLOCK_TABLE.set_hinge(self.kind, self.state, hinge) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_hinge(mut self, hinge: Hinge) -> Self { + self.set_hinge(hinge); + self + } + pub fn honey_level(self) -> Option { + BLOCK_TABLE.honey_level(self.kind, self.state) + } + pub fn set_honey_level(&mut self, honey_level: i32) -> bool { + match BLOCK_TABLE.set_honey_level(self.kind, self.state, honey_level) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_honey_level(mut self, honey_level: i32) -> Self { + self.set_honey_level(honey_level); + self + } + pub fn in_wall(self) -> Option { + BLOCK_TABLE.in_wall(self.kind, self.state) + } + pub fn set_in_wall(&mut self, in_wall: bool) -> bool { + match BLOCK_TABLE.set_in_wall(self.kind, self.state, in_wall) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_in_wall(mut self, in_wall: bool) -> Self { + self.set_in_wall(in_wall); + self + } + pub fn instrument(self) -> Option { + BLOCK_TABLE.instrument(self.kind, self.state) + } + pub fn set_instrument(&mut self, instrument: Instrument) -> bool { + match BLOCK_TABLE.set_instrument(self.kind, self.state, instrument) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_instrument(mut self, instrument: Instrument) -> Self { + self.set_instrument(instrument); + self + } + pub fn inverted(self) -> Option { + BLOCK_TABLE.inverted(self.kind, self.state) + } + pub fn set_inverted(&mut self, inverted: bool) -> bool { + match BLOCK_TABLE.set_inverted(self.kind, self.state, inverted) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_inverted(mut self, inverted: bool) -> Self { + self.set_inverted(inverted); + self + } + pub fn layers(self) -> Option { + BLOCK_TABLE.layers(self.kind, self.state) + } + pub fn set_layers(&mut self, layers: i32) -> bool { + match BLOCK_TABLE.set_layers(self.kind, self.state, layers) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_layers(mut self, layers: i32) -> Self { + self.set_layers(layers); + self + } + pub fn leaves(self) -> Option { + BLOCK_TABLE.leaves(self.kind, self.state) + } + pub fn set_leaves(&mut self, leaves: Leaves) -> bool { + match BLOCK_TABLE.set_leaves(self.kind, self.state, leaves) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_leaves(mut self, leaves: Leaves) -> Self { + self.set_leaves(leaves); + self + } + pub fn level_0_8(self) -> Option { + BLOCK_TABLE.level_0_8(self.kind, self.state) + } + pub fn set_level_0_8(&mut self, level_0_8: i32) -> bool { + match BLOCK_TABLE.set_level_0_8(self.kind, self.state, level_0_8) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_level_0_8(mut self, level_0_8: i32) -> Self { + self.set_level_0_8(level_0_8); + self + } + pub fn lit(self) -> Option { + BLOCK_TABLE.lit(self.kind, self.state) + } + pub fn set_lit(&mut self, lit: bool) -> bool { + match BLOCK_TABLE.set_lit(self.kind, self.state, lit) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_lit(mut self, lit: bool) -> Self { + self.set_lit(lit); + self + } + pub fn locked(self) -> Option { + BLOCK_TABLE.locked(self.kind, self.state) + } + pub fn set_locked(&mut self, locked: bool) -> bool { + match BLOCK_TABLE.set_locked(self.kind, self.state, locked) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_locked(mut self, locked: bool) -> Self { + self.set_locked(locked); + self + } + pub fn moisture(self) -> Option { + BLOCK_TABLE.moisture(self.kind, self.state) + } + pub fn set_moisture(&mut self, moisture: i32) -> bool { + match BLOCK_TABLE.set_moisture(self.kind, self.state, moisture) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_moisture(mut self, moisture: i32) -> Self { + self.set_moisture(moisture); + self + } + pub fn north_connected(self) -> Option { + BLOCK_TABLE.north_connected(self.kind, self.state) + } + pub fn set_north_connected(&mut self, north_connected: bool) -> bool { + match BLOCK_TABLE.set_north_connected(self.kind, self.state, north_connected) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_north_connected(mut self, north_connected: bool) -> Self { + self.set_north_connected(north_connected); + self + } + pub fn north_nlt(self) -> Option { + BLOCK_TABLE.north_nlt(self.kind, self.state) + } + pub fn set_north_nlt(&mut self, north_nlt: NorthNlt) -> bool { + match BLOCK_TABLE.set_north_nlt(self.kind, self.state, north_nlt) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_north_nlt(mut self, north_nlt: NorthNlt) -> Self { + self.set_north_nlt(north_nlt); + self + } + pub fn north_wire(self) -> Option { + BLOCK_TABLE.north_wire(self.kind, self.state) + } + pub fn set_north_wire(&mut self, north_wire: NorthWire) -> bool { + match BLOCK_TABLE.set_north_wire(self.kind, self.state, north_wire) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_north_wire(mut self, north_wire: NorthWire) -> Self { + self.set_north_wire(north_wire); + self + } + pub fn note(self) -> Option { + BLOCK_TABLE.note(self.kind, self.state) + } + pub fn set_note(&mut self, note: i32) -> bool { + match BLOCK_TABLE.set_note(self.kind, self.state, note) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_note(mut self, note: i32) -> Self { + self.set_note(note); + self + } + pub fn occupied(self) -> Option { + BLOCK_TABLE.occupied(self.kind, self.state) + } + pub fn set_occupied(&mut self, occupied: bool) -> bool { + match BLOCK_TABLE.set_occupied(self.kind, self.state, occupied) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_occupied(mut self, occupied: bool) -> Self { + self.set_occupied(occupied); + self + } + pub fn open(self) -> Option { + BLOCK_TABLE.open(self.kind, self.state) + } + pub fn set_open(&mut self, open: bool) -> bool { + match BLOCK_TABLE.set_open(self.kind, self.state, open) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_open(mut self, open: bool) -> Self { + self.set_open(open); + self + } + pub fn orientation(self) -> Option { + BLOCK_TABLE.orientation(self.kind, self.state) + } + pub fn set_orientation(&mut self, orientation: Orientation) -> bool { + match BLOCK_TABLE.set_orientation(self.kind, self.state, orientation) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_orientation(mut self, orientation: Orientation) -> Self { + self.set_orientation(orientation); + self + } + pub fn part(self) -> Option { + BLOCK_TABLE.part(self.kind, self.state) + } + pub fn set_part(&mut self, part: Part) -> bool { + match BLOCK_TABLE.set_part(self.kind, self.state, part) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_part(mut self, part: Part) -> Self { + self.set_part(part); + self + } + pub fn persistent(self) -> Option { + BLOCK_TABLE.persistent(self.kind, self.state) + } + pub fn set_persistent(&mut self, persistent: bool) -> bool { + match BLOCK_TABLE.set_persistent(self.kind, self.state, persistent) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_persistent(mut self, persistent: bool) -> Self { + self.set_persistent(persistent); + self + } + pub fn pickles(self) -> Option { + BLOCK_TABLE.pickles(self.kind, self.state) + } + pub fn set_pickles(&mut self, pickles: i32) -> bool { + match BLOCK_TABLE.set_pickles(self.kind, self.state, pickles) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_pickles(mut self, pickles: i32) -> Self { + self.set_pickles(pickles); + self + } + pub fn piston_kind(self) -> Option { + BLOCK_TABLE.piston_kind(self.kind, self.state) + } + pub fn set_piston_kind(&mut self, piston_kind: PistonKind) -> bool { + match BLOCK_TABLE.set_piston_kind(self.kind, self.state, piston_kind) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_piston_kind(mut self, piston_kind: PistonKind) -> Self { + self.set_piston_kind(piston_kind); + self + } + pub fn power(self) -> Option { + BLOCK_TABLE.power(self.kind, self.state) + } + pub fn set_power(&mut self, power: i32) -> bool { + match BLOCK_TABLE.set_power(self.kind, self.state, power) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_power(mut self, power: i32) -> Self { + self.set_power(power); + self + } + pub fn powered(self) -> Option { + BLOCK_TABLE.powered(self.kind, self.state) + } + pub fn set_powered(&mut self, powered: bool) -> bool { + match BLOCK_TABLE.set_powered(self.kind, self.state, powered) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_powered(mut self, powered: bool) -> Self { + self.set_powered(powered); + self + } + pub fn powered_rail_shape(self) -> Option { + BLOCK_TABLE.powered_rail_shape(self.kind, self.state) + } + pub fn set_powered_rail_shape(&mut self, powered_rail_shape: PoweredRailShape) -> bool { + match BLOCK_TABLE.set_powered_rail_shape(self.kind, self.state, powered_rail_shape) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_powered_rail_shape(mut self, powered_rail_shape: PoweredRailShape) -> Self { + self.set_powered_rail_shape(powered_rail_shape); + self + } + pub fn rail_shape(self) -> Option { + BLOCK_TABLE.rail_shape(self.kind, self.state) + } + pub fn set_rail_shape(&mut self, rail_shape: RailShape) -> bool { + match BLOCK_TABLE.set_rail_shape(self.kind, self.state, rail_shape) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_rail_shape(mut self, rail_shape: RailShape) -> Self { + self.set_rail_shape(rail_shape); + self + } + pub fn rotation(self) -> Option { + BLOCK_TABLE.rotation(self.kind, self.state) + } + pub fn set_rotation(&mut self, rotation: i32) -> bool { + match BLOCK_TABLE.set_rotation(self.kind, self.state, rotation) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_rotation(mut self, rotation: i32) -> Self { + self.set_rotation(rotation); + self + } + pub fn short(self) -> Option { + BLOCK_TABLE.short(self.kind, self.state) + } + pub fn set_short(&mut self, short: bool) -> bool { + match BLOCK_TABLE.set_short(self.kind, self.state, short) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_short(mut self, short: bool) -> Self { + self.set_short(short); + self + } + pub fn signal_fire(self) -> Option { + BLOCK_TABLE.signal_fire(self.kind, self.state) + } + pub fn set_signal_fire(&mut self, signal_fire: bool) -> bool { + match BLOCK_TABLE.set_signal_fire(self.kind, self.state, signal_fire) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_signal_fire(mut self, signal_fire: bool) -> Self { + self.set_signal_fire(signal_fire); + self + } + pub fn slab_kind(self) -> Option { + BLOCK_TABLE.slab_kind(self.kind, self.state) + } + pub fn set_slab_kind(&mut self, slab_kind: SlabKind) -> bool { + match BLOCK_TABLE.set_slab_kind(self.kind, self.state, slab_kind) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_slab_kind(mut self, slab_kind: SlabKind) -> Self { + self.set_slab_kind(slab_kind); + self + } + pub fn snowy(self) -> Option { + BLOCK_TABLE.snowy(self.kind, self.state) + } + pub fn set_snowy(&mut self, snowy: bool) -> bool { + match BLOCK_TABLE.set_snowy(self.kind, self.state, snowy) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_snowy(mut self, snowy: bool) -> Self { + self.set_snowy(snowy); + self + } + pub fn south_connected(self) -> Option { + BLOCK_TABLE.south_connected(self.kind, self.state) + } + pub fn set_south_connected(&mut self, south_connected: bool) -> bool { + match BLOCK_TABLE.set_south_connected(self.kind, self.state, south_connected) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_south_connected(mut self, south_connected: bool) -> Self { + self.set_south_connected(south_connected); + self + } + pub fn south_nlt(self) -> Option { + BLOCK_TABLE.south_nlt(self.kind, self.state) + } + pub fn set_south_nlt(&mut self, south_nlt: SouthNlt) -> bool { + match BLOCK_TABLE.set_south_nlt(self.kind, self.state, south_nlt) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_south_nlt(mut self, south_nlt: SouthNlt) -> Self { + self.set_south_nlt(south_nlt); + self + } + pub fn south_wire(self) -> Option { + BLOCK_TABLE.south_wire(self.kind, self.state) + } + pub fn set_south_wire(&mut self, south_wire: SouthWire) -> bool { + match BLOCK_TABLE.set_south_wire(self.kind, self.state, south_wire) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_south_wire(mut self, south_wire: SouthWire) -> Self { + self.set_south_wire(south_wire); + self + } + pub fn stage(self) -> Option { + BLOCK_TABLE.stage(self.kind, self.state) + } + pub fn set_stage(&mut self, stage: i32) -> bool { + match BLOCK_TABLE.set_stage(self.kind, self.state, stage) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_stage(mut self, stage: i32) -> Self { + self.set_stage(stage); + self + } + pub fn stairs_shape(self) -> Option { + BLOCK_TABLE.stairs_shape(self.kind, self.state) + } + pub fn set_stairs_shape(&mut self, stairs_shape: StairsShape) -> bool { + match BLOCK_TABLE.set_stairs_shape(self.kind, self.state, stairs_shape) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_stairs_shape(mut self, stairs_shape: StairsShape) -> Self { + self.set_stairs_shape(stairs_shape); + self + } + pub fn structure_block_mode(self) -> Option { + BLOCK_TABLE.structure_block_mode(self.kind, self.state) + } + pub fn set_structure_block_mode(&mut self, structure_block_mode: StructureBlockMode) -> bool { + match BLOCK_TABLE.set_structure_block_mode(self.kind, self.state, structure_block_mode) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_structure_block_mode(mut self, structure_block_mode: StructureBlockMode) -> Self { + self.set_structure_block_mode(structure_block_mode); + self + } + pub fn triggered(self) -> Option { + BLOCK_TABLE.triggered(self.kind, self.state) + } + pub fn set_triggered(&mut self, triggered: bool) -> bool { + match BLOCK_TABLE.set_triggered(self.kind, self.state, triggered) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_triggered(mut self, triggered: bool) -> Self { + self.set_triggered(triggered); + self + } + pub fn unstable(self) -> Option { + BLOCK_TABLE.unstable(self.kind, self.state) + } + pub fn set_unstable(&mut self, unstable: bool) -> bool { + match BLOCK_TABLE.set_unstable(self.kind, self.state, unstable) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_unstable(mut self, unstable: bool) -> Self { + self.set_unstable(unstable); + self + } + pub fn up(self) -> Option { + BLOCK_TABLE.up(self.kind, self.state) + } + pub fn set_up(&mut self, up: bool) -> bool { + match BLOCK_TABLE.set_up(self.kind, self.state, up) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_up(mut self, up: bool) -> Self { + self.set_up(up); + self + } + pub fn water_level(self) -> Option { + BLOCK_TABLE.water_level(self.kind, self.state) + } + pub fn set_water_level(&mut self, water_level: i32) -> bool { + match BLOCK_TABLE.set_water_level(self.kind, self.state, water_level) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_water_level(mut self, water_level: i32) -> Self { + self.set_water_level(water_level); + self + } + pub fn waterlogged(self) -> Option { + BLOCK_TABLE.waterlogged(self.kind, self.state) + } + pub fn set_waterlogged(&mut self, waterlogged: bool) -> bool { + match BLOCK_TABLE.set_waterlogged(self.kind, self.state, waterlogged) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_waterlogged(mut self, waterlogged: bool) -> Self { + self.set_waterlogged(waterlogged); + self + } + pub fn west_connected(self) -> Option { + BLOCK_TABLE.west_connected(self.kind, self.state) + } + pub fn set_west_connected(&mut self, west_connected: bool) -> bool { + match BLOCK_TABLE.set_west_connected(self.kind, self.state, west_connected) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_west_connected(mut self, west_connected: bool) -> Self { + self.set_west_connected(west_connected); + self + } + pub fn west_nlt(self) -> Option { + BLOCK_TABLE.west_nlt(self.kind, self.state) + } + pub fn set_west_nlt(&mut self, west_nlt: WestNlt) -> bool { + match BLOCK_TABLE.set_west_nlt(self.kind, self.state, west_nlt) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_west_nlt(mut self, west_nlt: WestNlt) -> Self { + self.set_west_nlt(west_nlt); + self + } + pub fn west_wire(self) -> Option { + BLOCK_TABLE.west_wire(self.kind, self.state) + } + pub fn set_west_wire(&mut self, west_wire: WestWire) -> bool { + match BLOCK_TABLE.set_west_wire(self.kind, self.state, west_wire) { + Some(new_state) => { + self.state = new_state; + true + } + None => false, + } + } + pub fn with_west_wire(mut self, west_wire: WestWire) -> Self { + self.set_west_wire(west_wire); + self + } + #[doc = "Returns the identifier of this block. For example, returns `minecraft::air` for an air block."] + pub fn identifier(self) -> &'static str { + match self.kind { + BlockKind::Air => "minecraft:air", + BlockKind::Stone => "minecraft:stone", + BlockKind::Granite => "minecraft:granite", + BlockKind::PolishedGranite => "minecraft:polished_granite", + BlockKind::Diorite => "minecraft:diorite", + BlockKind::PolishedDiorite => "minecraft:polished_diorite", + BlockKind::Andesite => "minecraft:andesite", + BlockKind::PolishedAndesite => "minecraft:polished_andesite", + BlockKind::GrassBlock => "minecraft:grass_block", + BlockKind::Dirt => "minecraft:dirt", + BlockKind::CoarseDirt => "minecraft:coarse_dirt", + BlockKind::Podzol => "minecraft:podzol", + BlockKind::Cobblestone => "minecraft:cobblestone", + BlockKind::OakPlanks => "minecraft:oak_planks", + BlockKind::SprucePlanks => "minecraft:spruce_planks", + BlockKind::BirchPlanks => "minecraft:birch_planks", + BlockKind::JunglePlanks => "minecraft:jungle_planks", + BlockKind::AcaciaPlanks => "minecraft:acacia_planks", + BlockKind::DarkOakPlanks => "minecraft:dark_oak_planks", + BlockKind::OakSapling => "minecraft:oak_sapling", + BlockKind::SpruceSapling => "minecraft:spruce_sapling", + BlockKind::BirchSapling => "minecraft:birch_sapling", + BlockKind::JungleSapling => "minecraft:jungle_sapling", + BlockKind::AcaciaSapling => "minecraft:acacia_sapling", + BlockKind::DarkOakSapling => "minecraft:dark_oak_sapling", + BlockKind::Bedrock => "minecraft:bedrock", + BlockKind::Water => "minecraft:water", + BlockKind::Lava => "minecraft:lava", + BlockKind::Sand => "minecraft:sand", + BlockKind::RedSand => "minecraft:red_sand", + BlockKind::Gravel => "minecraft:gravel", + BlockKind::GoldOre => "minecraft:gold_ore", + BlockKind::IronOre => "minecraft:iron_ore", + BlockKind::CoalOre => "minecraft:coal_ore", + BlockKind::NetherGoldOre => "minecraft:nether_gold_ore", + BlockKind::OakLog => "minecraft:oak_log", + BlockKind::SpruceLog => "minecraft:spruce_log", + BlockKind::BirchLog => "minecraft:birch_log", + BlockKind::JungleLog => "minecraft:jungle_log", + BlockKind::AcaciaLog => "minecraft:acacia_log", + BlockKind::DarkOakLog => "minecraft:dark_oak_log", + BlockKind::StrippedSpruceLog => "minecraft:stripped_spruce_log", + BlockKind::StrippedBirchLog => "minecraft:stripped_birch_log", + BlockKind::StrippedJungleLog => "minecraft:stripped_jungle_log", + BlockKind::StrippedAcaciaLog => "minecraft:stripped_acacia_log", + BlockKind::StrippedDarkOakLog => "minecraft:stripped_dark_oak_log", + BlockKind::StrippedOakLog => "minecraft:stripped_oak_log", + BlockKind::OakWood => "minecraft:oak_wood", + BlockKind::SpruceWood => "minecraft:spruce_wood", + BlockKind::BirchWood => "minecraft:birch_wood", + BlockKind::JungleWood => "minecraft:jungle_wood", + BlockKind::AcaciaWood => "minecraft:acacia_wood", + BlockKind::DarkOakWood => "minecraft:dark_oak_wood", + BlockKind::StrippedOakWood => "minecraft:stripped_oak_wood", + BlockKind::StrippedSpruceWood => "minecraft:stripped_spruce_wood", + BlockKind::StrippedBirchWood => "minecraft:stripped_birch_wood", + BlockKind::StrippedJungleWood => "minecraft:stripped_jungle_wood", + BlockKind::StrippedAcaciaWood => "minecraft:stripped_acacia_wood", + BlockKind::StrippedDarkOakWood => "minecraft:stripped_dark_oak_wood", + BlockKind::OakLeaves => "minecraft:oak_leaves", + BlockKind::SpruceLeaves => "minecraft:spruce_leaves", + BlockKind::BirchLeaves => "minecraft:birch_leaves", + BlockKind::JungleLeaves => "minecraft:jungle_leaves", + BlockKind::AcaciaLeaves => "minecraft:acacia_leaves", + BlockKind::DarkOakLeaves => "minecraft:dark_oak_leaves", + BlockKind::Sponge => "minecraft:sponge", + BlockKind::WetSponge => "minecraft:wet_sponge", + BlockKind::Glass => "minecraft:glass", + BlockKind::LapisOre => "minecraft:lapis_ore", + BlockKind::LapisBlock => "minecraft:lapis_block", + BlockKind::Dispenser => "minecraft:dispenser", + BlockKind::Sandstone => "minecraft:sandstone", + BlockKind::ChiseledSandstone => "minecraft:chiseled_sandstone", + BlockKind::CutSandstone => "minecraft:cut_sandstone", + BlockKind::NoteBlock => "minecraft:note_block", + BlockKind::WhiteBed => "minecraft:white_bed", + BlockKind::OrangeBed => "minecraft:orange_bed", + BlockKind::MagentaBed => "minecraft:magenta_bed", + BlockKind::LightBlueBed => "minecraft:light_blue_bed", + BlockKind::YellowBed => "minecraft:yellow_bed", + BlockKind::LimeBed => "minecraft:lime_bed", + BlockKind::PinkBed => "minecraft:pink_bed", + BlockKind::GrayBed => "minecraft:gray_bed", + BlockKind::LightGrayBed => "minecraft:light_gray_bed", + BlockKind::CyanBed => "minecraft:cyan_bed", + BlockKind::PurpleBed => "minecraft:purple_bed", + BlockKind::BlueBed => "minecraft:blue_bed", + BlockKind::BrownBed => "minecraft:brown_bed", + BlockKind::GreenBed => "minecraft:green_bed", + BlockKind::RedBed => "minecraft:red_bed", + BlockKind::BlackBed => "minecraft:black_bed", + BlockKind::PoweredRail => "minecraft:powered_rail", + BlockKind::DetectorRail => "minecraft:detector_rail", + BlockKind::StickyPiston => "minecraft:sticky_piston", + BlockKind::Cobweb => "minecraft:cobweb", + BlockKind::Grass => "minecraft:grass", + BlockKind::Fern => "minecraft:fern", + BlockKind::DeadBush => "minecraft:dead_bush", + BlockKind::Seagrass => "minecraft:seagrass", + BlockKind::TallSeagrass => "minecraft:tall_seagrass", + BlockKind::Piston => "minecraft:piston", + BlockKind::PistonHead => "minecraft:piston_head", + BlockKind::WhiteWool => "minecraft:white_wool", + BlockKind::OrangeWool => "minecraft:orange_wool", + BlockKind::MagentaWool => "minecraft:magenta_wool", + BlockKind::LightBlueWool => "minecraft:light_blue_wool", + BlockKind::YellowWool => "minecraft:yellow_wool", + BlockKind::LimeWool => "minecraft:lime_wool", + BlockKind::PinkWool => "minecraft:pink_wool", + BlockKind::GrayWool => "minecraft:gray_wool", + BlockKind::LightGrayWool => "minecraft:light_gray_wool", + BlockKind::CyanWool => "minecraft:cyan_wool", + BlockKind::PurpleWool => "minecraft:purple_wool", + BlockKind::BlueWool => "minecraft:blue_wool", + BlockKind::BrownWool => "minecraft:brown_wool", + BlockKind::GreenWool => "minecraft:green_wool", + BlockKind::RedWool => "minecraft:red_wool", + BlockKind::BlackWool => "minecraft:black_wool", + BlockKind::MovingPiston => "minecraft:moving_piston", + BlockKind::Dandelion => "minecraft:dandelion", + BlockKind::Poppy => "minecraft:poppy", + BlockKind::BlueOrchid => "minecraft:blue_orchid", + BlockKind::Allium => "minecraft:allium", + BlockKind::AzureBluet => "minecraft:azure_bluet", + BlockKind::RedTulip => "minecraft:red_tulip", + BlockKind::OrangeTulip => "minecraft:orange_tulip", + BlockKind::WhiteTulip => "minecraft:white_tulip", + BlockKind::PinkTulip => "minecraft:pink_tulip", + BlockKind::OxeyeDaisy => "minecraft:oxeye_daisy", + BlockKind::Cornflower => "minecraft:cornflower", + BlockKind::WitherRose => "minecraft:wither_rose", + BlockKind::LilyOfTheValley => "minecraft:lily_of_the_valley", + BlockKind::BrownMushroom => "minecraft:brown_mushroom", + BlockKind::RedMushroom => "minecraft:red_mushroom", + BlockKind::GoldBlock => "minecraft:gold_block", + BlockKind::IronBlock => "minecraft:iron_block", + BlockKind::Bricks => "minecraft:bricks", + BlockKind::Tnt => "minecraft:tnt", + BlockKind::Bookshelf => "minecraft:bookshelf", + BlockKind::MossyCobblestone => "minecraft:mossy_cobblestone", + BlockKind::Obsidian => "minecraft:obsidian", + BlockKind::Torch => "minecraft:torch", + BlockKind::WallTorch => "minecraft:wall_torch", + BlockKind::Fire => "minecraft:fire", + BlockKind::SoulFire => "minecraft:soul_fire", + BlockKind::Spawner => "minecraft:spawner", + BlockKind::OakStairs => "minecraft:oak_stairs", + BlockKind::Chest => "minecraft:chest", + BlockKind::RedstoneWire => "minecraft:redstone_wire", + BlockKind::DiamondOre => "minecraft:diamond_ore", + BlockKind::DiamondBlock => "minecraft:diamond_block", + BlockKind::CraftingTable => "minecraft:crafting_table", + BlockKind::Wheat => "minecraft:wheat", + BlockKind::Farmland => "minecraft:farmland", + BlockKind::Furnace => "minecraft:furnace", + BlockKind::OakSign => "minecraft:oak_sign", + BlockKind::SpruceSign => "minecraft:spruce_sign", + BlockKind::BirchSign => "minecraft:birch_sign", + BlockKind::AcaciaSign => "minecraft:acacia_sign", + BlockKind::JungleSign => "minecraft:jungle_sign", + BlockKind::DarkOakSign => "minecraft:dark_oak_sign", + BlockKind::OakDoor => "minecraft:oak_door", + BlockKind::Ladder => "minecraft:ladder", + BlockKind::Rail => "minecraft:rail", + BlockKind::CobblestoneStairs => "minecraft:cobblestone_stairs", + BlockKind::OakWallSign => "minecraft:oak_wall_sign", + BlockKind::SpruceWallSign => "minecraft:spruce_wall_sign", + BlockKind::BirchWallSign => "minecraft:birch_wall_sign", + BlockKind::AcaciaWallSign => "minecraft:acacia_wall_sign", + BlockKind::JungleWallSign => "minecraft:jungle_wall_sign", + BlockKind::DarkOakWallSign => "minecraft:dark_oak_wall_sign", + BlockKind::Lever => "minecraft:lever", + BlockKind::StonePressurePlate => "minecraft:stone_pressure_plate", + BlockKind::IronDoor => "minecraft:iron_door", + BlockKind::OakPressurePlate => "minecraft:oak_pressure_plate", + BlockKind::SprucePressurePlate => "minecraft:spruce_pressure_plate", + BlockKind::BirchPressurePlate => "minecraft:birch_pressure_plate", + BlockKind::JunglePressurePlate => "minecraft:jungle_pressure_plate", + BlockKind::AcaciaPressurePlate => "minecraft:acacia_pressure_plate", + BlockKind::DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate", + BlockKind::RedstoneOre => "minecraft:redstone_ore", + BlockKind::RedstoneTorch => "minecraft:redstone_torch", + BlockKind::RedstoneWallTorch => "minecraft:redstone_wall_torch", + BlockKind::StoneButton => "minecraft:stone_button", + BlockKind::Snow => "minecraft:snow", + BlockKind::Ice => "minecraft:ice", + BlockKind::SnowBlock => "minecraft:snow_block", + BlockKind::Cactus => "minecraft:cactus", + BlockKind::Clay => "minecraft:clay", + BlockKind::SugarCane => "minecraft:sugar_cane", + BlockKind::Jukebox => "minecraft:jukebox", + BlockKind::OakFence => "minecraft:oak_fence", + BlockKind::Pumpkin => "minecraft:pumpkin", + BlockKind::Netherrack => "minecraft:netherrack", + BlockKind::SoulSand => "minecraft:soul_sand", + BlockKind::SoulSoil => "minecraft:soul_soil", + BlockKind::Basalt => "minecraft:basalt", + BlockKind::PolishedBasalt => "minecraft:polished_basalt", + BlockKind::SoulTorch => "minecraft:soul_torch", + BlockKind::SoulWallTorch => "minecraft:soul_wall_torch", + BlockKind::Glowstone => "minecraft:glowstone", + BlockKind::NetherPortal => "minecraft:nether_portal", + BlockKind::CarvedPumpkin => "minecraft:carved_pumpkin", + BlockKind::JackOLantern => "minecraft:jack_o_lantern", + BlockKind::Cake => "minecraft:cake", + BlockKind::Repeater => "minecraft:repeater", + BlockKind::WhiteStainedGlass => "minecraft:white_stained_glass", + BlockKind::OrangeStainedGlass => "minecraft:orange_stained_glass", + BlockKind::MagentaStainedGlass => "minecraft:magenta_stained_glass", + BlockKind::LightBlueStainedGlass => "minecraft:light_blue_stained_glass", + BlockKind::YellowStainedGlass => "minecraft:yellow_stained_glass", + BlockKind::LimeStainedGlass => "minecraft:lime_stained_glass", + BlockKind::PinkStainedGlass => "minecraft:pink_stained_glass", + BlockKind::GrayStainedGlass => "minecraft:gray_stained_glass", + BlockKind::LightGrayStainedGlass => "minecraft:light_gray_stained_glass", + BlockKind::CyanStainedGlass => "minecraft:cyan_stained_glass", + BlockKind::PurpleStainedGlass => "minecraft:purple_stained_glass", + BlockKind::BlueStainedGlass => "minecraft:blue_stained_glass", + BlockKind::BrownStainedGlass => "minecraft:brown_stained_glass", + BlockKind::GreenStainedGlass => "minecraft:green_stained_glass", + BlockKind::RedStainedGlass => "minecraft:red_stained_glass", + BlockKind::BlackStainedGlass => "minecraft:black_stained_glass", + BlockKind::OakTrapdoor => "minecraft:oak_trapdoor", + BlockKind::SpruceTrapdoor => "minecraft:spruce_trapdoor", + BlockKind::BirchTrapdoor => "minecraft:birch_trapdoor", + BlockKind::JungleTrapdoor => "minecraft:jungle_trapdoor", + BlockKind::AcaciaTrapdoor => "minecraft:acacia_trapdoor", + BlockKind::DarkOakTrapdoor => "minecraft:dark_oak_trapdoor", + BlockKind::StoneBricks => "minecraft:stone_bricks", + BlockKind::MossyStoneBricks => "minecraft:mossy_stone_bricks", + BlockKind::CrackedStoneBricks => "minecraft:cracked_stone_bricks", + BlockKind::ChiseledStoneBricks => "minecraft:chiseled_stone_bricks", + BlockKind::InfestedStone => "minecraft:infested_stone", + BlockKind::InfestedCobblestone => "minecraft:infested_cobblestone", + BlockKind::InfestedStoneBricks => "minecraft:infested_stone_bricks", + BlockKind::InfestedMossyStoneBricks => "minecraft:infested_mossy_stone_bricks", + BlockKind::InfestedCrackedStoneBricks => "minecraft:infested_cracked_stone_bricks", + BlockKind::InfestedChiseledStoneBricks => "minecraft:infested_chiseled_stone_bricks", + BlockKind::BrownMushroomBlock => "minecraft:brown_mushroom_block", + BlockKind::RedMushroomBlock => "minecraft:red_mushroom_block", + BlockKind::MushroomStem => "minecraft:mushroom_stem", + BlockKind::IronBars => "minecraft:iron_bars", + BlockKind::Chain => "minecraft:chain", + BlockKind::GlassPane => "minecraft:glass_pane", + BlockKind::Melon => "minecraft:melon", + BlockKind::AttachedPumpkinStem => "minecraft:attached_pumpkin_stem", + BlockKind::AttachedMelonStem => "minecraft:attached_melon_stem", + BlockKind::PumpkinStem => "minecraft:pumpkin_stem", + BlockKind::MelonStem => "minecraft:melon_stem", + BlockKind::Vine => "minecraft:vine", + BlockKind::OakFenceGate => "minecraft:oak_fence_gate", + BlockKind::BrickStairs => "minecraft:brick_stairs", + BlockKind::StoneBrickStairs => "minecraft:stone_brick_stairs", + BlockKind::Mycelium => "minecraft:mycelium", + BlockKind::LilyPad => "minecraft:lily_pad", + BlockKind::NetherBricks => "minecraft:nether_bricks", + BlockKind::NetherBrickFence => "minecraft:nether_brick_fence", + BlockKind::NetherBrickStairs => "minecraft:nether_brick_stairs", + BlockKind::NetherWart => "minecraft:nether_wart", + BlockKind::EnchantingTable => "minecraft:enchanting_table", + BlockKind::BrewingStand => "minecraft:brewing_stand", + BlockKind::Cauldron => "minecraft:cauldron", + BlockKind::EndPortal => "minecraft:end_portal", + BlockKind::EndPortalFrame => "minecraft:end_portal_frame", + BlockKind::EndStone => "minecraft:end_stone", + BlockKind::DragonEgg => "minecraft:dragon_egg", + BlockKind::RedstoneLamp => "minecraft:redstone_lamp", + BlockKind::Cocoa => "minecraft:cocoa", + BlockKind::SandstoneStairs => "minecraft:sandstone_stairs", + BlockKind::EmeraldOre => "minecraft:emerald_ore", + BlockKind::EnderChest => "minecraft:ender_chest", + BlockKind::TripwireHook => "minecraft:tripwire_hook", + BlockKind::Tripwire => "minecraft:tripwire", + BlockKind::EmeraldBlock => "minecraft:emerald_block", + BlockKind::SpruceStairs => "minecraft:spruce_stairs", + BlockKind::BirchStairs => "minecraft:birch_stairs", + BlockKind::JungleStairs => "minecraft:jungle_stairs", + BlockKind::CommandBlock => "minecraft:command_block", + BlockKind::Beacon => "minecraft:beacon", + BlockKind::CobblestoneWall => "minecraft:cobblestone_wall", + BlockKind::MossyCobblestoneWall => "minecraft:mossy_cobblestone_wall", + BlockKind::FlowerPot => "minecraft:flower_pot", + BlockKind::PottedOakSapling => "minecraft:potted_oak_sapling", + BlockKind::PottedSpruceSapling => "minecraft:potted_spruce_sapling", + BlockKind::PottedBirchSapling => "minecraft:potted_birch_sapling", + BlockKind::PottedJungleSapling => "minecraft:potted_jungle_sapling", + BlockKind::PottedAcaciaSapling => "minecraft:potted_acacia_sapling", + BlockKind::PottedDarkOakSapling => "minecraft:potted_dark_oak_sapling", + BlockKind::PottedFern => "minecraft:potted_fern", + BlockKind::PottedDandelion => "minecraft:potted_dandelion", + BlockKind::PottedPoppy => "minecraft:potted_poppy", + BlockKind::PottedBlueOrchid => "minecraft:potted_blue_orchid", + BlockKind::PottedAllium => "minecraft:potted_allium", + BlockKind::PottedAzureBluet => "minecraft:potted_azure_bluet", + BlockKind::PottedRedTulip => "minecraft:potted_red_tulip", + BlockKind::PottedOrangeTulip => "minecraft:potted_orange_tulip", + BlockKind::PottedWhiteTulip => "minecraft:potted_white_tulip", + BlockKind::PottedPinkTulip => "minecraft:potted_pink_tulip", + BlockKind::PottedOxeyeDaisy => "minecraft:potted_oxeye_daisy", + BlockKind::PottedCornflower => "minecraft:potted_cornflower", + BlockKind::PottedLilyOfTheValley => "minecraft:potted_lily_of_the_valley", + BlockKind::PottedWitherRose => "minecraft:potted_wither_rose", + BlockKind::PottedRedMushroom => "minecraft:potted_red_mushroom", + BlockKind::PottedBrownMushroom => "minecraft:potted_brown_mushroom", + BlockKind::PottedDeadBush => "minecraft:potted_dead_bush", + BlockKind::PottedCactus => "minecraft:potted_cactus", + BlockKind::Carrots => "minecraft:carrots", + BlockKind::Potatoes => "minecraft:potatoes", + BlockKind::OakButton => "minecraft:oak_button", + BlockKind::SpruceButton => "minecraft:spruce_button", + BlockKind::BirchButton => "minecraft:birch_button", + BlockKind::JungleButton => "minecraft:jungle_button", + BlockKind::AcaciaButton => "minecraft:acacia_button", + BlockKind::DarkOakButton => "minecraft:dark_oak_button", + BlockKind::SkeletonSkull => "minecraft:skeleton_skull", + BlockKind::SkeletonWallSkull => "minecraft:skeleton_wall_skull", + BlockKind::WitherSkeletonSkull => "minecraft:wither_skeleton_skull", + BlockKind::WitherSkeletonWallSkull => "minecraft:wither_skeleton_wall_skull", + BlockKind::ZombieHead => "minecraft:zombie_head", + BlockKind::ZombieWallHead => "minecraft:zombie_wall_head", + BlockKind::PlayerHead => "minecraft:player_head", + BlockKind::PlayerWallHead => "minecraft:player_wall_head", + BlockKind::CreeperHead => "minecraft:creeper_head", + BlockKind::CreeperWallHead => "minecraft:creeper_wall_head", + BlockKind::DragonHead => "minecraft:dragon_head", + BlockKind::DragonWallHead => "minecraft:dragon_wall_head", + BlockKind::Anvil => "minecraft:anvil", + BlockKind::ChippedAnvil => "minecraft:chipped_anvil", + BlockKind::DamagedAnvil => "minecraft:damaged_anvil", + BlockKind::TrappedChest => "minecraft:trapped_chest", + BlockKind::LightWeightedPressurePlate => "minecraft:light_weighted_pressure_plate", + BlockKind::HeavyWeightedPressurePlate => "minecraft:heavy_weighted_pressure_plate", + BlockKind::Comparator => "minecraft:comparator", + BlockKind::DaylightDetector => "minecraft:daylight_detector", + BlockKind::RedstoneBlock => "minecraft:redstone_block", + BlockKind::NetherQuartzOre => "minecraft:nether_quartz_ore", + BlockKind::Hopper => "minecraft:hopper", + BlockKind::QuartzBlock => "minecraft:quartz_block", + BlockKind::ChiseledQuartzBlock => "minecraft:chiseled_quartz_block", + BlockKind::QuartzPillar => "minecraft:quartz_pillar", + BlockKind::QuartzStairs => "minecraft:quartz_stairs", + BlockKind::ActivatorRail => "minecraft:activator_rail", + BlockKind::Dropper => "minecraft:dropper", + BlockKind::WhiteTerracotta => "minecraft:white_terracotta", + BlockKind::OrangeTerracotta => "minecraft:orange_terracotta", + BlockKind::MagentaTerracotta => "minecraft:magenta_terracotta", + BlockKind::LightBlueTerracotta => "minecraft:light_blue_terracotta", + BlockKind::YellowTerracotta => "minecraft:yellow_terracotta", + BlockKind::LimeTerracotta => "minecraft:lime_terracotta", + BlockKind::PinkTerracotta => "minecraft:pink_terracotta", + BlockKind::GrayTerracotta => "minecraft:gray_terracotta", + BlockKind::LightGrayTerracotta => "minecraft:light_gray_terracotta", + BlockKind::CyanTerracotta => "minecraft:cyan_terracotta", + BlockKind::PurpleTerracotta => "minecraft:purple_terracotta", + BlockKind::BlueTerracotta => "minecraft:blue_terracotta", + BlockKind::BrownTerracotta => "minecraft:brown_terracotta", + BlockKind::GreenTerracotta => "minecraft:green_terracotta", + BlockKind::RedTerracotta => "minecraft:red_terracotta", + BlockKind::BlackTerracotta => "minecraft:black_terracotta", + BlockKind::WhiteStainedGlassPane => "minecraft:white_stained_glass_pane", + BlockKind::OrangeStainedGlassPane => "minecraft:orange_stained_glass_pane", + BlockKind::MagentaStainedGlassPane => "minecraft:magenta_stained_glass_pane", + BlockKind::LightBlueStainedGlassPane => "minecraft:light_blue_stained_glass_pane", + BlockKind::YellowStainedGlassPane => "minecraft:yellow_stained_glass_pane", + BlockKind::LimeStainedGlassPane => "minecraft:lime_stained_glass_pane", + BlockKind::PinkStainedGlassPane => "minecraft:pink_stained_glass_pane", + BlockKind::GrayStainedGlassPane => "minecraft:gray_stained_glass_pane", + BlockKind::LightGrayStainedGlassPane => "minecraft:light_gray_stained_glass_pane", + BlockKind::CyanStainedGlassPane => "minecraft:cyan_stained_glass_pane", + BlockKind::PurpleStainedGlassPane => "minecraft:purple_stained_glass_pane", + BlockKind::BlueStainedGlassPane => "minecraft:blue_stained_glass_pane", + BlockKind::BrownStainedGlassPane => "minecraft:brown_stained_glass_pane", + BlockKind::GreenStainedGlassPane => "minecraft:green_stained_glass_pane", + BlockKind::RedStainedGlassPane => "minecraft:red_stained_glass_pane", + BlockKind::BlackStainedGlassPane => "minecraft:black_stained_glass_pane", + BlockKind::AcaciaStairs => "minecraft:acacia_stairs", + BlockKind::DarkOakStairs => "minecraft:dark_oak_stairs", + BlockKind::SlimeBlock => "minecraft:slime_block", + BlockKind::Barrier => "minecraft:barrier", + BlockKind::IronTrapdoor => "minecraft:iron_trapdoor", + BlockKind::Prismarine => "minecraft:prismarine", + BlockKind::PrismarineBricks => "minecraft:prismarine_bricks", + BlockKind::DarkPrismarine => "minecraft:dark_prismarine", + BlockKind::PrismarineStairs => "minecraft:prismarine_stairs", + BlockKind::PrismarineBrickStairs => "minecraft:prismarine_brick_stairs", + BlockKind::DarkPrismarineStairs => "minecraft:dark_prismarine_stairs", + BlockKind::PrismarineSlab => "minecraft:prismarine_slab", + BlockKind::PrismarineBrickSlab => "minecraft:prismarine_brick_slab", + BlockKind::DarkPrismarineSlab => "minecraft:dark_prismarine_slab", + BlockKind::SeaLantern => "minecraft:sea_lantern", + BlockKind::HayBlock => "minecraft:hay_block", + BlockKind::WhiteCarpet => "minecraft:white_carpet", + BlockKind::OrangeCarpet => "minecraft:orange_carpet", + BlockKind::MagentaCarpet => "minecraft:magenta_carpet", + BlockKind::LightBlueCarpet => "minecraft:light_blue_carpet", + BlockKind::YellowCarpet => "minecraft:yellow_carpet", + BlockKind::LimeCarpet => "minecraft:lime_carpet", + BlockKind::PinkCarpet => "minecraft:pink_carpet", + BlockKind::GrayCarpet => "minecraft:gray_carpet", + BlockKind::LightGrayCarpet => "minecraft:light_gray_carpet", + BlockKind::CyanCarpet => "minecraft:cyan_carpet", + BlockKind::PurpleCarpet => "minecraft:purple_carpet", + BlockKind::BlueCarpet => "minecraft:blue_carpet", + BlockKind::BrownCarpet => "minecraft:brown_carpet", + BlockKind::GreenCarpet => "minecraft:green_carpet", + BlockKind::RedCarpet => "minecraft:red_carpet", + BlockKind::BlackCarpet => "minecraft:black_carpet", + BlockKind::Terracotta => "minecraft:terracotta", + BlockKind::CoalBlock => "minecraft:coal_block", + BlockKind::PackedIce => "minecraft:packed_ice", + BlockKind::Sunflower => "minecraft:sunflower", + BlockKind::Lilac => "minecraft:lilac", + BlockKind::RoseBush => "minecraft:rose_bush", + BlockKind::Peony => "minecraft:peony", + BlockKind::TallGrass => "minecraft:tall_grass", + BlockKind::LargeFern => "minecraft:large_fern", + BlockKind::WhiteBanner => "minecraft:white_banner", + BlockKind::OrangeBanner => "minecraft:orange_banner", + BlockKind::MagentaBanner => "minecraft:magenta_banner", + BlockKind::LightBlueBanner => "minecraft:light_blue_banner", + BlockKind::YellowBanner => "minecraft:yellow_banner", + BlockKind::LimeBanner => "minecraft:lime_banner", + BlockKind::PinkBanner => "minecraft:pink_banner", + BlockKind::GrayBanner => "minecraft:gray_banner", + BlockKind::LightGrayBanner => "minecraft:light_gray_banner", + BlockKind::CyanBanner => "minecraft:cyan_banner", + BlockKind::PurpleBanner => "minecraft:purple_banner", + BlockKind::BlueBanner => "minecraft:blue_banner", + BlockKind::BrownBanner => "minecraft:brown_banner", + BlockKind::GreenBanner => "minecraft:green_banner", + BlockKind::RedBanner => "minecraft:red_banner", + BlockKind::BlackBanner => "minecraft:black_banner", + BlockKind::WhiteWallBanner => "minecraft:white_wall_banner", + BlockKind::OrangeWallBanner => "minecraft:orange_wall_banner", + BlockKind::MagentaWallBanner => "minecraft:magenta_wall_banner", + BlockKind::LightBlueWallBanner => "minecraft:light_blue_wall_banner", + BlockKind::YellowWallBanner => "minecraft:yellow_wall_banner", + BlockKind::LimeWallBanner => "minecraft:lime_wall_banner", + BlockKind::PinkWallBanner => "minecraft:pink_wall_banner", + BlockKind::GrayWallBanner => "minecraft:gray_wall_banner", + BlockKind::LightGrayWallBanner => "minecraft:light_gray_wall_banner", + BlockKind::CyanWallBanner => "minecraft:cyan_wall_banner", + BlockKind::PurpleWallBanner => "minecraft:purple_wall_banner", + BlockKind::BlueWallBanner => "minecraft:blue_wall_banner", + BlockKind::BrownWallBanner => "minecraft:brown_wall_banner", + BlockKind::GreenWallBanner => "minecraft:green_wall_banner", + BlockKind::RedWallBanner => "minecraft:red_wall_banner", + BlockKind::BlackWallBanner => "minecraft:black_wall_banner", + BlockKind::RedSandstone => "minecraft:red_sandstone", + BlockKind::ChiseledRedSandstone => "minecraft:chiseled_red_sandstone", + BlockKind::CutRedSandstone => "minecraft:cut_red_sandstone", + BlockKind::RedSandstoneStairs => "minecraft:red_sandstone_stairs", + BlockKind::OakSlab => "minecraft:oak_slab", + BlockKind::SpruceSlab => "minecraft:spruce_slab", + BlockKind::BirchSlab => "minecraft:birch_slab", + BlockKind::JungleSlab => "minecraft:jungle_slab", + BlockKind::AcaciaSlab => "minecraft:acacia_slab", + BlockKind::DarkOakSlab => "minecraft:dark_oak_slab", + BlockKind::StoneSlab => "minecraft:stone_slab", + BlockKind::SmoothStoneSlab => "minecraft:smooth_stone_slab", + BlockKind::SandstoneSlab => "minecraft:sandstone_slab", + BlockKind::CutSandstoneSlab => "minecraft:cut_sandstone_slab", + BlockKind::PetrifiedOakSlab => "minecraft:petrified_oak_slab", + BlockKind::CobblestoneSlab => "minecraft:cobblestone_slab", + BlockKind::BrickSlab => "minecraft:brick_slab", + BlockKind::StoneBrickSlab => "minecraft:stone_brick_slab", + BlockKind::NetherBrickSlab => "minecraft:nether_brick_slab", + BlockKind::QuartzSlab => "minecraft:quartz_slab", + BlockKind::RedSandstoneSlab => "minecraft:red_sandstone_slab", + BlockKind::CutRedSandstoneSlab => "minecraft:cut_red_sandstone_slab", + BlockKind::PurpurSlab => "minecraft:purpur_slab", + BlockKind::SmoothStone => "minecraft:smooth_stone", + BlockKind::SmoothSandstone => "minecraft:smooth_sandstone", + BlockKind::SmoothQuartz => "minecraft:smooth_quartz", + BlockKind::SmoothRedSandstone => "minecraft:smooth_red_sandstone", + BlockKind::SpruceFenceGate => "minecraft:spruce_fence_gate", + BlockKind::BirchFenceGate => "minecraft:birch_fence_gate", + BlockKind::JungleFenceGate => "minecraft:jungle_fence_gate", + BlockKind::AcaciaFenceGate => "minecraft:acacia_fence_gate", + BlockKind::DarkOakFenceGate => "minecraft:dark_oak_fence_gate", + BlockKind::SpruceFence => "minecraft:spruce_fence", + BlockKind::BirchFence => "minecraft:birch_fence", + BlockKind::JungleFence => "minecraft:jungle_fence", + BlockKind::AcaciaFence => "minecraft:acacia_fence", + BlockKind::DarkOakFence => "minecraft:dark_oak_fence", + BlockKind::SpruceDoor => "minecraft:spruce_door", + BlockKind::BirchDoor => "minecraft:birch_door", + BlockKind::JungleDoor => "minecraft:jungle_door", + BlockKind::AcaciaDoor => "minecraft:acacia_door", + BlockKind::DarkOakDoor => "minecraft:dark_oak_door", + BlockKind::EndRod => "minecraft:end_rod", + BlockKind::ChorusPlant => "minecraft:chorus_plant", + BlockKind::ChorusFlower => "minecraft:chorus_flower", + BlockKind::PurpurBlock => "minecraft:purpur_block", + BlockKind::PurpurPillar => "minecraft:purpur_pillar", + BlockKind::PurpurStairs => "minecraft:purpur_stairs", + BlockKind::EndStoneBricks => "minecraft:end_stone_bricks", + BlockKind::Beetroots => "minecraft:beetroots", + BlockKind::GrassPath => "minecraft:grass_path", + BlockKind::EndGateway => "minecraft:end_gateway", + BlockKind::RepeatingCommandBlock => "minecraft:repeating_command_block", + BlockKind::ChainCommandBlock => "minecraft:chain_command_block", + BlockKind::FrostedIce => "minecraft:frosted_ice", + BlockKind::MagmaBlock => "minecraft:magma_block", + BlockKind::NetherWartBlock => "minecraft:nether_wart_block", + BlockKind::RedNetherBricks => "minecraft:red_nether_bricks", + BlockKind::BoneBlock => "minecraft:bone_block", + BlockKind::StructureVoid => "minecraft:structure_void", + BlockKind::Observer => "minecraft:observer", + BlockKind::ShulkerBox => "minecraft:shulker_box", + BlockKind::WhiteShulkerBox => "minecraft:white_shulker_box", + BlockKind::OrangeShulkerBox => "minecraft:orange_shulker_box", + BlockKind::MagentaShulkerBox => "minecraft:magenta_shulker_box", + BlockKind::LightBlueShulkerBox => "minecraft:light_blue_shulker_box", + BlockKind::YellowShulkerBox => "minecraft:yellow_shulker_box", + BlockKind::LimeShulkerBox => "minecraft:lime_shulker_box", + BlockKind::PinkShulkerBox => "minecraft:pink_shulker_box", + BlockKind::GrayShulkerBox => "minecraft:gray_shulker_box", + BlockKind::LightGrayShulkerBox => "minecraft:light_gray_shulker_box", + BlockKind::CyanShulkerBox => "minecraft:cyan_shulker_box", + BlockKind::PurpleShulkerBox => "minecraft:purple_shulker_box", + BlockKind::BlueShulkerBox => "minecraft:blue_shulker_box", + BlockKind::BrownShulkerBox => "minecraft:brown_shulker_box", + BlockKind::GreenShulkerBox => "minecraft:green_shulker_box", + BlockKind::RedShulkerBox => "minecraft:red_shulker_box", + BlockKind::BlackShulkerBox => "minecraft:black_shulker_box", + BlockKind::WhiteGlazedTerracotta => "minecraft:white_glazed_terracotta", + BlockKind::OrangeGlazedTerracotta => "minecraft:orange_glazed_terracotta", + BlockKind::MagentaGlazedTerracotta => "minecraft:magenta_glazed_terracotta", + BlockKind::LightBlueGlazedTerracotta => "minecraft:light_blue_glazed_terracotta", + BlockKind::YellowGlazedTerracotta => "minecraft:yellow_glazed_terracotta", + BlockKind::LimeGlazedTerracotta => "minecraft:lime_glazed_terracotta", + BlockKind::PinkGlazedTerracotta => "minecraft:pink_glazed_terracotta", + BlockKind::GrayGlazedTerracotta => "minecraft:gray_glazed_terracotta", + BlockKind::LightGrayGlazedTerracotta => "minecraft:light_gray_glazed_terracotta", + BlockKind::CyanGlazedTerracotta => "minecraft:cyan_glazed_terracotta", + BlockKind::PurpleGlazedTerracotta => "minecraft:purple_glazed_terracotta", + BlockKind::BlueGlazedTerracotta => "minecraft:blue_glazed_terracotta", + BlockKind::BrownGlazedTerracotta => "minecraft:brown_glazed_terracotta", + BlockKind::GreenGlazedTerracotta => "minecraft:green_glazed_terracotta", + BlockKind::RedGlazedTerracotta => "minecraft:red_glazed_terracotta", + BlockKind::BlackGlazedTerracotta => "minecraft:black_glazed_terracotta", + BlockKind::WhiteConcrete => "minecraft:white_concrete", + BlockKind::OrangeConcrete => "minecraft:orange_concrete", + BlockKind::MagentaConcrete => "minecraft:magenta_concrete", + BlockKind::LightBlueConcrete => "minecraft:light_blue_concrete", + BlockKind::YellowConcrete => "minecraft:yellow_concrete", + BlockKind::LimeConcrete => "minecraft:lime_concrete", + BlockKind::PinkConcrete => "minecraft:pink_concrete", + BlockKind::GrayConcrete => "minecraft:gray_concrete", + BlockKind::LightGrayConcrete => "minecraft:light_gray_concrete", + BlockKind::CyanConcrete => "minecraft:cyan_concrete", + BlockKind::PurpleConcrete => "minecraft:purple_concrete", + BlockKind::BlueConcrete => "minecraft:blue_concrete", + BlockKind::BrownConcrete => "minecraft:brown_concrete", + BlockKind::GreenConcrete => "minecraft:green_concrete", + BlockKind::RedConcrete => "minecraft:red_concrete", + BlockKind::BlackConcrete => "minecraft:black_concrete", + BlockKind::WhiteConcretePowder => "minecraft:white_concrete_powder", + BlockKind::OrangeConcretePowder => "minecraft:orange_concrete_powder", + BlockKind::MagentaConcretePowder => "minecraft:magenta_concrete_powder", + BlockKind::LightBlueConcretePowder => "minecraft:light_blue_concrete_powder", + BlockKind::YellowConcretePowder => "minecraft:yellow_concrete_powder", + BlockKind::LimeConcretePowder => "minecraft:lime_concrete_powder", + BlockKind::PinkConcretePowder => "minecraft:pink_concrete_powder", + BlockKind::GrayConcretePowder => "minecraft:gray_concrete_powder", + BlockKind::LightGrayConcretePowder => "minecraft:light_gray_concrete_powder", + BlockKind::CyanConcretePowder => "minecraft:cyan_concrete_powder", + BlockKind::PurpleConcretePowder => "minecraft:purple_concrete_powder", + BlockKind::BlueConcretePowder => "minecraft:blue_concrete_powder", + BlockKind::BrownConcretePowder => "minecraft:brown_concrete_powder", + BlockKind::GreenConcretePowder => "minecraft:green_concrete_powder", + BlockKind::RedConcretePowder => "minecraft:red_concrete_powder", + BlockKind::BlackConcretePowder => "minecraft:black_concrete_powder", + BlockKind::Kelp => "minecraft:kelp", + BlockKind::KelpPlant => "minecraft:kelp_plant", + BlockKind::DriedKelpBlock => "minecraft:dried_kelp_block", + BlockKind::TurtleEgg => "minecraft:turtle_egg", + BlockKind::DeadTubeCoralBlock => "minecraft:dead_tube_coral_block", + BlockKind::DeadBrainCoralBlock => "minecraft:dead_brain_coral_block", + BlockKind::DeadBubbleCoralBlock => "minecraft:dead_bubble_coral_block", + BlockKind::DeadFireCoralBlock => "minecraft:dead_fire_coral_block", + BlockKind::DeadHornCoralBlock => "minecraft:dead_horn_coral_block", + BlockKind::TubeCoralBlock => "minecraft:tube_coral_block", + BlockKind::BrainCoralBlock => "minecraft:brain_coral_block", + BlockKind::BubbleCoralBlock => "minecraft:bubble_coral_block", + BlockKind::FireCoralBlock => "minecraft:fire_coral_block", + BlockKind::HornCoralBlock => "minecraft:horn_coral_block", + BlockKind::DeadTubeCoral => "minecraft:dead_tube_coral", + BlockKind::DeadBrainCoral => "minecraft:dead_brain_coral", + BlockKind::DeadBubbleCoral => "minecraft:dead_bubble_coral", + BlockKind::DeadFireCoral => "minecraft:dead_fire_coral", + BlockKind::DeadHornCoral => "minecraft:dead_horn_coral", + BlockKind::TubeCoral => "minecraft:tube_coral", + BlockKind::BrainCoral => "minecraft:brain_coral", + BlockKind::BubbleCoral => "minecraft:bubble_coral", + BlockKind::FireCoral => "minecraft:fire_coral", + BlockKind::HornCoral => "minecraft:horn_coral", + BlockKind::DeadTubeCoralFan => "minecraft:dead_tube_coral_fan", + BlockKind::DeadBrainCoralFan => "minecraft:dead_brain_coral_fan", + BlockKind::DeadBubbleCoralFan => "minecraft:dead_bubble_coral_fan", + BlockKind::DeadFireCoralFan => "minecraft:dead_fire_coral_fan", + BlockKind::DeadHornCoralFan => "minecraft:dead_horn_coral_fan", + BlockKind::TubeCoralFan => "minecraft:tube_coral_fan", + BlockKind::BrainCoralFan => "minecraft:brain_coral_fan", + BlockKind::BubbleCoralFan => "minecraft:bubble_coral_fan", + BlockKind::FireCoralFan => "minecraft:fire_coral_fan", + BlockKind::HornCoralFan => "minecraft:horn_coral_fan", + BlockKind::DeadTubeCoralWallFan => "minecraft:dead_tube_coral_wall_fan", + BlockKind::DeadBrainCoralWallFan => "minecraft:dead_brain_coral_wall_fan", + BlockKind::DeadBubbleCoralWallFan => "minecraft:dead_bubble_coral_wall_fan", + BlockKind::DeadFireCoralWallFan => "minecraft:dead_fire_coral_wall_fan", + BlockKind::DeadHornCoralWallFan => "minecraft:dead_horn_coral_wall_fan", + BlockKind::TubeCoralWallFan => "minecraft:tube_coral_wall_fan", + BlockKind::BrainCoralWallFan => "minecraft:brain_coral_wall_fan", + BlockKind::BubbleCoralWallFan => "minecraft:bubble_coral_wall_fan", + BlockKind::FireCoralWallFan => "minecraft:fire_coral_wall_fan", + BlockKind::HornCoralWallFan => "minecraft:horn_coral_wall_fan", + BlockKind::SeaPickle => "minecraft:sea_pickle", + BlockKind::BlueIce => "minecraft:blue_ice", + BlockKind::Conduit => "minecraft:conduit", + BlockKind::BambooSapling => "minecraft:bamboo_sapling", + BlockKind::Bamboo => "minecraft:bamboo", + BlockKind::PottedBamboo => "minecraft:potted_bamboo", + BlockKind::VoidAir => "minecraft:void_air", + BlockKind::CaveAir => "minecraft:cave_air", + BlockKind::BubbleColumn => "minecraft:bubble_column", + BlockKind::PolishedGraniteStairs => "minecraft:polished_granite_stairs", + BlockKind::SmoothRedSandstoneStairs => "minecraft:smooth_red_sandstone_stairs", + BlockKind::MossyStoneBrickStairs => "minecraft:mossy_stone_brick_stairs", + BlockKind::PolishedDioriteStairs => "minecraft:polished_diorite_stairs", + BlockKind::MossyCobblestoneStairs => "minecraft:mossy_cobblestone_stairs", + BlockKind::EndStoneBrickStairs => "minecraft:end_stone_brick_stairs", + BlockKind::StoneStairs => "minecraft:stone_stairs", + BlockKind::SmoothSandstoneStairs => "minecraft:smooth_sandstone_stairs", + BlockKind::SmoothQuartzStairs => "minecraft:smooth_quartz_stairs", + BlockKind::GraniteStairs => "minecraft:granite_stairs", + BlockKind::AndesiteStairs => "minecraft:andesite_stairs", + BlockKind::RedNetherBrickStairs => "minecraft:red_nether_brick_stairs", + BlockKind::PolishedAndesiteStairs => "minecraft:polished_andesite_stairs", + BlockKind::DioriteStairs => "minecraft:diorite_stairs", + BlockKind::PolishedGraniteSlab => "minecraft:polished_granite_slab", + BlockKind::SmoothRedSandstoneSlab => "minecraft:smooth_red_sandstone_slab", + BlockKind::MossyStoneBrickSlab => "minecraft:mossy_stone_brick_slab", + BlockKind::PolishedDioriteSlab => "minecraft:polished_diorite_slab", + BlockKind::MossyCobblestoneSlab => "minecraft:mossy_cobblestone_slab", + BlockKind::EndStoneBrickSlab => "minecraft:end_stone_brick_slab", + BlockKind::SmoothSandstoneSlab => "minecraft:smooth_sandstone_slab", + BlockKind::SmoothQuartzSlab => "minecraft:smooth_quartz_slab", + BlockKind::GraniteSlab => "minecraft:granite_slab", + BlockKind::AndesiteSlab => "minecraft:andesite_slab", + BlockKind::RedNetherBrickSlab => "minecraft:red_nether_brick_slab", + BlockKind::PolishedAndesiteSlab => "minecraft:polished_andesite_slab", + BlockKind::DioriteSlab => "minecraft:diorite_slab", + BlockKind::BrickWall => "minecraft:brick_wall", + BlockKind::PrismarineWall => "minecraft:prismarine_wall", + BlockKind::RedSandstoneWall => "minecraft:red_sandstone_wall", + BlockKind::MossyStoneBrickWall => "minecraft:mossy_stone_brick_wall", + BlockKind::GraniteWall => "minecraft:granite_wall", + BlockKind::StoneBrickWall => "minecraft:stone_brick_wall", + BlockKind::NetherBrickWall => "minecraft:nether_brick_wall", + BlockKind::AndesiteWall => "minecraft:andesite_wall", + BlockKind::RedNetherBrickWall => "minecraft:red_nether_brick_wall", + BlockKind::SandstoneWall => "minecraft:sandstone_wall", + BlockKind::EndStoneBrickWall => "minecraft:end_stone_brick_wall", + BlockKind::DioriteWall => "minecraft:diorite_wall", + BlockKind::Scaffolding => "minecraft:scaffolding", + BlockKind::Loom => "minecraft:loom", + BlockKind::Barrel => "minecraft:barrel", + BlockKind::Smoker => "minecraft:smoker", + BlockKind::BlastFurnace => "minecraft:blast_furnace", + BlockKind::CartographyTable => "minecraft:cartography_table", + BlockKind::FletchingTable => "minecraft:fletching_table", + BlockKind::Grindstone => "minecraft:grindstone", + BlockKind::Lectern => "minecraft:lectern", + BlockKind::SmithingTable => "minecraft:smithing_table", + BlockKind::Stonecutter => "minecraft:stonecutter", + BlockKind::Bell => "minecraft:bell", + BlockKind::Lantern => "minecraft:lantern", + BlockKind::SoulLantern => "minecraft:soul_lantern", + BlockKind::Campfire => "minecraft:campfire", + BlockKind::SoulCampfire => "minecraft:soul_campfire", + BlockKind::SweetBerryBush => "minecraft:sweet_berry_bush", + BlockKind::WarpedStem => "minecraft:warped_stem", + BlockKind::StrippedWarpedStem => "minecraft:stripped_warped_stem", + BlockKind::WarpedHyphae => "minecraft:warped_hyphae", + BlockKind::StrippedWarpedHyphae => "minecraft:stripped_warped_hyphae", + BlockKind::WarpedNylium => "minecraft:warped_nylium", + BlockKind::WarpedFungus => "minecraft:warped_fungus", + BlockKind::WarpedWartBlock => "minecraft:warped_wart_block", + BlockKind::WarpedRoots => "minecraft:warped_roots", + BlockKind::NetherSprouts => "minecraft:nether_sprouts", + BlockKind::CrimsonStem => "minecraft:crimson_stem", + BlockKind::StrippedCrimsonStem => "minecraft:stripped_crimson_stem", + BlockKind::CrimsonHyphae => "minecraft:crimson_hyphae", + BlockKind::StrippedCrimsonHyphae => "minecraft:stripped_crimson_hyphae", + BlockKind::CrimsonNylium => "minecraft:crimson_nylium", + BlockKind::CrimsonFungus => "minecraft:crimson_fungus", + BlockKind::Shroomlight => "minecraft:shroomlight", + BlockKind::WeepingVines => "minecraft:weeping_vines", + BlockKind::WeepingVinesPlant => "minecraft:weeping_vines_plant", + BlockKind::TwistingVines => "minecraft:twisting_vines", + BlockKind::TwistingVinesPlant => "minecraft:twisting_vines_plant", + BlockKind::CrimsonRoots => "minecraft:crimson_roots", + BlockKind::CrimsonPlanks => "minecraft:crimson_planks", + BlockKind::WarpedPlanks => "minecraft:warped_planks", + BlockKind::CrimsonSlab => "minecraft:crimson_slab", + BlockKind::WarpedSlab => "minecraft:warped_slab", + BlockKind::CrimsonPressurePlate => "minecraft:crimson_pressure_plate", + BlockKind::WarpedPressurePlate => "minecraft:warped_pressure_plate", + BlockKind::CrimsonFence => "minecraft:crimson_fence", + BlockKind::WarpedFence => "minecraft:warped_fence", + BlockKind::CrimsonTrapdoor => "minecraft:crimson_trapdoor", + BlockKind::WarpedTrapdoor => "minecraft:warped_trapdoor", + BlockKind::CrimsonFenceGate => "minecraft:crimson_fence_gate", + BlockKind::WarpedFenceGate => "minecraft:warped_fence_gate", + BlockKind::CrimsonStairs => "minecraft:crimson_stairs", + BlockKind::WarpedStairs => "minecraft:warped_stairs", + BlockKind::CrimsonButton => "minecraft:crimson_button", + BlockKind::WarpedButton => "minecraft:warped_button", + BlockKind::CrimsonDoor => "minecraft:crimson_door", + BlockKind::WarpedDoor => "minecraft:warped_door", + BlockKind::CrimsonSign => "minecraft:crimson_sign", + BlockKind::WarpedSign => "minecraft:warped_sign", + BlockKind::CrimsonWallSign => "minecraft:crimson_wall_sign", + BlockKind::WarpedWallSign => "minecraft:warped_wall_sign", + BlockKind::StructureBlock => "minecraft:structure_block", + BlockKind::Jigsaw => "minecraft:jigsaw", + BlockKind::Composter => "minecraft:composter", + BlockKind::Target => "minecraft:target", + BlockKind::BeeNest => "minecraft:bee_nest", + BlockKind::Beehive => "minecraft:beehive", + BlockKind::HoneyBlock => "minecraft:honey_block", + BlockKind::HoneycombBlock => "minecraft:honeycomb_block", + BlockKind::NetheriteBlock => "minecraft:netherite_block", + BlockKind::AncientDebris => "minecraft:ancient_debris", + BlockKind::CryingObsidian => "minecraft:crying_obsidian", + BlockKind::RespawnAnchor => "minecraft:respawn_anchor", + BlockKind::PottedCrimsonFungus => "minecraft:potted_crimson_fungus", + BlockKind::PottedWarpedFungus => "minecraft:potted_warped_fungus", + BlockKind::PottedCrimsonRoots => "minecraft:potted_crimson_roots", + BlockKind::PottedWarpedRoots => "minecraft:potted_warped_roots", + BlockKind::Lodestone => "minecraft:lodestone", + BlockKind::Blackstone => "minecraft:blackstone", + BlockKind::BlackstoneStairs => "minecraft:blackstone_stairs", + BlockKind::BlackstoneWall => "minecraft:blackstone_wall", + BlockKind::BlackstoneSlab => "minecraft:blackstone_slab", + BlockKind::PolishedBlackstone => "minecraft:polished_blackstone", + BlockKind::PolishedBlackstoneBricks => "minecraft:polished_blackstone_bricks", + BlockKind::CrackedPolishedBlackstoneBricks => { + "minecraft:cracked_polished_blackstone_bricks" + } + BlockKind::ChiseledPolishedBlackstone => "minecraft:chiseled_polished_blackstone", + BlockKind::PolishedBlackstoneBrickSlab => "minecraft:polished_blackstone_brick_slab", + BlockKind::PolishedBlackstoneBrickStairs => { + "minecraft:polished_blackstone_brick_stairs" + } + BlockKind::PolishedBlackstoneBrickWall => "minecraft:polished_blackstone_brick_wall", + BlockKind::GildedBlackstone => "minecraft:gilded_blackstone", + BlockKind::PolishedBlackstoneStairs => "minecraft:polished_blackstone_stairs", + BlockKind::PolishedBlackstoneSlab => "minecraft:polished_blackstone_slab", + BlockKind::PolishedBlackstonePressurePlate => { + "minecraft:polished_blackstone_pressure_plate" + } + BlockKind::PolishedBlackstoneButton => "minecraft:polished_blackstone_button", + BlockKind::PolishedBlackstoneWall => "minecraft:polished_blackstone_wall", + BlockKind::ChiseledNetherBricks => "minecraft:chiseled_nether_bricks", + BlockKind::CrackedNetherBricks => "minecraft:cracked_nether_bricks", + BlockKind::QuartzBricks => "minecraft:quartz_bricks", + } + } + #[doc = "Returns a mapping from property name to property value for this block. Used to serialize blocks in vanilla world saves."] + pub fn to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + match self.kind { + BlockKind::Air => self.air_to_properties_map(), + BlockKind::Stone => self.stone_to_properties_map(), + BlockKind::Granite => self.granite_to_properties_map(), + BlockKind::PolishedGranite => self.polished_granite_to_properties_map(), + BlockKind::Diorite => self.diorite_to_properties_map(), + BlockKind::PolishedDiorite => self.polished_diorite_to_properties_map(), + BlockKind::Andesite => self.andesite_to_properties_map(), + BlockKind::PolishedAndesite => self.polished_andesite_to_properties_map(), + BlockKind::GrassBlock => self.grass_block_to_properties_map(), + BlockKind::Dirt => self.dirt_to_properties_map(), + BlockKind::CoarseDirt => self.coarse_dirt_to_properties_map(), + BlockKind::Podzol => self.podzol_to_properties_map(), + BlockKind::Cobblestone => self.cobblestone_to_properties_map(), + BlockKind::OakPlanks => self.oak_planks_to_properties_map(), + BlockKind::SprucePlanks => self.spruce_planks_to_properties_map(), + BlockKind::BirchPlanks => self.birch_planks_to_properties_map(), + BlockKind::JunglePlanks => self.jungle_planks_to_properties_map(), + BlockKind::AcaciaPlanks => self.acacia_planks_to_properties_map(), + BlockKind::DarkOakPlanks => self.dark_oak_planks_to_properties_map(), + BlockKind::OakSapling => self.oak_sapling_to_properties_map(), + BlockKind::SpruceSapling => self.spruce_sapling_to_properties_map(), + BlockKind::BirchSapling => self.birch_sapling_to_properties_map(), + BlockKind::JungleSapling => self.jungle_sapling_to_properties_map(), + BlockKind::AcaciaSapling => self.acacia_sapling_to_properties_map(), + BlockKind::DarkOakSapling => self.dark_oak_sapling_to_properties_map(), + BlockKind::Bedrock => self.bedrock_to_properties_map(), + BlockKind::Water => self.water_to_properties_map(), + BlockKind::Lava => self.lava_to_properties_map(), + BlockKind::Sand => self.sand_to_properties_map(), + BlockKind::RedSand => self.red_sand_to_properties_map(), + BlockKind::Gravel => self.gravel_to_properties_map(), + BlockKind::GoldOre => self.gold_ore_to_properties_map(), + BlockKind::IronOre => self.iron_ore_to_properties_map(), + BlockKind::CoalOre => self.coal_ore_to_properties_map(), + BlockKind::NetherGoldOre => self.nether_gold_ore_to_properties_map(), + BlockKind::OakLog => self.oak_log_to_properties_map(), + BlockKind::SpruceLog => self.spruce_log_to_properties_map(), + BlockKind::BirchLog => self.birch_log_to_properties_map(), + BlockKind::JungleLog => self.jungle_log_to_properties_map(), + BlockKind::AcaciaLog => self.acacia_log_to_properties_map(), + BlockKind::DarkOakLog => self.dark_oak_log_to_properties_map(), + BlockKind::StrippedSpruceLog => self.stripped_spruce_log_to_properties_map(), + BlockKind::StrippedBirchLog => self.stripped_birch_log_to_properties_map(), + BlockKind::StrippedJungleLog => self.stripped_jungle_log_to_properties_map(), + BlockKind::StrippedAcaciaLog => self.stripped_acacia_log_to_properties_map(), + BlockKind::StrippedDarkOakLog => self.stripped_dark_oak_log_to_properties_map(), + BlockKind::StrippedOakLog => self.stripped_oak_log_to_properties_map(), + BlockKind::OakWood => self.oak_wood_to_properties_map(), + BlockKind::SpruceWood => self.spruce_wood_to_properties_map(), + BlockKind::BirchWood => self.birch_wood_to_properties_map(), + BlockKind::JungleWood => self.jungle_wood_to_properties_map(), + BlockKind::AcaciaWood => self.acacia_wood_to_properties_map(), + BlockKind::DarkOakWood => self.dark_oak_wood_to_properties_map(), + BlockKind::StrippedOakWood => self.stripped_oak_wood_to_properties_map(), + BlockKind::StrippedSpruceWood => self.stripped_spruce_wood_to_properties_map(), + BlockKind::StrippedBirchWood => self.stripped_birch_wood_to_properties_map(), + BlockKind::StrippedJungleWood => self.stripped_jungle_wood_to_properties_map(), + BlockKind::StrippedAcaciaWood => self.stripped_acacia_wood_to_properties_map(), + BlockKind::StrippedDarkOakWood => self.stripped_dark_oak_wood_to_properties_map(), + BlockKind::OakLeaves => self.oak_leaves_to_properties_map(), + BlockKind::SpruceLeaves => self.spruce_leaves_to_properties_map(), + BlockKind::BirchLeaves => self.birch_leaves_to_properties_map(), + BlockKind::JungleLeaves => self.jungle_leaves_to_properties_map(), + BlockKind::AcaciaLeaves => self.acacia_leaves_to_properties_map(), + BlockKind::DarkOakLeaves => self.dark_oak_leaves_to_properties_map(), + BlockKind::Sponge => self.sponge_to_properties_map(), + BlockKind::WetSponge => self.wet_sponge_to_properties_map(), + BlockKind::Glass => self.glass_to_properties_map(), + BlockKind::LapisOre => self.lapis_ore_to_properties_map(), + BlockKind::LapisBlock => self.lapis_block_to_properties_map(), + BlockKind::Dispenser => self.dispenser_to_properties_map(), + BlockKind::Sandstone => self.sandstone_to_properties_map(), + BlockKind::ChiseledSandstone => self.chiseled_sandstone_to_properties_map(), + BlockKind::CutSandstone => self.cut_sandstone_to_properties_map(), + BlockKind::NoteBlock => self.note_block_to_properties_map(), + BlockKind::WhiteBed => self.white_bed_to_properties_map(), + BlockKind::OrangeBed => self.orange_bed_to_properties_map(), + BlockKind::MagentaBed => self.magenta_bed_to_properties_map(), + BlockKind::LightBlueBed => self.light_blue_bed_to_properties_map(), + BlockKind::YellowBed => self.yellow_bed_to_properties_map(), + BlockKind::LimeBed => self.lime_bed_to_properties_map(), + BlockKind::PinkBed => self.pink_bed_to_properties_map(), + BlockKind::GrayBed => self.gray_bed_to_properties_map(), + BlockKind::LightGrayBed => self.light_gray_bed_to_properties_map(), + BlockKind::CyanBed => self.cyan_bed_to_properties_map(), + BlockKind::PurpleBed => self.purple_bed_to_properties_map(), + BlockKind::BlueBed => self.blue_bed_to_properties_map(), + BlockKind::BrownBed => self.brown_bed_to_properties_map(), + BlockKind::GreenBed => self.green_bed_to_properties_map(), + BlockKind::RedBed => self.red_bed_to_properties_map(), + BlockKind::BlackBed => self.black_bed_to_properties_map(), + BlockKind::PoweredRail => self.powered_rail_to_properties_map(), + BlockKind::DetectorRail => self.detector_rail_to_properties_map(), + BlockKind::StickyPiston => self.sticky_piston_to_properties_map(), + BlockKind::Cobweb => self.cobweb_to_properties_map(), + BlockKind::Grass => self.grass_to_properties_map(), + BlockKind::Fern => self.fern_to_properties_map(), + BlockKind::DeadBush => self.dead_bush_to_properties_map(), + BlockKind::Seagrass => self.seagrass_to_properties_map(), + BlockKind::TallSeagrass => self.tall_seagrass_to_properties_map(), + BlockKind::Piston => self.piston_to_properties_map(), + BlockKind::PistonHead => self.piston_head_to_properties_map(), + BlockKind::WhiteWool => self.white_wool_to_properties_map(), + BlockKind::OrangeWool => self.orange_wool_to_properties_map(), + BlockKind::MagentaWool => self.magenta_wool_to_properties_map(), + BlockKind::LightBlueWool => self.light_blue_wool_to_properties_map(), + BlockKind::YellowWool => self.yellow_wool_to_properties_map(), + BlockKind::LimeWool => self.lime_wool_to_properties_map(), + BlockKind::PinkWool => self.pink_wool_to_properties_map(), + BlockKind::GrayWool => self.gray_wool_to_properties_map(), + BlockKind::LightGrayWool => self.light_gray_wool_to_properties_map(), + BlockKind::CyanWool => self.cyan_wool_to_properties_map(), + BlockKind::PurpleWool => self.purple_wool_to_properties_map(), + BlockKind::BlueWool => self.blue_wool_to_properties_map(), + BlockKind::BrownWool => self.brown_wool_to_properties_map(), + BlockKind::GreenWool => self.green_wool_to_properties_map(), + BlockKind::RedWool => self.red_wool_to_properties_map(), + BlockKind::BlackWool => self.black_wool_to_properties_map(), + BlockKind::MovingPiston => self.moving_piston_to_properties_map(), + BlockKind::Dandelion => self.dandelion_to_properties_map(), + BlockKind::Poppy => self.poppy_to_properties_map(), + BlockKind::BlueOrchid => self.blue_orchid_to_properties_map(), + BlockKind::Allium => self.allium_to_properties_map(), + BlockKind::AzureBluet => self.azure_bluet_to_properties_map(), + BlockKind::RedTulip => self.red_tulip_to_properties_map(), + BlockKind::OrangeTulip => self.orange_tulip_to_properties_map(), + BlockKind::WhiteTulip => self.white_tulip_to_properties_map(), + BlockKind::PinkTulip => self.pink_tulip_to_properties_map(), + BlockKind::OxeyeDaisy => self.oxeye_daisy_to_properties_map(), + BlockKind::Cornflower => self.cornflower_to_properties_map(), + BlockKind::WitherRose => self.wither_rose_to_properties_map(), + BlockKind::LilyOfTheValley => self.lily_of_the_valley_to_properties_map(), + BlockKind::BrownMushroom => self.brown_mushroom_to_properties_map(), + BlockKind::RedMushroom => self.red_mushroom_to_properties_map(), + BlockKind::GoldBlock => self.gold_block_to_properties_map(), + BlockKind::IronBlock => self.iron_block_to_properties_map(), + BlockKind::Bricks => self.bricks_to_properties_map(), + BlockKind::Tnt => self.tnt_to_properties_map(), + BlockKind::Bookshelf => self.bookshelf_to_properties_map(), + BlockKind::MossyCobblestone => self.mossy_cobblestone_to_properties_map(), + BlockKind::Obsidian => self.obsidian_to_properties_map(), + BlockKind::Torch => self.torch_to_properties_map(), + BlockKind::WallTorch => self.wall_torch_to_properties_map(), + BlockKind::Fire => self.fire_to_properties_map(), + BlockKind::SoulFire => self.soul_fire_to_properties_map(), + BlockKind::Spawner => self.spawner_to_properties_map(), + BlockKind::OakStairs => self.oak_stairs_to_properties_map(), + BlockKind::Chest => self.chest_to_properties_map(), + BlockKind::RedstoneWire => self.redstone_wire_to_properties_map(), + BlockKind::DiamondOre => self.diamond_ore_to_properties_map(), + BlockKind::DiamondBlock => self.diamond_block_to_properties_map(), + BlockKind::CraftingTable => self.crafting_table_to_properties_map(), + BlockKind::Wheat => self.wheat_to_properties_map(), + BlockKind::Farmland => self.farmland_to_properties_map(), + BlockKind::Furnace => self.furnace_to_properties_map(), + BlockKind::OakSign => self.oak_sign_to_properties_map(), + BlockKind::SpruceSign => self.spruce_sign_to_properties_map(), + BlockKind::BirchSign => self.birch_sign_to_properties_map(), + BlockKind::AcaciaSign => self.acacia_sign_to_properties_map(), + BlockKind::JungleSign => self.jungle_sign_to_properties_map(), + BlockKind::DarkOakSign => self.dark_oak_sign_to_properties_map(), + BlockKind::OakDoor => self.oak_door_to_properties_map(), + BlockKind::Ladder => self.ladder_to_properties_map(), + BlockKind::Rail => self.rail_to_properties_map(), + BlockKind::CobblestoneStairs => self.cobblestone_stairs_to_properties_map(), + BlockKind::OakWallSign => self.oak_wall_sign_to_properties_map(), + BlockKind::SpruceWallSign => self.spruce_wall_sign_to_properties_map(), + BlockKind::BirchWallSign => self.birch_wall_sign_to_properties_map(), + BlockKind::AcaciaWallSign => self.acacia_wall_sign_to_properties_map(), + BlockKind::JungleWallSign => self.jungle_wall_sign_to_properties_map(), + BlockKind::DarkOakWallSign => self.dark_oak_wall_sign_to_properties_map(), + BlockKind::Lever => self.lever_to_properties_map(), + BlockKind::StonePressurePlate => self.stone_pressure_plate_to_properties_map(), + BlockKind::IronDoor => self.iron_door_to_properties_map(), + BlockKind::OakPressurePlate => self.oak_pressure_plate_to_properties_map(), + BlockKind::SprucePressurePlate => self.spruce_pressure_plate_to_properties_map(), + BlockKind::BirchPressurePlate => self.birch_pressure_plate_to_properties_map(), + BlockKind::JunglePressurePlate => self.jungle_pressure_plate_to_properties_map(), + BlockKind::AcaciaPressurePlate => self.acacia_pressure_plate_to_properties_map(), + BlockKind::DarkOakPressurePlate => self.dark_oak_pressure_plate_to_properties_map(), + BlockKind::RedstoneOre => self.redstone_ore_to_properties_map(), + BlockKind::RedstoneTorch => self.redstone_torch_to_properties_map(), + BlockKind::RedstoneWallTorch => self.redstone_wall_torch_to_properties_map(), + BlockKind::StoneButton => self.stone_button_to_properties_map(), + BlockKind::Snow => self.snow_to_properties_map(), + BlockKind::Ice => self.ice_to_properties_map(), + BlockKind::SnowBlock => self.snow_block_to_properties_map(), + BlockKind::Cactus => self.cactus_to_properties_map(), + BlockKind::Clay => self.clay_to_properties_map(), + BlockKind::SugarCane => self.sugar_cane_to_properties_map(), + BlockKind::Jukebox => self.jukebox_to_properties_map(), + BlockKind::OakFence => self.oak_fence_to_properties_map(), + BlockKind::Pumpkin => self.pumpkin_to_properties_map(), + BlockKind::Netherrack => self.netherrack_to_properties_map(), + BlockKind::SoulSand => self.soul_sand_to_properties_map(), + BlockKind::SoulSoil => self.soul_soil_to_properties_map(), + BlockKind::Basalt => self.basalt_to_properties_map(), + BlockKind::PolishedBasalt => self.polished_basalt_to_properties_map(), + BlockKind::SoulTorch => self.soul_torch_to_properties_map(), + BlockKind::SoulWallTorch => self.soul_wall_torch_to_properties_map(), + BlockKind::Glowstone => self.glowstone_to_properties_map(), + BlockKind::NetherPortal => self.nether_portal_to_properties_map(), + BlockKind::CarvedPumpkin => self.carved_pumpkin_to_properties_map(), + BlockKind::JackOLantern => self.jack_o_lantern_to_properties_map(), + BlockKind::Cake => self.cake_to_properties_map(), + BlockKind::Repeater => self.repeater_to_properties_map(), + BlockKind::WhiteStainedGlass => self.white_stained_glass_to_properties_map(), + BlockKind::OrangeStainedGlass => self.orange_stained_glass_to_properties_map(), + BlockKind::MagentaStainedGlass => self.magenta_stained_glass_to_properties_map(), + BlockKind::LightBlueStainedGlass => self.light_blue_stained_glass_to_properties_map(), + BlockKind::YellowStainedGlass => self.yellow_stained_glass_to_properties_map(), + BlockKind::LimeStainedGlass => self.lime_stained_glass_to_properties_map(), + BlockKind::PinkStainedGlass => self.pink_stained_glass_to_properties_map(), + BlockKind::GrayStainedGlass => self.gray_stained_glass_to_properties_map(), + BlockKind::LightGrayStainedGlass => self.light_gray_stained_glass_to_properties_map(), + BlockKind::CyanStainedGlass => self.cyan_stained_glass_to_properties_map(), + BlockKind::PurpleStainedGlass => self.purple_stained_glass_to_properties_map(), + BlockKind::BlueStainedGlass => self.blue_stained_glass_to_properties_map(), + BlockKind::BrownStainedGlass => self.brown_stained_glass_to_properties_map(), + BlockKind::GreenStainedGlass => self.green_stained_glass_to_properties_map(), + BlockKind::RedStainedGlass => self.red_stained_glass_to_properties_map(), + BlockKind::BlackStainedGlass => self.black_stained_glass_to_properties_map(), + BlockKind::OakTrapdoor => self.oak_trapdoor_to_properties_map(), + BlockKind::SpruceTrapdoor => self.spruce_trapdoor_to_properties_map(), + BlockKind::BirchTrapdoor => self.birch_trapdoor_to_properties_map(), + BlockKind::JungleTrapdoor => self.jungle_trapdoor_to_properties_map(), + BlockKind::AcaciaTrapdoor => self.acacia_trapdoor_to_properties_map(), + BlockKind::DarkOakTrapdoor => self.dark_oak_trapdoor_to_properties_map(), + BlockKind::StoneBricks => self.stone_bricks_to_properties_map(), + BlockKind::MossyStoneBricks => self.mossy_stone_bricks_to_properties_map(), + BlockKind::CrackedStoneBricks => self.cracked_stone_bricks_to_properties_map(), + BlockKind::ChiseledStoneBricks => self.chiseled_stone_bricks_to_properties_map(), + BlockKind::InfestedStone => self.infested_stone_to_properties_map(), + BlockKind::InfestedCobblestone => self.infested_cobblestone_to_properties_map(), + BlockKind::InfestedStoneBricks => self.infested_stone_bricks_to_properties_map(), + BlockKind::InfestedMossyStoneBricks => { + self.infested_mossy_stone_bricks_to_properties_map() + } + BlockKind::InfestedCrackedStoneBricks => { + self.infested_cracked_stone_bricks_to_properties_map() + } + BlockKind::InfestedChiseledStoneBricks => { + self.infested_chiseled_stone_bricks_to_properties_map() + } + BlockKind::BrownMushroomBlock => self.brown_mushroom_block_to_properties_map(), + BlockKind::RedMushroomBlock => self.red_mushroom_block_to_properties_map(), + BlockKind::MushroomStem => self.mushroom_stem_to_properties_map(), + BlockKind::IronBars => self.iron_bars_to_properties_map(), + BlockKind::Chain => self.chain_to_properties_map(), + BlockKind::GlassPane => self.glass_pane_to_properties_map(), + BlockKind::Melon => self.melon_to_properties_map(), + BlockKind::AttachedPumpkinStem => self.attached_pumpkin_stem_to_properties_map(), + BlockKind::AttachedMelonStem => self.attached_melon_stem_to_properties_map(), + BlockKind::PumpkinStem => self.pumpkin_stem_to_properties_map(), + BlockKind::MelonStem => self.melon_stem_to_properties_map(), + BlockKind::Vine => self.vine_to_properties_map(), + BlockKind::OakFenceGate => self.oak_fence_gate_to_properties_map(), + BlockKind::BrickStairs => self.brick_stairs_to_properties_map(), + BlockKind::StoneBrickStairs => self.stone_brick_stairs_to_properties_map(), + BlockKind::Mycelium => self.mycelium_to_properties_map(), + BlockKind::LilyPad => self.lily_pad_to_properties_map(), + BlockKind::NetherBricks => self.nether_bricks_to_properties_map(), + BlockKind::NetherBrickFence => self.nether_brick_fence_to_properties_map(), + BlockKind::NetherBrickStairs => self.nether_brick_stairs_to_properties_map(), + BlockKind::NetherWart => self.nether_wart_to_properties_map(), + BlockKind::EnchantingTable => self.enchanting_table_to_properties_map(), + BlockKind::BrewingStand => self.brewing_stand_to_properties_map(), + BlockKind::Cauldron => self.cauldron_to_properties_map(), + BlockKind::EndPortal => self.end_portal_to_properties_map(), + BlockKind::EndPortalFrame => self.end_portal_frame_to_properties_map(), + BlockKind::EndStone => self.end_stone_to_properties_map(), + BlockKind::DragonEgg => self.dragon_egg_to_properties_map(), + BlockKind::RedstoneLamp => self.redstone_lamp_to_properties_map(), + BlockKind::Cocoa => self.cocoa_to_properties_map(), + BlockKind::SandstoneStairs => self.sandstone_stairs_to_properties_map(), + BlockKind::EmeraldOre => self.emerald_ore_to_properties_map(), + BlockKind::EnderChest => self.ender_chest_to_properties_map(), + BlockKind::TripwireHook => self.tripwire_hook_to_properties_map(), + BlockKind::Tripwire => self.tripwire_to_properties_map(), + BlockKind::EmeraldBlock => self.emerald_block_to_properties_map(), + BlockKind::SpruceStairs => self.spruce_stairs_to_properties_map(), + BlockKind::BirchStairs => self.birch_stairs_to_properties_map(), + BlockKind::JungleStairs => self.jungle_stairs_to_properties_map(), + BlockKind::CommandBlock => self.command_block_to_properties_map(), + BlockKind::Beacon => self.beacon_to_properties_map(), + BlockKind::CobblestoneWall => self.cobblestone_wall_to_properties_map(), + BlockKind::MossyCobblestoneWall => self.mossy_cobblestone_wall_to_properties_map(), + BlockKind::FlowerPot => self.flower_pot_to_properties_map(), + BlockKind::PottedOakSapling => self.potted_oak_sapling_to_properties_map(), + BlockKind::PottedSpruceSapling => self.potted_spruce_sapling_to_properties_map(), + BlockKind::PottedBirchSapling => self.potted_birch_sapling_to_properties_map(), + BlockKind::PottedJungleSapling => self.potted_jungle_sapling_to_properties_map(), + BlockKind::PottedAcaciaSapling => self.potted_acacia_sapling_to_properties_map(), + BlockKind::PottedDarkOakSapling => self.potted_dark_oak_sapling_to_properties_map(), + BlockKind::PottedFern => self.potted_fern_to_properties_map(), + BlockKind::PottedDandelion => self.potted_dandelion_to_properties_map(), + BlockKind::PottedPoppy => self.potted_poppy_to_properties_map(), + BlockKind::PottedBlueOrchid => self.potted_blue_orchid_to_properties_map(), + BlockKind::PottedAllium => self.potted_allium_to_properties_map(), + BlockKind::PottedAzureBluet => self.potted_azure_bluet_to_properties_map(), + BlockKind::PottedRedTulip => self.potted_red_tulip_to_properties_map(), + BlockKind::PottedOrangeTulip => self.potted_orange_tulip_to_properties_map(), + BlockKind::PottedWhiteTulip => self.potted_white_tulip_to_properties_map(), + BlockKind::PottedPinkTulip => self.potted_pink_tulip_to_properties_map(), + BlockKind::PottedOxeyeDaisy => self.potted_oxeye_daisy_to_properties_map(), + BlockKind::PottedCornflower => self.potted_cornflower_to_properties_map(), + BlockKind::PottedLilyOfTheValley => self.potted_lily_of_the_valley_to_properties_map(), + BlockKind::PottedWitherRose => self.potted_wither_rose_to_properties_map(), + BlockKind::PottedRedMushroom => self.potted_red_mushroom_to_properties_map(), + BlockKind::PottedBrownMushroom => self.potted_brown_mushroom_to_properties_map(), + BlockKind::PottedDeadBush => self.potted_dead_bush_to_properties_map(), + BlockKind::PottedCactus => self.potted_cactus_to_properties_map(), + BlockKind::Carrots => self.carrots_to_properties_map(), + BlockKind::Potatoes => self.potatoes_to_properties_map(), + BlockKind::OakButton => self.oak_button_to_properties_map(), + BlockKind::SpruceButton => self.spruce_button_to_properties_map(), + BlockKind::BirchButton => self.birch_button_to_properties_map(), + BlockKind::JungleButton => self.jungle_button_to_properties_map(), + BlockKind::AcaciaButton => self.acacia_button_to_properties_map(), + BlockKind::DarkOakButton => self.dark_oak_button_to_properties_map(), + BlockKind::SkeletonSkull => self.skeleton_skull_to_properties_map(), + BlockKind::SkeletonWallSkull => self.skeleton_wall_skull_to_properties_map(), + BlockKind::WitherSkeletonSkull => self.wither_skeleton_skull_to_properties_map(), + BlockKind::WitherSkeletonWallSkull => { + self.wither_skeleton_wall_skull_to_properties_map() + } + BlockKind::ZombieHead => self.zombie_head_to_properties_map(), + BlockKind::ZombieWallHead => self.zombie_wall_head_to_properties_map(), + BlockKind::PlayerHead => self.player_head_to_properties_map(), + BlockKind::PlayerWallHead => self.player_wall_head_to_properties_map(), + BlockKind::CreeperHead => self.creeper_head_to_properties_map(), + BlockKind::CreeperWallHead => self.creeper_wall_head_to_properties_map(), + BlockKind::DragonHead => self.dragon_head_to_properties_map(), + BlockKind::DragonWallHead => self.dragon_wall_head_to_properties_map(), + BlockKind::Anvil => self.anvil_to_properties_map(), + BlockKind::ChippedAnvil => self.chipped_anvil_to_properties_map(), + BlockKind::DamagedAnvil => self.damaged_anvil_to_properties_map(), + BlockKind::TrappedChest => self.trapped_chest_to_properties_map(), + BlockKind::LightWeightedPressurePlate => { + self.light_weighted_pressure_plate_to_properties_map() + } + BlockKind::HeavyWeightedPressurePlate => { + self.heavy_weighted_pressure_plate_to_properties_map() + } + BlockKind::Comparator => self.comparator_to_properties_map(), + BlockKind::DaylightDetector => self.daylight_detector_to_properties_map(), + BlockKind::RedstoneBlock => self.redstone_block_to_properties_map(), + BlockKind::NetherQuartzOre => self.nether_quartz_ore_to_properties_map(), + BlockKind::Hopper => self.hopper_to_properties_map(), + BlockKind::QuartzBlock => self.quartz_block_to_properties_map(), + BlockKind::ChiseledQuartzBlock => self.chiseled_quartz_block_to_properties_map(), + BlockKind::QuartzPillar => self.quartz_pillar_to_properties_map(), + BlockKind::QuartzStairs => self.quartz_stairs_to_properties_map(), + BlockKind::ActivatorRail => self.activator_rail_to_properties_map(), + BlockKind::Dropper => self.dropper_to_properties_map(), + BlockKind::WhiteTerracotta => self.white_terracotta_to_properties_map(), + BlockKind::OrangeTerracotta => self.orange_terracotta_to_properties_map(), + BlockKind::MagentaTerracotta => self.magenta_terracotta_to_properties_map(), + BlockKind::LightBlueTerracotta => self.light_blue_terracotta_to_properties_map(), + BlockKind::YellowTerracotta => self.yellow_terracotta_to_properties_map(), + BlockKind::LimeTerracotta => self.lime_terracotta_to_properties_map(), + BlockKind::PinkTerracotta => self.pink_terracotta_to_properties_map(), + BlockKind::GrayTerracotta => self.gray_terracotta_to_properties_map(), + BlockKind::LightGrayTerracotta => self.light_gray_terracotta_to_properties_map(), + BlockKind::CyanTerracotta => self.cyan_terracotta_to_properties_map(), + BlockKind::PurpleTerracotta => self.purple_terracotta_to_properties_map(), + BlockKind::BlueTerracotta => self.blue_terracotta_to_properties_map(), + BlockKind::BrownTerracotta => self.brown_terracotta_to_properties_map(), + BlockKind::GreenTerracotta => self.green_terracotta_to_properties_map(), + BlockKind::RedTerracotta => self.red_terracotta_to_properties_map(), + BlockKind::BlackTerracotta => self.black_terracotta_to_properties_map(), + BlockKind::WhiteStainedGlassPane => self.white_stained_glass_pane_to_properties_map(), + BlockKind::OrangeStainedGlassPane => self.orange_stained_glass_pane_to_properties_map(), + BlockKind::MagentaStainedGlassPane => { + self.magenta_stained_glass_pane_to_properties_map() + } + BlockKind::LightBlueStainedGlassPane => { + self.light_blue_stained_glass_pane_to_properties_map() + } + BlockKind::YellowStainedGlassPane => self.yellow_stained_glass_pane_to_properties_map(), + BlockKind::LimeStainedGlassPane => self.lime_stained_glass_pane_to_properties_map(), + BlockKind::PinkStainedGlassPane => self.pink_stained_glass_pane_to_properties_map(), + BlockKind::GrayStainedGlassPane => self.gray_stained_glass_pane_to_properties_map(), + BlockKind::LightGrayStainedGlassPane => { + self.light_gray_stained_glass_pane_to_properties_map() + } + BlockKind::CyanStainedGlassPane => self.cyan_stained_glass_pane_to_properties_map(), + BlockKind::PurpleStainedGlassPane => self.purple_stained_glass_pane_to_properties_map(), + BlockKind::BlueStainedGlassPane => self.blue_stained_glass_pane_to_properties_map(), + BlockKind::BrownStainedGlassPane => self.brown_stained_glass_pane_to_properties_map(), + BlockKind::GreenStainedGlassPane => self.green_stained_glass_pane_to_properties_map(), + BlockKind::RedStainedGlassPane => self.red_stained_glass_pane_to_properties_map(), + BlockKind::BlackStainedGlassPane => self.black_stained_glass_pane_to_properties_map(), + BlockKind::AcaciaStairs => self.acacia_stairs_to_properties_map(), + BlockKind::DarkOakStairs => self.dark_oak_stairs_to_properties_map(), + BlockKind::SlimeBlock => self.slime_block_to_properties_map(), + BlockKind::Barrier => self.barrier_to_properties_map(), + BlockKind::IronTrapdoor => self.iron_trapdoor_to_properties_map(), + BlockKind::Prismarine => self.prismarine_to_properties_map(), + BlockKind::PrismarineBricks => self.prismarine_bricks_to_properties_map(), + BlockKind::DarkPrismarine => self.dark_prismarine_to_properties_map(), + BlockKind::PrismarineStairs => self.prismarine_stairs_to_properties_map(), + BlockKind::PrismarineBrickStairs => self.prismarine_brick_stairs_to_properties_map(), + BlockKind::DarkPrismarineStairs => self.dark_prismarine_stairs_to_properties_map(), + BlockKind::PrismarineSlab => self.prismarine_slab_to_properties_map(), + BlockKind::PrismarineBrickSlab => self.prismarine_brick_slab_to_properties_map(), + BlockKind::DarkPrismarineSlab => self.dark_prismarine_slab_to_properties_map(), + BlockKind::SeaLantern => self.sea_lantern_to_properties_map(), + BlockKind::HayBlock => self.hay_block_to_properties_map(), + BlockKind::WhiteCarpet => self.white_carpet_to_properties_map(), + BlockKind::OrangeCarpet => self.orange_carpet_to_properties_map(), + BlockKind::MagentaCarpet => self.magenta_carpet_to_properties_map(), + BlockKind::LightBlueCarpet => self.light_blue_carpet_to_properties_map(), + BlockKind::YellowCarpet => self.yellow_carpet_to_properties_map(), + BlockKind::LimeCarpet => self.lime_carpet_to_properties_map(), + BlockKind::PinkCarpet => self.pink_carpet_to_properties_map(), + BlockKind::GrayCarpet => self.gray_carpet_to_properties_map(), + BlockKind::LightGrayCarpet => self.light_gray_carpet_to_properties_map(), + BlockKind::CyanCarpet => self.cyan_carpet_to_properties_map(), + BlockKind::PurpleCarpet => self.purple_carpet_to_properties_map(), + BlockKind::BlueCarpet => self.blue_carpet_to_properties_map(), + BlockKind::BrownCarpet => self.brown_carpet_to_properties_map(), + BlockKind::GreenCarpet => self.green_carpet_to_properties_map(), + BlockKind::RedCarpet => self.red_carpet_to_properties_map(), + BlockKind::BlackCarpet => self.black_carpet_to_properties_map(), + BlockKind::Terracotta => self.terracotta_to_properties_map(), + BlockKind::CoalBlock => self.coal_block_to_properties_map(), + BlockKind::PackedIce => self.packed_ice_to_properties_map(), + BlockKind::Sunflower => self.sunflower_to_properties_map(), + BlockKind::Lilac => self.lilac_to_properties_map(), + BlockKind::RoseBush => self.rose_bush_to_properties_map(), + BlockKind::Peony => self.peony_to_properties_map(), + BlockKind::TallGrass => self.tall_grass_to_properties_map(), + BlockKind::LargeFern => self.large_fern_to_properties_map(), + BlockKind::WhiteBanner => self.white_banner_to_properties_map(), + BlockKind::OrangeBanner => self.orange_banner_to_properties_map(), + BlockKind::MagentaBanner => self.magenta_banner_to_properties_map(), + BlockKind::LightBlueBanner => self.light_blue_banner_to_properties_map(), + BlockKind::YellowBanner => self.yellow_banner_to_properties_map(), + BlockKind::LimeBanner => self.lime_banner_to_properties_map(), + BlockKind::PinkBanner => self.pink_banner_to_properties_map(), + BlockKind::GrayBanner => self.gray_banner_to_properties_map(), + BlockKind::LightGrayBanner => self.light_gray_banner_to_properties_map(), + BlockKind::CyanBanner => self.cyan_banner_to_properties_map(), + BlockKind::PurpleBanner => self.purple_banner_to_properties_map(), + BlockKind::BlueBanner => self.blue_banner_to_properties_map(), + BlockKind::BrownBanner => self.brown_banner_to_properties_map(), + BlockKind::GreenBanner => self.green_banner_to_properties_map(), + BlockKind::RedBanner => self.red_banner_to_properties_map(), + BlockKind::BlackBanner => self.black_banner_to_properties_map(), + BlockKind::WhiteWallBanner => self.white_wall_banner_to_properties_map(), + BlockKind::OrangeWallBanner => self.orange_wall_banner_to_properties_map(), + BlockKind::MagentaWallBanner => self.magenta_wall_banner_to_properties_map(), + BlockKind::LightBlueWallBanner => self.light_blue_wall_banner_to_properties_map(), + BlockKind::YellowWallBanner => self.yellow_wall_banner_to_properties_map(), + BlockKind::LimeWallBanner => self.lime_wall_banner_to_properties_map(), + BlockKind::PinkWallBanner => self.pink_wall_banner_to_properties_map(), + BlockKind::GrayWallBanner => self.gray_wall_banner_to_properties_map(), + BlockKind::LightGrayWallBanner => self.light_gray_wall_banner_to_properties_map(), + BlockKind::CyanWallBanner => self.cyan_wall_banner_to_properties_map(), + BlockKind::PurpleWallBanner => self.purple_wall_banner_to_properties_map(), + BlockKind::BlueWallBanner => self.blue_wall_banner_to_properties_map(), + BlockKind::BrownWallBanner => self.brown_wall_banner_to_properties_map(), + BlockKind::GreenWallBanner => self.green_wall_banner_to_properties_map(), + BlockKind::RedWallBanner => self.red_wall_banner_to_properties_map(), + BlockKind::BlackWallBanner => self.black_wall_banner_to_properties_map(), + BlockKind::RedSandstone => self.red_sandstone_to_properties_map(), + BlockKind::ChiseledRedSandstone => self.chiseled_red_sandstone_to_properties_map(), + BlockKind::CutRedSandstone => self.cut_red_sandstone_to_properties_map(), + BlockKind::RedSandstoneStairs => self.red_sandstone_stairs_to_properties_map(), + BlockKind::OakSlab => self.oak_slab_to_properties_map(), + BlockKind::SpruceSlab => self.spruce_slab_to_properties_map(), + BlockKind::BirchSlab => self.birch_slab_to_properties_map(), + BlockKind::JungleSlab => self.jungle_slab_to_properties_map(), + BlockKind::AcaciaSlab => self.acacia_slab_to_properties_map(), + BlockKind::DarkOakSlab => self.dark_oak_slab_to_properties_map(), + BlockKind::StoneSlab => self.stone_slab_to_properties_map(), + BlockKind::SmoothStoneSlab => self.smooth_stone_slab_to_properties_map(), + BlockKind::SandstoneSlab => self.sandstone_slab_to_properties_map(), + BlockKind::CutSandstoneSlab => self.cut_sandstone_slab_to_properties_map(), + BlockKind::PetrifiedOakSlab => self.petrified_oak_slab_to_properties_map(), + BlockKind::CobblestoneSlab => self.cobblestone_slab_to_properties_map(), + BlockKind::BrickSlab => self.brick_slab_to_properties_map(), + BlockKind::StoneBrickSlab => self.stone_brick_slab_to_properties_map(), + BlockKind::NetherBrickSlab => self.nether_brick_slab_to_properties_map(), + BlockKind::QuartzSlab => self.quartz_slab_to_properties_map(), + BlockKind::RedSandstoneSlab => self.red_sandstone_slab_to_properties_map(), + BlockKind::CutRedSandstoneSlab => self.cut_red_sandstone_slab_to_properties_map(), + BlockKind::PurpurSlab => self.purpur_slab_to_properties_map(), + BlockKind::SmoothStone => self.smooth_stone_to_properties_map(), + BlockKind::SmoothSandstone => self.smooth_sandstone_to_properties_map(), + BlockKind::SmoothQuartz => self.smooth_quartz_to_properties_map(), + BlockKind::SmoothRedSandstone => self.smooth_red_sandstone_to_properties_map(), + BlockKind::SpruceFenceGate => self.spruce_fence_gate_to_properties_map(), + BlockKind::BirchFenceGate => self.birch_fence_gate_to_properties_map(), + BlockKind::JungleFenceGate => self.jungle_fence_gate_to_properties_map(), + BlockKind::AcaciaFenceGate => self.acacia_fence_gate_to_properties_map(), + BlockKind::DarkOakFenceGate => self.dark_oak_fence_gate_to_properties_map(), + BlockKind::SpruceFence => self.spruce_fence_to_properties_map(), + BlockKind::BirchFence => self.birch_fence_to_properties_map(), + BlockKind::JungleFence => self.jungle_fence_to_properties_map(), + BlockKind::AcaciaFence => self.acacia_fence_to_properties_map(), + BlockKind::DarkOakFence => self.dark_oak_fence_to_properties_map(), + BlockKind::SpruceDoor => self.spruce_door_to_properties_map(), + BlockKind::BirchDoor => self.birch_door_to_properties_map(), + BlockKind::JungleDoor => self.jungle_door_to_properties_map(), + BlockKind::AcaciaDoor => self.acacia_door_to_properties_map(), + BlockKind::DarkOakDoor => self.dark_oak_door_to_properties_map(), + BlockKind::EndRod => self.end_rod_to_properties_map(), + BlockKind::ChorusPlant => self.chorus_plant_to_properties_map(), + BlockKind::ChorusFlower => self.chorus_flower_to_properties_map(), + BlockKind::PurpurBlock => self.purpur_block_to_properties_map(), + BlockKind::PurpurPillar => self.purpur_pillar_to_properties_map(), + BlockKind::PurpurStairs => self.purpur_stairs_to_properties_map(), + BlockKind::EndStoneBricks => self.end_stone_bricks_to_properties_map(), + BlockKind::Beetroots => self.beetroots_to_properties_map(), + BlockKind::GrassPath => self.grass_path_to_properties_map(), + BlockKind::EndGateway => self.end_gateway_to_properties_map(), + BlockKind::RepeatingCommandBlock => self.repeating_command_block_to_properties_map(), + BlockKind::ChainCommandBlock => self.chain_command_block_to_properties_map(), + BlockKind::FrostedIce => self.frosted_ice_to_properties_map(), + BlockKind::MagmaBlock => self.magma_block_to_properties_map(), + BlockKind::NetherWartBlock => self.nether_wart_block_to_properties_map(), + BlockKind::RedNetherBricks => self.red_nether_bricks_to_properties_map(), + BlockKind::BoneBlock => self.bone_block_to_properties_map(), + BlockKind::StructureVoid => self.structure_void_to_properties_map(), + BlockKind::Observer => self.observer_to_properties_map(), + BlockKind::ShulkerBox => self.shulker_box_to_properties_map(), + BlockKind::WhiteShulkerBox => self.white_shulker_box_to_properties_map(), + BlockKind::OrangeShulkerBox => self.orange_shulker_box_to_properties_map(), + BlockKind::MagentaShulkerBox => self.magenta_shulker_box_to_properties_map(), + BlockKind::LightBlueShulkerBox => self.light_blue_shulker_box_to_properties_map(), + BlockKind::YellowShulkerBox => self.yellow_shulker_box_to_properties_map(), + BlockKind::LimeShulkerBox => self.lime_shulker_box_to_properties_map(), + BlockKind::PinkShulkerBox => self.pink_shulker_box_to_properties_map(), + BlockKind::GrayShulkerBox => self.gray_shulker_box_to_properties_map(), + BlockKind::LightGrayShulkerBox => self.light_gray_shulker_box_to_properties_map(), + BlockKind::CyanShulkerBox => self.cyan_shulker_box_to_properties_map(), + BlockKind::PurpleShulkerBox => self.purple_shulker_box_to_properties_map(), + BlockKind::BlueShulkerBox => self.blue_shulker_box_to_properties_map(), + BlockKind::BrownShulkerBox => self.brown_shulker_box_to_properties_map(), + BlockKind::GreenShulkerBox => self.green_shulker_box_to_properties_map(), + BlockKind::RedShulkerBox => self.red_shulker_box_to_properties_map(), + BlockKind::BlackShulkerBox => self.black_shulker_box_to_properties_map(), + BlockKind::WhiteGlazedTerracotta => self.white_glazed_terracotta_to_properties_map(), + BlockKind::OrangeGlazedTerracotta => self.orange_glazed_terracotta_to_properties_map(), + BlockKind::MagentaGlazedTerracotta => { + self.magenta_glazed_terracotta_to_properties_map() + } + BlockKind::LightBlueGlazedTerracotta => { + self.light_blue_glazed_terracotta_to_properties_map() + } + BlockKind::YellowGlazedTerracotta => self.yellow_glazed_terracotta_to_properties_map(), + BlockKind::LimeGlazedTerracotta => self.lime_glazed_terracotta_to_properties_map(), + BlockKind::PinkGlazedTerracotta => self.pink_glazed_terracotta_to_properties_map(), + BlockKind::GrayGlazedTerracotta => self.gray_glazed_terracotta_to_properties_map(), + BlockKind::LightGrayGlazedTerracotta => { + self.light_gray_glazed_terracotta_to_properties_map() + } + BlockKind::CyanGlazedTerracotta => self.cyan_glazed_terracotta_to_properties_map(), + BlockKind::PurpleGlazedTerracotta => self.purple_glazed_terracotta_to_properties_map(), + BlockKind::BlueGlazedTerracotta => self.blue_glazed_terracotta_to_properties_map(), + BlockKind::BrownGlazedTerracotta => self.brown_glazed_terracotta_to_properties_map(), + BlockKind::GreenGlazedTerracotta => self.green_glazed_terracotta_to_properties_map(), + BlockKind::RedGlazedTerracotta => self.red_glazed_terracotta_to_properties_map(), + BlockKind::BlackGlazedTerracotta => self.black_glazed_terracotta_to_properties_map(), + BlockKind::WhiteConcrete => self.white_concrete_to_properties_map(), + BlockKind::OrangeConcrete => self.orange_concrete_to_properties_map(), + BlockKind::MagentaConcrete => self.magenta_concrete_to_properties_map(), + BlockKind::LightBlueConcrete => self.light_blue_concrete_to_properties_map(), + BlockKind::YellowConcrete => self.yellow_concrete_to_properties_map(), + BlockKind::LimeConcrete => self.lime_concrete_to_properties_map(), + BlockKind::PinkConcrete => self.pink_concrete_to_properties_map(), + BlockKind::GrayConcrete => self.gray_concrete_to_properties_map(), + BlockKind::LightGrayConcrete => self.light_gray_concrete_to_properties_map(), + BlockKind::CyanConcrete => self.cyan_concrete_to_properties_map(), + BlockKind::PurpleConcrete => self.purple_concrete_to_properties_map(), + BlockKind::BlueConcrete => self.blue_concrete_to_properties_map(), + BlockKind::BrownConcrete => self.brown_concrete_to_properties_map(), + BlockKind::GreenConcrete => self.green_concrete_to_properties_map(), + BlockKind::RedConcrete => self.red_concrete_to_properties_map(), + BlockKind::BlackConcrete => self.black_concrete_to_properties_map(), + BlockKind::WhiteConcretePowder => self.white_concrete_powder_to_properties_map(), + BlockKind::OrangeConcretePowder => self.orange_concrete_powder_to_properties_map(), + BlockKind::MagentaConcretePowder => self.magenta_concrete_powder_to_properties_map(), + BlockKind::LightBlueConcretePowder => { + self.light_blue_concrete_powder_to_properties_map() + } + BlockKind::YellowConcretePowder => self.yellow_concrete_powder_to_properties_map(), + BlockKind::LimeConcretePowder => self.lime_concrete_powder_to_properties_map(), + BlockKind::PinkConcretePowder => self.pink_concrete_powder_to_properties_map(), + BlockKind::GrayConcretePowder => self.gray_concrete_powder_to_properties_map(), + BlockKind::LightGrayConcretePowder => { + self.light_gray_concrete_powder_to_properties_map() + } + BlockKind::CyanConcretePowder => self.cyan_concrete_powder_to_properties_map(), + BlockKind::PurpleConcretePowder => self.purple_concrete_powder_to_properties_map(), + BlockKind::BlueConcretePowder => self.blue_concrete_powder_to_properties_map(), + BlockKind::BrownConcretePowder => self.brown_concrete_powder_to_properties_map(), + BlockKind::GreenConcretePowder => self.green_concrete_powder_to_properties_map(), + BlockKind::RedConcretePowder => self.red_concrete_powder_to_properties_map(), + BlockKind::BlackConcretePowder => self.black_concrete_powder_to_properties_map(), + BlockKind::Kelp => self.kelp_to_properties_map(), + BlockKind::KelpPlant => self.kelp_plant_to_properties_map(), + BlockKind::DriedKelpBlock => self.dried_kelp_block_to_properties_map(), + BlockKind::TurtleEgg => self.turtle_egg_to_properties_map(), + BlockKind::DeadTubeCoralBlock => self.dead_tube_coral_block_to_properties_map(), + BlockKind::DeadBrainCoralBlock => self.dead_brain_coral_block_to_properties_map(), + BlockKind::DeadBubbleCoralBlock => self.dead_bubble_coral_block_to_properties_map(), + BlockKind::DeadFireCoralBlock => self.dead_fire_coral_block_to_properties_map(), + BlockKind::DeadHornCoralBlock => self.dead_horn_coral_block_to_properties_map(), + BlockKind::TubeCoralBlock => self.tube_coral_block_to_properties_map(), + BlockKind::BrainCoralBlock => self.brain_coral_block_to_properties_map(), + BlockKind::BubbleCoralBlock => self.bubble_coral_block_to_properties_map(), + BlockKind::FireCoralBlock => self.fire_coral_block_to_properties_map(), + BlockKind::HornCoralBlock => self.horn_coral_block_to_properties_map(), + BlockKind::DeadTubeCoral => self.dead_tube_coral_to_properties_map(), + BlockKind::DeadBrainCoral => self.dead_brain_coral_to_properties_map(), + BlockKind::DeadBubbleCoral => self.dead_bubble_coral_to_properties_map(), + BlockKind::DeadFireCoral => self.dead_fire_coral_to_properties_map(), + BlockKind::DeadHornCoral => self.dead_horn_coral_to_properties_map(), + BlockKind::TubeCoral => self.tube_coral_to_properties_map(), + BlockKind::BrainCoral => self.brain_coral_to_properties_map(), + BlockKind::BubbleCoral => self.bubble_coral_to_properties_map(), + BlockKind::FireCoral => self.fire_coral_to_properties_map(), + BlockKind::HornCoral => self.horn_coral_to_properties_map(), + BlockKind::DeadTubeCoralFan => self.dead_tube_coral_fan_to_properties_map(), + BlockKind::DeadBrainCoralFan => self.dead_brain_coral_fan_to_properties_map(), + BlockKind::DeadBubbleCoralFan => self.dead_bubble_coral_fan_to_properties_map(), + BlockKind::DeadFireCoralFan => self.dead_fire_coral_fan_to_properties_map(), + BlockKind::DeadHornCoralFan => self.dead_horn_coral_fan_to_properties_map(), + BlockKind::TubeCoralFan => self.tube_coral_fan_to_properties_map(), + BlockKind::BrainCoralFan => self.brain_coral_fan_to_properties_map(), + BlockKind::BubbleCoralFan => self.bubble_coral_fan_to_properties_map(), + BlockKind::FireCoralFan => self.fire_coral_fan_to_properties_map(), + BlockKind::HornCoralFan => self.horn_coral_fan_to_properties_map(), + BlockKind::DeadTubeCoralWallFan => self.dead_tube_coral_wall_fan_to_properties_map(), + BlockKind::DeadBrainCoralWallFan => self.dead_brain_coral_wall_fan_to_properties_map(), + BlockKind::DeadBubbleCoralWallFan => { + self.dead_bubble_coral_wall_fan_to_properties_map() + } + BlockKind::DeadFireCoralWallFan => self.dead_fire_coral_wall_fan_to_properties_map(), + BlockKind::DeadHornCoralWallFan => self.dead_horn_coral_wall_fan_to_properties_map(), + BlockKind::TubeCoralWallFan => self.tube_coral_wall_fan_to_properties_map(), + BlockKind::BrainCoralWallFan => self.brain_coral_wall_fan_to_properties_map(), + BlockKind::BubbleCoralWallFan => self.bubble_coral_wall_fan_to_properties_map(), + BlockKind::FireCoralWallFan => self.fire_coral_wall_fan_to_properties_map(), + BlockKind::HornCoralWallFan => self.horn_coral_wall_fan_to_properties_map(), + BlockKind::SeaPickle => self.sea_pickle_to_properties_map(), + BlockKind::BlueIce => self.blue_ice_to_properties_map(), + BlockKind::Conduit => self.conduit_to_properties_map(), + BlockKind::BambooSapling => self.bamboo_sapling_to_properties_map(), + BlockKind::Bamboo => self.bamboo_to_properties_map(), + BlockKind::PottedBamboo => self.potted_bamboo_to_properties_map(), + BlockKind::VoidAir => self.void_air_to_properties_map(), + BlockKind::CaveAir => self.cave_air_to_properties_map(), + BlockKind::BubbleColumn => self.bubble_column_to_properties_map(), + BlockKind::PolishedGraniteStairs => self.polished_granite_stairs_to_properties_map(), + BlockKind::SmoothRedSandstoneStairs => { + self.smooth_red_sandstone_stairs_to_properties_map() + } + BlockKind::MossyStoneBrickStairs => self.mossy_stone_brick_stairs_to_properties_map(), + BlockKind::PolishedDioriteStairs => self.polished_diorite_stairs_to_properties_map(), + BlockKind::MossyCobblestoneStairs => self.mossy_cobblestone_stairs_to_properties_map(), + BlockKind::EndStoneBrickStairs => self.end_stone_brick_stairs_to_properties_map(), + BlockKind::StoneStairs => self.stone_stairs_to_properties_map(), + BlockKind::SmoothSandstoneStairs => self.smooth_sandstone_stairs_to_properties_map(), + BlockKind::SmoothQuartzStairs => self.smooth_quartz_stairs_to_properties_map(), + BlockKind::GraniteStairs => self.granite_stairs_to_properties_map(), + BlockKind::AndesiteStairs => self.andesite_stairs_to_properties_map(), + BlockKind::RedNetherBrickStairs => self.red_nether_brick_stairs_to_properties_map(), + BlockKind::PolishedAndesiteStairs => self.polished_andesite_stairs_to_properties_map(), + BlockKind::DioriteStairs => self.diorite_stairs_to_properties_map(), + BlockKind::PolishedGraniteSlab => self.polished_granite_slab_to_properties_map(), + BlockKind::SmoothRedSandstoneSlab => self.smooth_red_sandstone_slab_to_properties_map(), + BlockKind::MossyStoneBrickSlab => self.mossy_stone_brick_slab_to_properties_map(), + BlockKind::PolishedDioriteSlab => self.polished_diorite_slab_to_properties_map(), + BlockKind::MossyCobblestoneSlab => self.mossy_cobblestone_slab_to_properties_map(), + BlockKind::EndStoneBrickSlab => self.end_stone_brick_slab_to_properties_map(), + BlockKind::SmoothSandstoneSlab => self.smooth_sandstone_slab_to_properties_map(), + BlockKind::SmoothQuartzSlab => self.smooth_quartz_slab_to_properties_map(), + BlockKind::GraniteSlab => self.granite_slab_to_properties_map(), + BlockKind::AndesiteSlab => self.andesite_slab_to_properties_map(), + BlockKind::RedNetherBrickSlab => self.red_nether_brick_slab_to_properties_map(), + BlockKind::PolishedAndesiteSlab => self.polished_andesite_slab_to_properties_map(), + BlockKind::DioriteSlab => self.diorite_slab_to_properties_map(), + BlockKind::BrickWall => self.brick_wall_to_properties_map(), + BlockKind::PrismarineWall => self.prismarine_wall_to_properties_map(), + BlockKind::RedSandstoneWall => self.red_sandstone_wall_to_properties_map(), + BlockKind::MossyStoneBrickWall => self.mossy_stone_brick_wall_to_properties_map(), + BlockKind::GraniteWall => self.granite_wall_to_properties_map(), + BlockKind::StoneBrickWall => self.stone_brick_wall_to_properties_map(), + BlockKind::NetherBrickWall => self.nether_brick_wall_to_properties_map(), + BlockKind::AndesiteWall => self.andesite_wall_to_properties_map(), + BlockKind::RedNetherBrickWall => self.red_nether_brick_wall_to_properties_map(), + BlockKind::SandstoneWall => self.sandstone_wall_to_properties_map(), + BlockKind::EndStoneBrickWall => self.end_stone_brick_wall_to_properties_map(), + BlockKind::DioriteWall => self.diorite_wall_to_properties_map(), + BlockKind::Scaffolding => self.scaffolding_to_properties_map(), + BlockKind::Loom => self.loom_to_properties_map(), + BlockKind::Barrel => self.barrel_to_properties_map(), + BlockKind::Smoker => self.smoker_to_properties_map(), + BlockKind::BlastFurnace => self.blast_furnace_to_properties_map(), + BlockKind::CartographyTable => self.cartography_table_to_properties_map(), + BlockKind::FletchingTable => self.fletching_table_to_properties_map(), + BlockKind::Grindstone => self.grindstone_to_properties_map(), + BlockKind::Lectern => self.lectern_to_properties_map(), + BlockKind::SmithingTable => self.smithing_table_to_properties_map(), + BlockKind::Stonecutter => self.stonecutter_to_properties_map(), + BlockKind::Bell => self.bell_to_properties_map(), + BlockKind::Lantern => self.lantern_to_properties_map(), + BlockKind::SoulLantern => self.soul_lantern_to_properties_map(), + BlockKind::Campfire => self.campfire_to_properties_map(), + BlockKind::SoulCampfire => self.soul_campfire_to_properties_map(), + BlockKind::SweetBerryBush => self.sweet_berry_bush_to_properties_map(), + BlockKind::WarpedStem => self.warped_stem_to_properties_map(), + BlockKind::StrippedWarpedStem => self.stripped_warped_stem_to_properties_map(), + BlockKind::WarpedHyphae => self.warped_hyphae_to_properties_map(), + BlockKind::StrippedWarpedHyphae => self.stripped_warped_hyphae_to_properties_map(), + BlockKind::WarpedNylium => self.warped_nylium_to_properties_map(), + BlockKind::WarpedFungus => self.warped_fungus_to_properties_map(), + BlockKind::WarpedWartBlock => self.warped_wart_block_to_properties_map(), + BlockKind::WarpedRoots => self.warped_roots_to_properties_map(), + BlockKind::NetherSprouts => self.nether_sprouts_to_properties_map(), + BlockKind::CrimsonStem => self.crimson_stem_to_properties_map(), + BlockKind::StrippedCrimsonStem => self.stripped_crimson_stem_to_properties_map(), + BlockKind::CrimsonHyphae => self.crimson_hyphae_to_properties_map(), + BlockKind::StrippedCrimsonHyphae => self.stripped_crimson_hyphae_to_properties_map(), + BlockKind::CrimsonNylium => self.crimson_nylium_to_properties_map(), + BlockKind::CrimsonFungus => self.crimson_fungus_to_properties_map(), + BlockKind::Shroomlight => self.shroomlight_to_properties_map(), + BlockKind::WeepingVines => self.weeping_vines_to_properties_map(), + BlockKind::WeepingVinesPlant => self.weeping_vines_plant_to_properties_map(), + BlockKind::TwistingVines => self.twisting_vines_to_properties_map(), + BlockKind::TwistingVinesPlant => self.twisting_vines_plant_to_properties_map(), + BlockKind::CrimsonRoots => self.crimson_roots_to_properties_map(), + BlockKind::CrimsonPlanks => self.crimson_planks_to_properties_map(), + BlockKind::WarpedPlanks => self.warped_planks_to_properties_map(), + BlockKind::CrimsonSlab => self.crimson_slab_to_properties_map(), + BlockKind::WarpedSlab => self.warped_slab_to_properties_map(), + BlockKind::CrimsonPressurePlate => self.crimson_pressure_plate_to_properties_map(), + BlockKind::WarpedPressurePlate => self.warped_pressure_plate_to_properties_map(), + BlockKind::CrimsonFence => self.crimson_fence_to_properties_map(), + BlockKind::WarpedFence => self.warped_fence_to_properties_map(), + BlockKind::CrimsonTrapdoor => self.crimson_trapdoor_to_properties_map(), + BlockKind::WarpedTrapdoor => self.warped_trapdoor_to_properties_map(), + BlockKind::CrimsonFenceGate => self.crimson_fence_gate_to_properties_map(), + BlockKind::WarpedFenceGate => self.warped_fence_gate_to_properties_map(), + BlockKind::CrimsonStairs => self.crimson_stairs_to_properties_map(), + BlockKind::WarpedStairs => self.warped_stairs_to_properties_map(), + BlockKind::CrimsonButton => self.crimson_button_to_properties_map(), + BlockKind::WarpedButton => self.warped_button_to_properties_map(), + BlockKind::CrimsonDoor => self.crimson_door_to_properties_map(), + BlockKind::WarpedDoor => self.warped_door_to_properties_map(), + BlockKind::CrimsonSign => self.crimson_sign_to_properties_map(), + BlockKind::WarpedSign => self.warped_sign_to_properties_map(), + BlockKind::CrimsonWallSign => self.crimson_wall_sign_to_properties_map(), + BlockKind::WarpedWallSign => self.warped_wall_sign_to_properties_map(), + BlockKind::StructureBlock => self.structure_block_to_properties_map(), + BlockKind::Jigsaw => self.jigsaw_to_properties_map(), + BlockKind::Composter => self.composter_to_properties_map(), + BlockKind::Target => self.target_to_properties_map(), + BlockKind::BeeNest => self.bee_nest_to_properties_map(), + BlockKind::Beehive => self.beehive_to_properties_map(), + BlockKind::HoneyBlock => self.honey_block_to_properties_map(), + BlockKind::HoneycombBlock => self.honeycomb_block_to_properties_map(), + BlockKind::NetheriteBlock => self.netherite_block_to_properties_map(), + BlockKind::AncientDebris => self.ancient_debris_to_properties_map(), + BlockKind::CryingObsidian => self.crying_obsidian_to_properties_map(), + BlockKind::RespawnAnchor => self.respawn_anchor_to_properties_map(), + BlockKind::PottedCrimsonFungus => self.potted_crimson_fungus_to_properties_map(), + BlockKind::PottedWarpedFungus => self.potted_warped_fungus_to_properties_map(), + BlockKind::PottedCrimsonRoots => self.potted_crimson_roots_to_properties_map(), + BlockKind::PottedWarpedRoots => self.potted_warped_roots_to_properties_map(), + BlockKind::Lodestone => self.lodestone_to_properties_map(), + BlockKind::Blackstone => self.blackstone_to_properties_map(), + BlockKind::BlackstoneStairs => self.blackstone_stairs_to_properties_map(), + BlockKind::BlackstoneWall => self.blackstone_wall_to_properties_map(), + BlockKind::BlackstoneSlab => self.blackstone_slab_to_properties_map(), + BlockKind::PolishedBlackstone => self.polished_blackstone_to_properties_map(), + BlockKind::PolishedBlackstoneBricks => { + self.polished_blackstone_bricks_to_properties_map() + } + BlockKind::CrackedPolishedBlackstoneBricks => { + self.cracked_polished_blackstone_bricks_to_properties_map() + } + BlockKind::ChiseledPolishedBlackstone => { + self.chiseled_polished_blackstone_to_properties_map() + } + BlockKind::PolishedBlackstoneBrickSlab => { + self.polished_blackstone_brick_slab_to_properties_map() + } + BlockKind::PolishedBlackstoneBrickStairs => { + self.polished_blackstone_brick_stairs_to_properties_map() + } + BlockKind::PolishedBlackstoneBrickWall => { + self.polished_blackstone_brick_wall_to_properties_map() + } + BlockKind::GildedBlackstone => self.gilded_blackstone_to_properties_map(), + BlockKind::PolishedBlackstoneStairs => { + self.polished_blackstone_stairs_to_properties_map() + } + BlockKind::PolishedBlackstoneSlab => self.polished_blackstone_slab_to_properties_map(), + BlockKind::PolishedBlackstonePressurePlate => { + self.polished_blackstone_pressure_plate_to_properties_map() + } + BlockKind::PolishedBlackstoneButton => { + self.polished_blackstone_button_to_properties_map() + } + BlockKind::PolishedBlackstoneWall => self.polished_blackstone_wall_to_properties_map(), + BlockKind::ChiseledNetherBricks => self.chiseled_nether_bricks_to_properties_map(), + BlockKind::CrackedNetherBricks => self.cracked_nether_bricks_to_properties_map(), + BlockKind::QuartzBricks => self.quartz_bricks_to_properties_map(), + } + } + fn air_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn stone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn granite_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn polished_granite_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn diorite_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn polished_diorite_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn andesite_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn polished_andesite_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn grass_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let snowy = self.snowy().unwrap(); + map.insert("snowy", { + match snowy { + true => "true", + false => "false", + } + }); + map + } + fn dirt_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn coarse_dirt_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn podzol_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let snowy = self.snowy().unwrap(); + map.insert("snowy", { + match snowy { + true => "true", + false => "false", + } + }); + map + } + fn cobblestone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn oak_planks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn spruce_planks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn birch_planks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn jungle_planks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn acacia_planks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dark_oak_planks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn oak_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let stage = self.stage().unwrap(); + map.insert("stage", { + match stage { + 0i32 => "0", + 1i32 => "1", + _ => "unknown", + } + }); + map + } + fn spruce_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let stage = self.stage().unwrap(); + map.insert("stage", { + match stage { + 0i32 => "0", + 1i32 => "1", + _ => "unknown", + } + }); + map + } + fn birch_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let stage = self.stage().unwrap(); + map.insert("stage", { + match stage { + 0i32 => "0", + 1i32 => "1", + _ => "unknown", + } + }); + map + } + fn jungle_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let stage = self.stage().unwrap(); + map.insert("stage", { + match stage { + 0i32 => "0", + 1i32 => "1", + _ => "unknown", + } + }); + map + } + fn acacia_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let stage = self.stage().unwrap(); + map.insert("stage", { + match stage { + 0i32 => "0", + 1i32 => "1", + _ => "unknown", + } + }); + map + } + fn dark_oak_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let stage = self.stage().unwrap(); + map.insert("stage", { + match stage { + 0i32 => "0", + 1i32 => "1", + _ => "unknown", + } + }); + map + } + fn bedrock_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn water_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let water_level = self.water_level().unwrap(); + map.insert("level", { + match water_level { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn lava_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let water_level = self.water_level().unwrap(); + map.insert("level", { + match water_level { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn sand_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_sand_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gravel_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gold_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn iron_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn coal_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn nether_gold_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn oak_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn spruce_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn birch_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn jungle_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn acacia_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn dark_oak_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_spruce_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_birch_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_jungle_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_acacia_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_dark_oak_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_oak_log_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn oak_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn spruce_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn birch_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn jungle_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn acacia_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn dark_oak_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_oak_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_spruce_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_birch_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_jungle_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_acacia_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_dark_oak_wood_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn oak_leaves_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let distance_1_7 = self.distance_1_7().unwrap(); + map.insert("distance", { + match distance_1_7 { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + let persistent = self.persistent().unwrap(); + map.insert("persistent", { + match persistent { + true => "true", + false => "false", + } + }); + map + } + fn spruce_leaves_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let distance_1_7 = self.distance_1_7().unwrap(); + map.insert("distance", { + match distance_1_7 { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + let persistent = self.persistent().unwrap(); + map.insert("persistent", { + match persistent { + true => "true", + false => "false", + } + }); + map + } + fn birch_leaves_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let distance_1_7 = self.distance_1_7().unwrap(); + map.insert("distance", { + match distance_1_7 { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + let persistent = self.persistent().unwrap(); + map.insert("persistent", { + match persistent { + true => "true", + false => "false", + } + }); + map + } + fn jungle_leaves_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let distance_1_7 = self.distance_1_7().unwrap(); + map.insert("distance", { + match distance_1_7 { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + let persistent = self.persistent().unwrap(); + map.insert("persistent", { + match persistent { + true => "true", + false => "false", + } + }); + map + } + fn acacia_leaves_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let distance_1_7 = self.distance_1_7().unwrap(); + map.insert("distance", { + match distance_1_7 { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + let persistent = self.persistent().unwrap(); + map.insert("persistent", { + match persistent { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_leaves_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let distance_1_7 = self.distance_1_7().unwrap(); + map.insert("distance", { + match distance_1_7 { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + let persistent = self.persistent().unwrap(); + map.insert("persistent", { + match persistent { + true => "true", + false => "false", + } + }); + map + } + fn sponge_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn wet_sponge_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lapis_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lapis_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dispenser_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + let triggered = self.triggered().unwrap(); + map.insert("triggered", { + match triggered { + true => "true", + false => "false", + } + }); + map + } + fn sandstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn chiseled_sandstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cut_sandstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn note_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let instrument = self.instrument().unwrap(); + map.insert("instrument", { instrument.as_str() }); + let note = self.note().unwrap(); + map.insert("note", { + match note { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + 16i32 => "16", + 17i32 => "17", + 18i32 => "18", + 19i32 => "19", + 20i32 => "20", + 21i32 => "21", + 22i32 => "22", + 23i32 => "23", + 24i32 => "24", + _ => "unknown", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn white_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn orange_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn magenta_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn light_blue_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn yellow_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn lime_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn pink_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn gray_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn light_gray_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn cyan_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn purple_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn blue_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn brown_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn green_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn red_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn black_bed_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let occupied = self.occupied().unwrap(); + map.insert("occupied", { + match occupied { + true => "true", + false => "false", + } + }); + let part = self.part().unwrap(); + map.insert("part", { part.as_str() }); + map + } + fn powered_rail_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let powered_rail_shape = self.powered_rail_shape().unwrap(); + map.insert("shape", { powered_rail_shape.as_str() }); + map + } + fn detector_rail_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let powered_rail_shape = self.powered_rail_shape().unwrap(); + map.insert("shape", { powered_rail_shape.as_str() }); + map + } + fn sticky_piston_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let extended = self.extended().unwrap(); + map.insert("extended", { + match extended { + true => "true", + false => "false", + } + }); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn cobweb_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn grass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn fern_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dead_bush_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn seagrass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn tall_seagrass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + map + } + fn piston_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let extended = self.extended().unwrap(); + map.insert("extended", { + match extended { + true => "true", + false => "false", + } + }); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn piston_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + let piston_kind = self.piston_kind().unwrap(); + map.insert("type", { piston_kind.as_str() }); + let short = self.short().unwrap(); + map.insert("short", { + match short { + true => "true", + false => "false", + } + }); + map + } + fn white_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn orange_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn magenta_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_blue_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn yellow_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lime_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn pink_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gray_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_gray_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cyan_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn purple_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blue_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brown_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn green_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn black_wool_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn moving_piston_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + let piston_kind = self.piston_kind().unwrap(); + map.insert("type", { piston_kind.as_str() }); + map + } + fn dandelion_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn poppy_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blue_orchid_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn allium_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn azure_bluet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_tulip_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn orange_tulip_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn white_tulip_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn pink_tulip_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn oxeye_daisy_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cornflower_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn wither_rose_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lily_of_the_valley_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brown_mushroom_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_mushroom_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gold_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn iron_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn tnt_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let unstable = self.unstable().unwrap(); + map.insert("unstable", { + match unstable { + true => "true", + false => "false", + } + }); + map + } + fn bookshelf_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn mossy_cobblestone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn obsidian_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn torch_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn wall_torch_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn fire_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_15 = self.age_0_15().unwrap(); + map.insert("age", { + match age_0_15 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn soul_fire_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn spawner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn oak_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn chest_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let chest_kind = self.chest_kind().unwrap(); + map.insert("type", { chest_kind.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn redstone_wire_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_wire = self.east_wire().unwrap(); + map.insert("east", { east_wire.as_str() }); + let north_wire = self.north_wire().unwrap(); + map.insert("north", { north_wire.as_str() }); + let power = self.power().unwrap(); + map.insert("power", { + match power { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let south_wire = self.south_wire().unwrap(); + map.insert("south", { south_wire.as_str() }); + let west_wire = self.west_wire().unwrap(); + map.insert("west", { west_wire.as_str() }); + map + } + fn diamond_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn diamond_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn crafting_table_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn wheat_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_7 = self.age_0_7().unwrap(); + map.insert("age", { + match age_0_7 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + map + } + fn farmland_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let moisture = self.moisture().unwrap(); + map.insert("moisture", { + match moisture { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + map + } + fn furnace_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + map + } + fn oak_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn spruce_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn birch_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn acacia_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn jungle_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn oak_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn ladder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn rail_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rail_shape = self.rail_shape().unwrap(); + map.insert("shape", { rail_shape.as_str() }); + map + } + fn cobblestone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn oak_wall_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn spruce_wall_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn birch_wall_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn acacia_wall_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn jungle_wall_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_wall_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn lever_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn stone_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn iron_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn oak_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn spruce_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn birch_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn jungle_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn acacia_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn redstone_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + map + } + fn redstone_torch_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + map + } + fn redstone_wall_torch_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + map + } + fn stone_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn snow_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let layers = self.layers().unwrap(); + map.insert("layers", { + match layers { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + _ => "unknown", + } + }); + map + } + fn ice_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn snow_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cactus_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_15 = self.age_0_15().unwrap(); + map.insert("age", { + match age_0_15 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn clay_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn sugar_cane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_15 = self.age_0_15().unwrap(); + map.insert("age", { + match age_0_15 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn jukebox_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let has_record = self.has_record().unwrap(); + map.insert("has_record", { + match has_record { + true => "true", + false => "false", + } + }); + map + } + fn oak_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn pumpkin_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn netherrack_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn soul_sand_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn soul_soil_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn basalt_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn polished_basalt_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn soul_torch_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn soul_wall_torch_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn glowstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn nether_portal_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xz = self.axis_xz().unwrap(); + map.insert("axis", { axis_xz.as_str() }); + map + } + fn carved_pumpkin_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn jack_o_lantern_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn cake_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let bites = self.bites().unwrap(); + map.insert("bites", { + match bites { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + _ => "unknown", + } + }); + map + } + fn repeater_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let delay = self.delay().unwrap(); + map.insert("delay", { + match delay { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + _ => "unknown", + } + }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let locked = self.locked().unwrap(); + map.insert("locked", { + match locked { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn white_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn orange_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn magenta_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_blue_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn yellow_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lime_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn pink_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gray_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_gray_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cyan_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn purple_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blue_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brown_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn green_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn black_stained_glass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn oak_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn spruce_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn birch_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn jungle_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn acacia_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn stone_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn mossy_stone_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cracked_stone_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn chiseled_stone_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn infested_stone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn infested_cobblestone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn infested_stone_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn infested_mossy_stone_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn infested_cracked_stone_bricks_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn infested_chiseled_stone_bricks_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brown_mushroom_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let down = self.down().unwrap(); + map.insert("down", { + match down { + true => "true", + false => "false", + } + }); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn red_mushroom_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let down = self.down().unwrap(); + map.insert("down", { + match down { + true => "true", + false => "false", + } + }); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn mushroom_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let down = self.down().unwrap(); + map.insert("down", { + match down { + true => "true", + false => "false", + } + }); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn iron_bars_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn chain_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn melon_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn attached_pumpkin_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn attached_melon_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn pumpkin_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_7 = self.age_0_7().unwrap(); + map.insert("age", { + match age_0_7 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + map + } + fn melon_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_7 = self.age_0_7().unwrap(); + map.insert("age", { + match age_0_7 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + map + } + fn vine_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn oak_fence_gate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let in_wall = self.in_wall().unwrap(); + map.insert("in_wall", { + match in_wall { + true => "true", + false => "false", + } + }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn brick_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn stone_brick_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn mycelium_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let snowy = self.snowy().unwrap(); + map.insert("snowy", { + match snowy { + true => "true", + false => "false", + } + }); + map + } + fn lily_pad_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn nether_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn nether_brick_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn nether_brick_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn nether_wart_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_3 = self.age_0_3().unwrap(); + map.insert("age", { + match age_0_3 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + _ => "unknown", + } + }); + map + } + fn enchanting_table_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brewing_stand_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let has_bottle_0 = self.has_bottle_0().unwrap(); + map.insert("has_bottle_0", { + match has_bottle_0 { + true => "true", + false => "false", + } + }); + let has_bottle_1 = self.has_bottle_1().unwrap(); + map.insert("has_bottle_1", { + match has_bottle_1 { + true => "true", + false => "false", + } + }); + let has_bottle_2 = self.has_bottle_2().unwrap(); + map.insert("has_bottle_2", { + match has_bottle_2 { + true => "true", + false => "false", + } + }); + map + } + fn cauldron_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let cauldron_level = self.cauldron_level().unwrap(); + map.insert("level", { + match cauldron_level { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + _ => "unknown", + } + }); + map + } + fn end_portal_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn end_portal_frame_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let eye = self.eye().unwrap(); + map.insert("eye", { + match eye { + true => "true", + false => "false", + } + }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn end_stone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dragon_egg_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn redstone_lamp_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + map + } + fn cocoa_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_2 = self.age_0_2().unwrap(); + map.insert("age", { + match age_0_2 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + _ => "unknown", + } + }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn sandstone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn emerald_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn ender_chest_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn tripwire_hook_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let attached = self.attached().unwrap(); + map.insert("attached", { + match attached { + true => "true", + false => "false", + } + }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn tripwire_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let attached = self.attached().unwrap(); + map.insert("attached", { + match attached { + true => "true", + false => "false", + } + }); + let disarmed = self.disarmed().unwrap(); + map.insert("disarmed", { + match disarmed { + true => "true", + false => "false", + } + }); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn emerald_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn spruce_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn birch_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn jungle_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn command_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let conditional = self.conditional().unwrap(); + map.insert("conditional", { + match conditional { + true => "true", + false => "false", + } + }); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn beacon_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cobblestone_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn mossy_cobblestone_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn flower_pot_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_oak_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_spruce_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_birch_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_jungle_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_acacia_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_dark_oak_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_fern_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_dandelion_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_poppy_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_blue_orchid_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_allium_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_azure_bluet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_red_tulip_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_orange_tulip_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_white_tulip_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_pink_tulip_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_oxeye_daisy_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_cornflower_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_lily_of_the_valley_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_wither_rose_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_red_mushroom_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_brown_mushroom_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_dead_bush_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_cactus_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn carrots_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_7 = self.age_0_7().unwrap(); + map.insert("age", { + match age_0_7 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + map + } + fn potatoes_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_7 = self.age_0_7().unwrap(); + map.insert("age", { + match age_0_7 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + map + } + fn oak_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn spruce_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn birch_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn jungle_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn acacia_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn skeleton_skull_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn skeleton_wall_skull_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn wither_skeleton_skull_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn wither_skeleton_wall_skull_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn zombie_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn zombie_wall_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn player_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn player_wall_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn creeper_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn creeper_wall_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn dragon_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn dragon_wall_head_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn anvil_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn chipped_anvil_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn damaged_anvil_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn trapped_chest_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let chest_kind = self.chest_kind().unwrap(); + map.insert("type", { chest_kind.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn light_weighted_pressure_plate_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let power = self.power().unwrap(); + map.insert("power", { + match power { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn heavy_weighted_pressure_plate_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let power = self.power().unwrap(); + map.insert("power", { + match power { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn comparator_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let comparator_mode = self.comparator_mode().unwrap(); + map.insert("mode", { comparator_mode.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn daylight_detector_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let inverted = self.inverted().unwrap(); + map.insert("inverted", { + match inverted { + true => "true", + false => "false", + } + }); + let power = self.power().unwrap(); + map.insert("power", { + match power { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn redstone_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn nether_quartz_ore_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn hopper_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let enabled = self.enabled().unwrap(); + map.insert("enabled", { + match enabled { + true => "true", + false => "false", + } + }); + let facing_cardinal_and_down = self.facing_cardinal_and_down().unwrap(); + map.insert("facing", { facing_cardinal_and_down.as_str() }); + map + } + fn quartz_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn chiseled_quartz_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn quartz_pillar_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn quartz_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn activator_rail_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let powered_rail_shape = self.powered_rail_shape().unwrap(); + map.insert("shape", { powered_rail_shape.as_str() }); + map + } + fn dropper_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + let triggered = self.triggered().unwrap(); + map.insert("triggered", { + match triggered { + true => "true", + false => "false", + } + }); + map + } + fn white_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn orange_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn magenta_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_blue_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn yellow_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lime_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn pink_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gray_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_gray_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cyan_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn purple_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blue_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brown_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn green_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn black_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn white_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn orange_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn magenta_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn light_blue_stained_glass_pane_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn yellow_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn lime_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn pink_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn gray_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn light_gray_stained_glass_pane_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn cyan_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn purple_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn blue_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn brown_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn green_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn red_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn black_stained_glass_pane_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn acacia_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn slime_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn barrier_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn iron_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn prismarine_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn prismarine_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dark_prismarine_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn prismarine_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn prismarine_brick_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dark_prismarine_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn prismarine_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn prismarine_brick_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dark_prismarine_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn sea_lantern_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn hay_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn white_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn orange_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn magenta_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_blue_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn yellow_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lime_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn pink_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gray_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_gray_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cyan_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn purple_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blue_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brown_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn green_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn black_carpet_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn coal_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn packed_ice_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn sunflower_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + map + } + fn lilac_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + map + } + fn rose_bush_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + map + } + fn peony_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + map + } + fn tall_grass_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + map + } + fn large_fern_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + map + } + fn white_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn orange_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn magenta_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn light_blue_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn yellow_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn lime_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn pink_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn gray_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn light_gray_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn cyan_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn purple_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn blue_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn brown_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn green_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn red_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn black_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn white_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn orange_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn magenta_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn light_blue_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn yellow_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn lime_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn pink_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn gray_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn light_gray_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn cyan_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn purple_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn blue_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn brown_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn green_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn red_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn black_wall_banner_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn red_sandstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn chiseled_red_sandstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cut_red_sandstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_sandstone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn oak_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn spruce_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn birch_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn jungle_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn acacia_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn stone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn smooth_stone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn sandstone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn cut_sandstone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn petrified_oak_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn cobblestone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn brick_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn stone_brick_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn nether_brick_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn quartz_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn red_sandstone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn cut_red_sandstone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn purpur_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn smooth_stone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn smooth_sandstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn smooth_quartz_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn smooth_red_sandstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn spruce_fence_gate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let in_wall = self.in_wall().unwrap(); + map.insert("in_wall", { + match in_wall { + true => "true", + false => "false", + } + }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn birch_fence_gate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let in_wall = self.in_wall().unwrap(); + map.insert("in_wall", { + match in_wall { + true => "true", + false => "false", + } + }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn jungle_fence_gate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let in_wall = self.in_wall().unwrap(); + map.insert("in_wall", { + match in_wall { + true => "true", + false => "false", + } + }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn acacia_fence_gate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let in_wall = self.in_wall().unwrap(); + map.insert("in_wall", { + match in_wall { + true => "true", + false => "false", + } + }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_fence_gate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let in_wall = self.in_wall().unwrap(); + map.insert("in_wall", { + match in_wall { + true => "true", + false => "false", + } + }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn spruce_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn birch_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn jungle_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn acacia_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn spruce_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn birch_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn jungle_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn acacia_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn dark_oak_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn end_rod_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn chorus_plant_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let down = self.down().unwrap(); + map.insert("down", { + match down { + true => "true", + false => "false", + } + }); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn chorus_flower_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_5 = self.age_0_5().unwrap(); + map.insert("age", { + match age_0_5 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + _ => "unknown", + } + }); + map + } + fn purpur_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn purpur_pillar_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn purpur_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn end_stone_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn beetroots_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_3 = self.age_0_3().unwrap(); + map.insert("age", { + match age_0_3 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + _ => "unknown", + } + }); + map + } + fn grass_path_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn end_gateway_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn repeating_command_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let conditional = self.conditional().unwrap(); + map.insert("conditional", { + match conditional { + true => "true", + false => "false", + } + }); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn chain_command_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let conditional = self.conditional().unwrap(); + map.insert("conditional", { + match conditional { + true => "true", + false => "false", + } + }); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn frosted_ice_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_3 = self.age_0_3().unwrap(); + map.insert("age", { + match age_0_3 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + _ => "unknown", + } + }); + map + } + fn magma_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn nether_wart_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_nether_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn bone_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn structure_void_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn observer_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn white_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn orange_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn magenta_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn light_blue_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn yellow_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn lime_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn pink_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn gray_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn light_gray_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn cyan_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn purple_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn blue_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn brown_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn green_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn red_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn black_shulker_box_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + map + } + fn white_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn orange_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn magenta_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn light_blue_glazed_terracotta_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn yellow_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn lime_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn pink_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn gray_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn light_gray_glazed_terracotta_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn cyan_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn purple_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn blue_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn brown_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn green_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn red_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn black_glazed_terracotta_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn white_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn orange_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn magenta_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_blue_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn yellow_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lime_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn pink_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gray_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_gray_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cyan_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn purple_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blue_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brown_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn green_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn black_concrete_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn white_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn orange_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn magenta_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_blue_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn yellow_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lime_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn pink_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn gray_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn light_gray_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cyan_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn purple_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blue_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brown_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn green_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn red_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn black_concrete_powder_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn kelp_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_25 = self.age_0_25().unwrap(); + map.insert("age", { + match age_0_25 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + 16i32 => "16", + 17i32 => "17", + 18i32 => "18", + 19i32 => "19", + 20i32 => "20", + 21i32 => "21", + 22i32 => "22", + 23i32 => "23", + 24i32 => "24", + 25i32 => "25", + _ => "unknown", + } + }); + map + } + fn kelp_plant_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dried_kelp_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn turtle_egg_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let eggs = self.eggs().unwrap(); + map.insert("eggs", { + match eggs { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + _ => "unknown", + } + }); + let hatch = self.hatch().unwrap(); + map.insert("hatch", { + match hatch { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + _ => "unknown", + } + }); + map + } + fn dead_tube_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dead_brain_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dead_bubble_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dead_fire_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dead_horn_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn tube_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn brain_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn bubble_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn fire_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn horn_coral_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn dead_tube_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_brain_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_bubble_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_fire_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_horn_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn tube_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn brain_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn bubble_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn fire_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn horn_coral_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_tube_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_brain_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_bubble_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_fire_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_horn_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn tube_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn brain_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn bubble_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn fire_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn horn_coral_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_tube_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_brain_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_bubble_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_fire_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn dead_horn_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn tube_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn brain_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn bubble_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn fire_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn horn_coral_wall_fan_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn sea_pickle_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let pickles = self.pickles().unwrap(); + map.insert("pickles", { + match pickles { + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn blue_ice_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn conduit_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn bamboo_sapling_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn bamboo_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_1 = self.age_0_1().unwrap(); + map.insert("age", { + match age_0_1 { + 0i32 => "0", + 1i32 => "1", + _ => "unknown", + } + }); + let leaves = self.leaves().unwrap(); + map.insert("leaves", { leaves.as_str() }); + let stage = self.stage().unwrap(); + map.insert("stage", { + match stage { + 0i32 => "0", + 1i32 => "1", + _ => "unknown", + } + }); + map + } + fn potted_bamboo_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn void_air_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cave_air_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn bubble_column_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let drag = self.drag().unwrap(); + map.insert("drag", { + match drag { + true => "true", + false => "false", + } + }); + map + } + fn polished_granite_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn smooth_red_sandstone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn mossy_stone_brick_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_diorite_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn mossy_cobblestone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn end_stone_brick_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn stone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn smooth_sandstone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn smooth_quartz_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn granite_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn andesite_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn red_nether_brick_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_andesite_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn diorite_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_granite_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn smooth_red_sandstone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn mossy_stone_brick_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_diorite_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn mossy_cobblestone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn end_stone_brick_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn smooth_sandstone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn smooth_quartz_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn granite_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn andesite_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn red_nether_brick_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_andesite_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn diorite_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn brick_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn prismarine_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn red_sandstone_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn mossy_stone_brick_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn granite_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn stone_brick_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn nether_brick_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn andesite_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn red_nether_brick_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn sandstone_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn end_stone_brick_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn diorite_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn scaffolding_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let bottom = self.bottom().unwrap(); + map.insert("bottom", { + match bottom { + true => "true", + false => "false", + } + }); + let distance_0_7 = self.distance_0_7().unwrap(); + map.insert("distance", { + match distance_0_7 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn loom_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn barrel_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cubic = self.facing_cubic().unwrap(); + map.insert("facing", { facing_cubic.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + map + } + fn smoker_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + map + } + fn blast_furnace_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + map + } + fn cartography_table_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn fletching_table_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn grindstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn lectern_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let has_book = self.has_book().unwrap(); + map.insert("has_book", { + match has_book { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn smithing_table_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn stonecutter_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + map + } + fn bell_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let attachment = self.attachment().unwrap(); + map.insert("attachment", { attachment.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn lantern_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let hanging = self.hanging().unwrap(); + map.insert("hanging", { + match hanging { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn soul_lantern_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let hanging = self.hanging().unwrap(); + map.insert("hanging", { + match hanging { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn campfire_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + let signal_fire = self.signal_fire().unwrap(); + map.insert("signal_fire", { + match signal_fire { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn soul_campfire_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let lit = self.lit().unwrap(); + map.insert("lit", { + match lit { + true => "true", + false => "false", + } + }); + let signal_fire = self.signal_fire().unwrap(); + map.insert("signal_fire", { + match signal_fire { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn sweet_berry_bush_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_3 = self.age_0_3().unwrap(); + map.insert("age", { + match age_0_3 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + _ => "unknown", + } + }); + map + } + fn warped_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_warped_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn warped_hyphae_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_warped_hyphae_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn warped_nylium_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn warped_fungus_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn warped_wart_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn warped_roots_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn nether_sprouts_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn crimson_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_crimson_stem_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn crimson_hyphae_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn stripped_crimson_hyphae_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let axis_xyz = self.axis_xyz().unwrap(); + map.insert("axis", { axis_xyz.as_str() }); + map + } + fn crimson_nylium_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn crimson_fungus_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn shroomlight_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn weeping_vines_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_25 = self.age_0_25().unwrap(); + map.insert("age", { + match age_0_25 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + 16i32 => "16", + 17i32 => "17", + 18i32 => "18", + 19i32 => "19", + 20i32 => "20", + 21i32 => "21", + 22i32 => "22", + 23i32 => "23", + 24i32 => "24", + 25i32 => "25", + _ => "unknown", + } + }); + map + } + fn weeping_vines_plant_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn twisting_vines_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let age_0_25 = self.age_0_25().unwrap(); + map.insert("age", { + match age_0_25 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + 16i32 => "16", + 17i32 => "17", + 18i32 => "18", + 19i32 => "19", + 20i32 => "20", + 21i32 => "21", + 22i32 => "22", + 23i32 => "23", + 24i32 => "24", + 25i32 => "25", + _ => "unknown", + } + }); + map + } + fn twisting_vines_plant_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn crimson_roots_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn crimson_planks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn warped_planks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn crimson_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn warped_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn crimson_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn warped_pressure_plate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn crimson_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn warped_fence_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_connected = self.east_connected().unwrap(); + map.insert("east", { + match east_connected { + true => "true", + false => "false", + } + }); + let north_connected = self.north_connected().unwrap(); + map.insert("north", { + match north_connected { + true => "true", + false => "false", + } + }); + let south_connected = self.south_connected().unwrap(); + map.insert("south", { + match south_connected { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_connected = self.west_connected().unwrap(); + map.insert("west", { + match west_connected { + true => "true", + false => "false", + } + }); + map + } + fn crimson_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn warped_trapdoor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn crimson_fence_gate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let in_wall = self.in_wall().unwrap(); + map.insert("in_wall", { + match in_wall { + true => "true", + false => "false", + } + }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn warped_fence_gate_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let in_wall = self.in_wall().unwrap(); + map.insert("in_wall", { + match in_wall { + true => "true", + false => "false", + } + }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn crimson_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn warped_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn crimson_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn warped_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn crimson_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn warped_door_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_upper_lower = self.half_upper_lower().unwrap(); + map.insert("half", { half_upper_lower.as_str() }); + let hinge = self.hinge().unwrap(); + map.insert("hinge", { hinge.as_str() }); + let open = self.open().unwrap(); + map.insert("open", { + match open { + true => "true", + false => "false", + } + }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn crimson_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn warped_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let rotation = self.rotation().unwrap(); + map.insert("rotation", { + match rotation { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn crimson_wall_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn warped_wall_sign_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn structure_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let structure_block_mode = self.structure_block_mode().unwrap(); + map.insert("mode", { structure_block_mode.as_str() }); + map + } + fn jigsaw_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let orientation = self.orientation().unwrap(); + map.insert("orientation", { orientation.as_str() }); + map + } + fn composter_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let level_0_8 = self.level_0_8().unwrap(); + map.insert("level", { + match level_0_8 { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + _ => "unknown", + } + }); + map + } + fn target_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let power = self.power().unwrap(); + map.insert("power", { + match power { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + 6i32 => "6", + 7i32 => "7", + 8i32 => "8", + 9i32 => "9", + 10i32 => "10", + 11i32 => "11", + 12i32 => "12", + 13i32 => "13", + 14i32 => "14", + 15i32 => "15", + _ => "unknown", + } + }); + map + } + fn bee_nest_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let honey_level = self.honey_level().unwrap(); + map.insert("honey_level", { + match honey_level { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + _ => "unknown", + } + }); + map + } + fn beehive_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let honey_level = self.honey_level().unwrap(); + map.insert("honey_level", { + match honey_level { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + 5i32 => "5", + _ => "unknown", + } + }); + map + } + fn honey_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn honeycomb_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn netherite_block_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn ancient_debris_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn crying_obsidian_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn respawn_anchor_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let charges = self.charges().unwrap(); + map.insert("charges", { + match charges { + 0i32 => "0", + 1i32 => "1", + 2i32 => "2", + 3i32 => "3", + 4i32 => "4", + _ => "unknown", + } + }); + map + } + fn potted_crimson_fungus_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_warped_fungus_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_crimson_roots_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn potted_warped_roots_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn lodestone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blackstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn blackstone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn blackstone_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn blackstone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_blackstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn polished_blackstone_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cracked_polished_blackstone_bricks_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn chiseled_polished_blackstone_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn polished_blackstone_brick_slab_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_blackstone_brick_stairs_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_blackstone_brick_wall_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn gilded_blackstone_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn polished_blackstone_stairs_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let half_top_bottom = self.half_top_bottom().unwrap(); + map.insert("half", { half_top_bottom.as_str() }); + let stairs_shape = self.stairs_shape().unwrap(); + map.insert("shape", { stairs_shape.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_blackstone_slab_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let slab_kind = self.slab_kind().unwrap(); + map.insert("type", { slab_kind.as_str() }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + map + } + fn polished_blackstone_pressure_plate_to_properties_map( + self, + ) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn polished_blackstone_button_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let face = self.face().unwrap(); + map.insert("face", { face.as_str() }); + let facing_cardinal = self.facing_cardinal().unwrap(); + map.insert("facing", { facing_cardinal.as_str() }); + let powered = self.powered().unwrap(); + map.insert("powered", { + match powered { + true => "true", + false => "false", + } + }); + map + } + fn polished_blackstone_wall_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + let east_nlt = self.east_nlt().unwrap(); + map.insert("east", { east_nlt.as_str() }); + let north_nlt = self.north_nlt().unwrap(); + map.insert("north", { north_nlt.as_str() }); + let south_nlt = self.south_nlt().unwrap(); + map.insert("south", { south_nlt.as_str() }); + let up = self.up().unwrap(); + map.insert("up", { + match up { + true => "true", + false => "false", + } + }); + let waterlogged = self.waterlogged().unwrap(); + map.insert("waterlogged", { + match waterlogged { + true => "true", + false => "false", + } + }); + let west_nlt = self.west_nlt().unwrap(); + map.insert("west", { west_nlt.as_str() }); + map + } + fn chiseled_nether_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn cracked_nether_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + fn quartz_bricks_to_properties_map(self) -> BTreeMap<&'static str, &'static str> { + let mut map = BTreeMap::new(); + map + } + #[doc = "Attempts to convert a block kind identifier (e.g. `minecraft::air`) and properties map to a `BlockId`."] + pub fn from_identifier_and_properties( + identifier: &str, + properties: &BTreeMap, + ) -> Option { + match identifier { + "minecraft:air" => Self::air_from_identifier_and_properties(properties), + "minecraft:stone" => Self::stone_from_identifier_and_properties(properties), + "minecraft:granite" => Self::granite_from_identifier_and_properties(properties), + "minecraft:polished_granite" => { + Self::polished_granite_from_identifier_and_properties(properties) + } + "minecraft:diorite" => Self::diorite_from_identifier_and_properties(properties), + "minecraft:polished_diorite" => { + Self::polished_diorite_from_identifier_and_properties(properties) + } + "minecraft:andesite" => Self::andesite_from_identifier_and_properties(properties), + "minecraft:polished_andesite" => { + Self::polished_andesite_from_identifier_and_properties(properties) + } + "minecraft:grass_block" => Self::grass_block_from_identifier_and_properties(properties), + "minecraft:dirt" => Self::dirt_from_identifier_and_properties(properties), + "minecraft:coarse_dirt" => Self::coarse_dirt_from_identifier_and_properties(properties), + "minecraft:podzol" => Self::podzol_from_identifier_and_properties(properties), + "minecraft:cobblestone" => Self::cobblestone_from_identifier_and_properties(properties), + "minecraft:oak_planks" => Self::oak_planks_from_identifier_and_properties(properties), + "minecraft:spruce_planks" => { + Self::spruce_planks_from_identifier_and_properties(properties) + } + "minecraft:birch_planks" => { + Self::birch_planks_from_identifier_and_properties(properties) + } + "minecraft:jungle_planks" => { + Self::jungle_planks_from_identifier_and_properties(properties) + } + "minecraft:acacia_planks" => { + Self::acacia_planks_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_planks" => { + Self::dark_oak_planks_from_identifier_and_properties(properties) + } + "minecraft:oak_sapling" => Self::oak_sapling_from_identifier_and_properties(properties), + "minecraft:spruce_sapling" => { + Self::spruce_sapling_from_identifier_and_properties(properties) + } + "minecraft:birch_sapling" => { + Self::birch_sapling_from_identifier_and_properties(properties) + } + "minecraft:jungle_sapling" => { + Self::jungle_sapling_from_identifier_and_properties(properties) + } + "minecraft:acacia_sapling" => { + Self::acacia_sapling_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_sapling" => { + Self::dark_oak_sapling_from_identifier_and_properties(properties) + } + "minecraft:bedrock" => Self::bedrock_from_identifier_and_properties(properties), + "minecraft:water" => Self::water_from_identifier_and_properties(properties), + "minecraft:lava" => Self::lava_from_identifier_and_properties(properties), + "minecraft:sand" => Self::sand_from_identifier_and_properties(properties), + "minecraft:red_sand" => Self::red_sand_from_identifier_and_properties(properties), + "minecraft:gravel" => Self::gravel_from_identifier_and_properties(properties), + "minecraft:gold_ore" => Self::gold_ore_from_identifier_and_properties(properties), + "minecraft:iron_ore" => Self::iron_ore_from_identifier_and_properties(properties), + "minecraft:coal_ore" => Self::coal_ore_from_identifier_and_properties(properties), + "minecraft:nether_gold_ore" => { + Self::nether_gold_ore_from_identifier_and_properties(properties) + } + "minecraft:oak_log" => Self::oak_log_from_identifier_and_properties(properties), + "minecraft:spruce_log" => Self::spruce_log_from_identifier_and_properties(properties), + "minecraft:birch_log" => Self::birch_log_from_identifier_and_properties(properties), + "minecraft:jungle_log" => Self::jungle_log_from_identifier_and_properties(properties), + "minecraft:acacia_log" => Self::acacia_log_from_identifier_and_properties(properties), + "minecraft:dark_oak_log" => { + Self::dark_oak_log_from_identifier_and_properties(properties) + } + "minecraft:stripped_spruce_log" => { + Self::stripped_spruce_log_from_identifier_and_properties(properties) + } + "minecraft:stripped_birch_log" => { + Self::stripped_birch_log_from_identifier_and_properties(properties) + } + "minecraft:stripped_jungle_log" => { + Self::stripped_jungle_log_from_identifier_and_properties(properties) + } + "minecraft:stripped_acacia_log" => { + Self::stripped_acacia_log_from_identifier_and_properties(properties) + } + "minecraft:stripped_dark_oak_log" => { + Self::stripped_dark_oak_log_from_identifier_and_properties(properties) + } + "minecraft:stripped_oak_log" => { + Self::stripped_oak_log_from_identifier_and_properties(properties) + } + "minecraft:oak_wood" => Self::oak_wood_from_identifier_and_properties(properties), + "minecraft:spruce_wood" => Self::spruce_wood_from_identifier_and_properties(properties), + "minecraft:birch_wood" => Self::birch_wood_from_identifier_and_properties(properties), + "minecraft:jungle_wood" => Self::jungle_wood_from_identifier_and_properties(properties), + "minecraft:acacia_wood" => Self::acacia_wood_from_identifier_and_properties(properties), + "minecraft:dark_oak_wood" => { + Self::dark_oak_wood_from_identifier_and_properties(properties) + } + "minecraft:stripped_oak_wood" => { + Self::stripped_oak_wood_from_identifier_and_properties(properties) + } + "minecraft:stripped_spruce_wood" => { + Self::stripped_spruce_wood_from_identifier_and_properties(properties) + } + "minecraft:stripped_birch_wood" => { + Self::stripped_birch_wood_from_identifier_and_properties(properties) + } + "minecraft:stripped_jungle_wood" => { + Self::stripped_jungle_wood_from_identifier_and_properties(properties) + } + "minecraft:stripped_acacia_wood" => { + Self::stripped_acacia_wood_from_identifier_and_properties(properties) + } + "minecraft:stripped_dark_oak_wood" => { + Self::stripped_dark_oak_wood_from_identifier_and_properties(properties) + } + "minecraft:oak_leaves" => Self::oak_leaves_from_identifier_and_properties(properties), + "minecraft:spruce_leaves" => { + Self::spruce_leaves_from_identifier_and_properties(properties) + } + "minecraft:birch_leaves" => { + Self::birch_leaves_from_identifier_and_properties(properties) + } + "minecraft:jungle_leaves" => { + Self::jungle_leaves_from_identifier_and_properties(properties) + } + "minecraft:acacia_leaves" => { + Self::acacia_leaves_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_leaves" => { + Self::dark_oak_leaves_from_identifier_and_properties(properties) + } + "minecraft:sponge" => Self::sponge_from_identifier_and_properties(properties), + "minecraft:wet_sponge" => Self::wet_sponge_from_identifier_and_properties(properties), + "minecraft:glass" => Self::glass_from_identifier_and_properties(properties), + "minecraft:lapis_ore" => Self::lapis_ore_from_identifier_and_properties(properties), + "minecraft:lapis_block" => Self::lapis_block_from_identifier_and_properties(properties), + "minecraft:dispenser" => Self::dispenser_from_identifier_and_properties(properties), + "minecraft:sandstone" => Self::sandstone_from_identifier_and_properties(properties), + "minecraft:chiseled_sandstone" => { + Self::chiseled_sandstone_from_identifier_and_properties(properties) + } + "minecraft:cut_sandstone" => { + Self::cut_sandstone_from_identifier_and_properties(properties) + } + "minecraft:note_block" => Self::note_block_from_identifier_and_properties(properties), + "minecraft:white_bed" => Self::white_bed_from_identifier_and_properties(properties), + "minecraft:orange_bed" => Self::orange_bed_from_identifier_and_properties(properties), + "minecraft:magenta_bed" => Self::magenta_bed_from_identifier_and_properties(properties), + "minecraft:light_blue_bed" => { + Self::light_blue_bed_from_identifier_and_properties(properties) + } + "minecraft:yellow_bed" => Self::yellow_bed_from_identifier_and_properties(properties), + "minecraft:lime_bed" => Self::lime_bed_from_identifier_and_properties(properties), + "minecraft:pink_bed" => Self::pink_bed_from_identifier_and_properties(properties), + "minecraft:gray_bed" => Self::gray_bed_from_identifier_and_properties(properties), + "minecraft:light_gray_bed" => { + Self::light_gray_bed_from_identifier_and_properties(properties) + } + "minecraft:cyan_bed" => Self::cyan_bed_from_identifier_and_properties(properties), + "minecraft:purple_bed" => Self::purple_bed_from_identifier_and_properties(properties), + "minecraft:blue_bed" => Self::blue_bed_from_identifier_and_properties(properties), + "minecraft:brown_bed" => Self::brown_bed_from_identifier_and_properties(properties), + "minecraft:green_bed" => Self::green_bed_from_identifier_and_properties(properties), + "minecraft:red_bed" => Self::red_bed_from_identifier_and_properties(properties), + "minecraft:black_bed" => Self::black_bed_from_identifier_and_properties(properties), + "minecraft:powered_rail" => { + Self::powered_rail_from_identifier_and_properties(properties) + } + "minecraft:detector_rail" => { + Self::detector_rail_from_identifier_and_properties(properties) + } + "minecraft:sticky_piston" => { + Self::sticky_piston_from_identifier_and_properties(properties) + } + "minecraft:cobweb" => Self::cobweb_from_identifier_and_properties(properties), + "minecraft:grass" => Self::grass_from_identifier_and_properties(properties), + "minecraft:fern" => Self::fern_from_identifier_and_properties(properties), + "minecraft:dead_bush" => Self::dead_bush_from_identifier_and_properties(properties), + "minecraft:seagrass" => Self::seagrass_from_identifier_and_properties(properties), + "minecraft:tall_seagrass" => { + Self::tall_seagrass_from_identifier_and_properties(properties) + } + "minecraft:piston" => Self::piston_from_identifier_and_properties(properties), + "minecraft:piston_head" => Self::piston_head_from_identifier_and_properties(properties), + "minecraft:white_wool" => Self::white_wool_from_identifier_and_properties(properties), + "minecraft:orange_wool" => Self::orange_wool_from_identifier_and_properties(properties), + "minecraft:magenta_wool" => { + Self::magenta_wool_from_identifier_and_properties(properties) + } + "minecraft:light_blue_wool" => { + Self::light_blue_wool_from_identifier_and_properties(properties) + } + "minecraft:yellow_wool" => Self::yellow_wool_from_identifier_and_properties(properties), + "minecraft:lime_wool" => Self::lime_wool_from_identifier_and_properties(properties), + "minecraft:pink_wool" => Self::pink_wool_from_identifier_and_properties(properties), + "minecraft:gray_wool" => Self::gray_wool_from_identifier_and_properties(properties), + "minecraft:light_gray_wool" => { + Self::light_gray_wool_from_identifier_and_properties(properties) + } + "minecraft:cyan_wool" => Self::cyan_wool_from_identifier_and_properties(properties), + "minecraft:purple_wool" => Self::purple_wool_from_identifier_and_properties(properties), + "minecraft:blue_wool" => Self::blue_wool_from_identifier_and_properties(properties), + "minecraft:brown_wool" => Self::brown_wool_from_identifier_and_properties(properties), + "minecraft:green_wool" => Self::green_wool_from_identifier_and_properties(properties), + "minecraft:red_wool" => Self::red_wool_from_identifier_and_properties(properties), + "minecraft:black_wool" => Self::black_wool_from_identifier_and_properties(properties), + "minecraft:moving_piston" => { + Self::moving_piston_from_identifier_and_properties(properties) + } + "minecraft:dandelion" => Self::dandelion_from_identifier_and_properties(properties), + "minecraft:poppy" => Self::poppy_from_identifier_and_properties(properties), + "minecraft:blue_orchid" => Self::blue_orchid_from_identifier_and_properties(properties), + "minecraft:allium" => Self::allium_from_identifier_and_properties(properties), + "minecraft:azure_bluet" => Self::azure_bluet_from_identifier_and_properties(properties), + "minecraft:red_tulip" => Self::red_tulip_from_identifier_and_properties(properties), + "minecraft:orange_tulip" => { + Self::orange_tulip_from_identifier_and_properties(properties) + } + "minecraft:white_tulip" => Self::white_tulip_from_identifier_and_properties(properties), + "minecraft:pink_tulip" => Self::pink_tulip_from_identifier_and_properties(properties), + "minecraft:oxeye_daisy" => Self::oxeye_daisy_from_identifier_and_properties(properties), + "minecraft:cornflower" => Self::cornflower_from_identifier_and_properties(properties), + "minecraft:wither_rose" => Self::wither_rose_from_identifier_and_properties(properties), + "minecraft:lily_of_the_valley" => { + Self::lily_of_the_valley_from_identifier_and_properties(properties) + } + "minecraft:brown_mushroom" => { + Self::brown_mushroom_from_identifier_and_properties(properties) + } + "minecraft:red_mushroom" => { + Self::red_mushroom_from_identifier_and_properties(properties) + } + "minecraft:gold_block" => Self::gold_block_from_identifier_and_properties(properties), + "minecraft:iron_block" => Self::iron_block_from_identifier_and_properties(properties), + "minecraft:bricks" => Self::bricks_from_identifier_and_properties(properties), + "minecraft:tnt" => Self::tnt_from_identifier_and_properties(properties), + "minecraft:bookshelf" => Self::bookshelf_from_identifier_and_properties(properties), + "minecraft:mossy_cobblestone" => { + Self::mossy_cobblestone_from_identifier_and_properties(properties) + } + "minecraft:obsidian" => Self::obsidian_from_identifier_and_properties(properties), + "minecraft:torch" => Self::torch_from_identifier_and_properties(properties), + "minecraft:wall_torch" => Self::wall_torch_from_identifier_and_properties(properties), + "minecraft:fire" => Self::fire_from_identifier_and_properties(properties), + "minecraft:soul_fire" => Self::soul_fire_from_identifier_and_properties(properties), + "minecraft:spawner" => Self::spawner_from_identifier_and_properties(properties), + "minecraft:oak_stairs" => Self::oak_stairs_from_identifier_and_properties(properties), + "minecraft:chest" => Self::chest_from_identifier_and_properties(properties), + "minecraft:redstone_wire" => { + Self::redstone_wire_from_identifier_and_properties(properties) + } + "minecraft:diamond_ore" => Self::diamond_ore_from_identifier_and_properties(properties), + "minecraft:diamond_block" => { + Self::diamond_block_from_identifier_and_properties(properties) + } + "minecraft:crafting_table" => { + Self::crafting_table_from_identifier_and_properties(properties) + } + "minecraft:wheat" => Self::wheat_from_identifier_and_properties(properties), + "minecraft:farmland" => Self::farmland_from_identifier_and_properties(properties), + "minecraft:furnace" => Self::furnace_from_identifier_and_properties(properties), + "minecraft:oak_sign" => Self::oak_sign_from_identifier_and_properties(properties), + "minecraft:spruce_sign" => Self::spruce_sign_from_identifier_and_properties(properties), + "minecraft:birch_sign" => Self::birch_sign_from_identifier_and_properties(properties), + "minecraft:acacia_sign" => Self::acacia_sign_from_identifier_and_properties(properties), + "minecraft:jungle_sign" => Self::jungle_sign_from_identifier_and_properties(properties), + "minecraft:dark_oak_sign" => { + Self::dark_oak_sign_from_identifier_and_properties(properties) + } + "minecraft:oak_door" => Self::oak_door_from_identifier_and_properties(properties), + "minecraft:ladder" => Self::ladder_from_identifier_and_properties(properties), + "minecraft:rail" => Self::rail_from_identifier_and_properties(properties), + "minecraft:cobblestone_stairs" => { + Self::cobblestone_stairs_from_identifier_and_properties(properties) + } + "minecraft:oak_wall_sign" => { + Self::oak_wall_sign_from_identifier_and_properties(properties) + } + "minecraft:spruce_wall_sign" => { + Self::spruce_wall_sign_from_identifier_and_properties(properties) + } + "minecraft:birch_wall_sign" => { + Self::birch_wall_sign_from_identifier_and_properties(properties) + } + "minecraft:acacia_wall_sign" => { + Self::acacia_wall_sign_from_identifier_and_properties(properties) + } + "minecraft:jungle_wall_sign" => { + Self::jungle_wall_sign_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_wall_sign" => { + Self::dark_oak_wall_sign_from_identifier_and_properties(properties) + } + "minecraft:lever" => Self::lever_from_identifier_and_properties(properties), + "minecraft:stone_pressure_plate" => { + Self::stone_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:iron_door" => Self::iron_door_from_identifier_and_properties(properties), + "minecraft:oak_pressure_plate" => { + Self::oak_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:spruce_pressure_plate" => { + Self::spruce_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:birch_pressure_plate" => { + Self::birch_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:jungle_pressure_plate" => { + Self::jungle_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:acacia_pressure_plate" => { + Self::acacia_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_pressure_plate" => { + Self::dark_oak_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:redstone_ore" => { + Self::redstone_ore_from_identifier_and_properties(properties) + } + "minecraft:redstone_torch" => { + Self::redstone_torch_from_identifier_and_properties(properties) + } + "minecraft:redstone_wall_torch" => { + Self::redstone_wall_torch_from_identifier_and_properties(properties) + } + "minecraft:stone_button" => { + Self::stone_button_from_identifier_and_properties(properties) + } + "minecraft:snow" => Self::snow_from_identifier_and_properties(properties), + "minecraft:ice" => Self::ice_from_identifier_and_properties(properties), + "minecraft:snow_block" => Self::snow_block_from_identifier_and_properties(properties), + "minecraft:cactus" => Self::cactus_from_identifier_and_properties(properties), + "minecraft:clay" => Self::clay_from_identifier_and_properties(properties), + "minecraft:sugar_cane" => Self::sugar_cane_from_identifier_and_properties(properties), + "minecraft:jukebox" => Self::jukebox_from_identifier_and_properties(properties), + "minecraft:oak_fence" => Self::oak_fence_from_identifier_and_properties(properties), + "minecraft:pumpkin" => Self::pumpkin_from_identifier_and_properties(properties), + "minecraft:netherrack" => Self::netherrack_from_identifier_and_properties(properties), + "minecraft:soul_sand" => Self::soul_sand_from_identifier_and_properties(properties), + "minecraft:soul_soil" => Self::soul_soil_from_identifier_and_properties(properties), + "minecraft:basalt" => Self::basalt_from_identifier_and_properties(properties), + "minecraft:polished_basalt" => { + Self::polished_basalt_from_identifier_and_properties(properties) + } + "minecraft:soul_torch" => Self::soul_torch_from_identifier_and_properties(properties), + "minecraft:soul_wall_torch" => { + Self::soul_wall_torch_from_identifier_and_properties(properties) + } + "minecraft:glowstone" => Self::glowstone_from_identifier_and_properties(properties), + "minecraft:nether_portal" => { + Self::nether_portal_from_identifier_and_properties(properties) + } + "minecraft:carved_pumpkin" => { + Self::carved_pumpkin_from_identifier_and_properties(properties) + } + "minecraft:jack_o_lantern" => { + Self::jack_o_lantern_from_identifier_and_properties(properties) + } + "minecraft:cake" => Self::cake_from_identifier_and_properties(properties), + "minecraft:repeater" => Self::repeater_from_identifier_and_properties(properties), + "minecraft:white_stained_glass" => { + Self::white_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:orange_stained_glass" => { + Self::orange_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:magenta_stained_glass" => { + Self::magenta_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:light_blue_stained_glass" => { + Self::light_blue_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:yellow_stained_glass" => { + Self::yellow_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:lime_stained_glass" => { + Self::lime_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:pink_stained_glass" => { + Self::pink_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:gray_stained_glass" => { + Self::gray_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:light_gray_stained_glass" => { + Self::light_gray_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:cyan_stained_glass" => { + Self::cyan_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:purple_stained_glass" => { + Self::purple_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:blue_stained_glass" => { + Self::blue_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:brown_stained_glass" => { + Self::brown_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:green_stained_glass" => { + Self::green_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:red_stained_glass" => { + Self::red_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:black_stained_glass" => { + Self::black_stained_glass_from_identifier_and_properties(properties) + } + "minecraft:oak_trapdoor" => { + Self::oak_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:spruce_trapdoor" => { + Self::spruce_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:birch_trapdoor" => { + Self::birch_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:jungle_trapdoor" => { + Self::jungle_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:acacia_trapdoor" => { + Self::acacia_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_trapdoor" => { + Self::dark_oak_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:stone_bricks" => { + Self::stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:mossy_stone_bricks" => { + Self::mossy_stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:cracked_stone_bricks" => { + Self::cracked_stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:chiseled_stone_bricks" => { + Self::chiseled_stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:infested_stone" => { + Self::infested_stone_from_identifier_and_properties(properties) + } + "minecraft:infested_cobblestone" => { + Self::infested_cobblestone_from_identifier_and_properties(properties) + } + "minecraft:infested_stone_bricks" => { + Self::infested_stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:infested_mossy_stone_bricks" => { + Self::infested_mossy_stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:infested_cracked_stone_bricks" => { + Self::infested_cracked_stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:infested_chiseled_stone_bricks" => { + Self::infested_chiseled_stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:brown_mushroom_block" => { + Self::brown_mushroom_block_from_identifier_and_properties(properties) + } + "minecraft:red_mushroom_block" => { + Self::red_mushroom_block_from_identifier_and_properties(properties) + } + "minecraft:mushroom_stem" => { + Self::mushroom_stem_from_identifier_and_properties(properties) + } + "minecraft:iron_bars" => Self::iron_bars_from_identifier_and_properties(properties), + "minecraft:chain" => Self::chain_from_identifier_and_properties(properties), + "minecraft:glass_pane" => Self::glass_pane_from_identifier_and_properties(properties), + "minecraft:melon" => Self::melon_from_identifier_and_properties(properties), + "minecraft:attached_pumpkin_stem" => { + Self::attached_pumpkin_stem_from_identifier_and_properties(properties) + } + "minecraft:attached_melon_stem" => { + Self::attached_melon_stem_from_identifier_and_properties(properties) + } + "minecraft:pumpkin_stem" => { + Self::pumpkin_stem_from_identifier_and_properties(properties) + } + "minecraft:melon_stem" => Self::melon_stem_from_identifier_and_properties(properties), + "minecraft:vine" => Self::vine_from_identifier_and_properties(properties), + "minecraft:oak_fence_gate" => { + Self::oak_fence_gate_from_identifier_and_properties(properties) + } + "minecraft:brick_stairs" => { + Self::brick_stairs_from_identifier_and_properties(properties) + } + "minecraft:stone_brick_stairs" => { + Self::stone_brick_stairs_from_identifier_and_properties(properties) + } + "minecraft:mycelium" => Self::mycelium_from_identifier_and_properties(properties), + "minecraft:lily_pad" => Self::lily_pad_from_identifier_and_properties(properties), + "minecraft:nether_bricks" => { + Self::nether_bricks_from_identifier_and_properties(properties) + } + "minecraft:nether_brick_fence" => { + Self::nether_brick_fence_from_identifier_and_properties(properties) + } + "minecraft:nether_brick_stairs" => { + Self::nether_brick_stairs_from_identifier_and_properties(properties) + } + "minecraft:nether_wart" => Self::nether_wart_from_identifier_and_properties(properties), + "minecraft:enchanting_table" => { + Self::enchanting_table_from_identifier_and_properties(properties) + } + "minecraft:brewing_stand" => { + Self::brewing_stand_from_identifier_and_properties(properties) + } + "minecraft:cauldron" => Self::cauldron_from_identifier_and_properties(properties), + "minecraft:end_portal" => Self::end_portal_from_identifier_and_properties(properties), + "minecraft:end_portal_frame" => { + Self::end_portal_frame_from_identifier_and_properties(properties) + } + "minecraft:end_stone" => Self::end_stone_from_identifier_and_properties(properties), + "minecraft:dragon_egg" => Self::dragon_egg_from_identifier_and_properties(properties), + "minecraft:redstone_lamp" => { + Self::redstone_lamp_from_identifier_and_properties(properties) + } + "minecraft:cocoa" => Self::cocoa_from_identifier_and_properties(properties), + "minecraft:sandstone_stairs" => { + Self::sandstone_stairs_from_identifier_and_properties(properties) + } + "minecraft:emerald_ore" => Self::emerald_ore_from_identifier_and_properties(properties), + "minecraft:ender_chest" => Self::ender_chest_from_identifier_and_properties(properties), + "minecraft:tripwire_hook" => { + Self::tripwire_hook_from_identifier_and_properties(properties) + } + "minecraft:tripwire" => Self::tripwire_from_identifier_and_properties(properties), + "minecraft:emerald_block" => { + Self::emerald_block_from_identifier_and_properties(properties) + } + "minecraft:spruce_stairs" => { + Self::spruce_stairs_from_identifier_and_properties(properties) + } + "minecraft:birch_stairs" => { + Self::birch_stairs_from_identifier_and_properties(properties) + } + "minecraft:jungle_stairs" => { + Self::jungle_stairs_from_identifier_and_properties(properties) + } + "minecraft:command_block" => { + Self::command_block_from_identifier_and_properties(properties) + } + "minecraft:beacon" => Self::beacon_from_identifier_and_properties(properties), + "minecraft:cobblestone_wall" => { + Self::cobblestone_wall_from_identifier_and_properties(properties) + } + "minecraft:mossy_cobblestone_wall" => { + Self::mossy_cobblestone_wall_from_identifier_and_properties(properties) + } + "minecraft:flower_pot" => Self::flower_pot_from_identifier_and_properties(properties), + "minecraft:potted_oak_sapling" => { + Self::potted_oak_sapling_from_identifier_and_properties(properties) + } + "minecraft:potted_spruce_sapling" => { + Self::potted_spruce_sapling_from_identifier_and_properties(properties) + } + "minecraft:potted_birch_sapling" => { + Self::potted_birch_sapling_from_identifier_and_properties(properties) + } + "minecraft:potted_jungle_sapling" => { + Self::potted_jungle_sapling_from_identifier_and_properties(properties) + } + "minecraft:potted_acacia_sapling" => { + Self::potted_acacia_sapling_from_identifier_and_properties(properties) + } + "minecraft:potted_dark_oak_sapling" => { + Self::potted_dark_oak_sapling_from_identifier_and_properties(properties) + } + "minecraft:potted_fern" => Self::potted_fern_from_identifier_and_properties(properties), + "minecraft:potted_dandelion" => { + Self::potted_dandelion_from_identifier_and_properties(properties) + } + "minecraft:potted_poppy" => { + Self::potted_poppy_from_identifier_and_properties(properties) + } + "minecraft:potted_blue_orchid" => { + Self::potted_blue_orchid_from_identifier_and_properties(properties) + } + "minecraft:potted_allium" => { + Self::potted_allium_from_identifier_and_properties(properties) + } + "minecraft:potted_azure_bluet" => { + Self::potted_azure_bluet_from_identifier_and_properties(properties) + } + "minecraft:potted_red_tulip" => { + Self::potted_red_tulip_from_identifier_and_properties(properties) + } + "minecraft:potted_orange_tulip" => { + Self::potted_orange_tulip_from_identifier_and_properties(properties) + } + "minecraft:potted_white_tulip" => { + Self::potted_white_tulip_from_identifier_and_properties(properties) + } + "minecraft:potted_pink_tulip" => { + Self::potted_pink_tulip_from_identifier_and_properties(properties) + } + "minecraft:potted_oxeye_daisy" => { + Self::potted_oxeye_daisy_from_identifier_and_properties(properties) + } + "minecraft:potted_cornflower" => { + Self::potted_cornflower_from_identifier_and_properties(properties) + } + "minecraft:potted_lily_of_the_valley" => { + Self::potted_lily_of_the_valley_from_identifier_and_properties(properties) + } + "minecraft:potted_wither_rose" => { + Self::potted_wither_rose_from_identifier_and_properties(properties) + } + "minecraft:potted_red_mushroom" => { + Self::potted_red_mushroom_from_identifier_and_properties(properties) + } + "minecraft:potted_brown_mushroom" => { + Self::potted_brown_mushroom_from_identifier_and_properties(properties) + } + "minecraft:potted_dead_bush" => { + Self::potted_dead_bush_from_identifier_and_properties(properties) + } + "minecraft:potted_cactus" => { + Self::potted_cactus_from_identifier_and_properties(properties) + } + "minecraft:carrots" => Self::carrots_from_identifier_and_properties(properties), + "minecraft:potatoes" => Self::potatoes_from_identifier_and_properties(properties), + "minecraft:oak_button" => Self::oak_button_from_identifier_and_properties(properties), + "minecraft:spruce_button" => { + Self::spruce_button_from_identifier_and_properties(properties) + } + "minecraft:birch_button" => { + Self::birch_button_from_identifier_and_properties(properties) + } + "minecraft:jungle_button" => { + Self::jungle_button_from_identifier_and_properties(properties) + } + "minecraft:acacia_button" => { + Self::acacia_button_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_button" => { + Self::dark_oak_button_from_identifier_and_properties(properties) + } + "minecraft:skeleton_skull" => { + Self::skeleton_skull_from_identifier_and_properties(properties) + } + "minecraft:skeleton_wall_skull" => { + Self::skeleton_wall_skull_from_identifier_and_properties(properties) + } + "minecraft:wither_skeleton_skull" => { + Self::wither_skeleton_skull_from_identifier_and_properties(properties) + } + "minecraft:wither_skeleton_wall_skull" => { + Self::wither_skeleton_wall_skull_from_identifier_and_properties(properties) + } + "minecraft:zombie_head" => Self::zombie_head_from_identifier_and_properties(properties), + "minecraft:zombie_wall_head" => { + Self::zombie_wall_head_from_identifier_and_properties(properties) + } + "minecraft:player_head" => Self::player_head_from_identifier_and_properties(properties), + "minecraft:player_wall_head" => { + Self::player_wall_head_from_identifier_and_properties(properties) + } + "minecraft:creeper_head" => { + Self::creeper_head_from_identifier_and_properties(properties) + } + "minecraft:creeper_wall_head" => { + Self::creeper_wall_head_from_identifier_and_properties(properties) + } + "minecraft:dragon_head" => Self::dragon_head_from_identifier_and_properties(properties), + "minecraft:dragon_wall_head" => { + Self::dragon_wall_head_from_identifier_and_properties(properties) + } + "minecraft:anvil" => Self::anvil_from_identifier_and_properties(properties), + "minecraft:chipped_anvil" => { + Self::chipped_anvil_from_identifier_and_properties(properties) + } + "minecraft:damaged_anvil" => { + Self::damaged_anvil_from_identifier_and_properties(properties) + } + "minecraft:trapped_chest" => { + Self::trapped_chest_from_identifier_and_properties(properties) + } + "minecraft:light_weighted_pressure_plate" => { + Self::light_weighted_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:heavy_weighted_pressure_plate" => { + Self::heavy_weighted_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:comparator" => Self::comparator_from_identifier_and_properties(properties), + "minecraft:daylight_detector" => { + Self::daylight_detector_from_identifier_and_properties(properties) + } + "minecraft:redstone_block" => { + Self::redstone_block_from_identifier_and_properties(properties) + } + "minecraft:nether_quartz_ore" => { + Self::nether_quartz_ore_from_identifier_and_properties(properties) + } + "minecraft:hopper" => Self::hopper_from_identifier_and_properties(properties), + "minecraft:quartz_block" => { + Self::quartz_block_from_identifier_and_properties(properties) + } + "minecraft:chiseled_quartz_block" => { + Self::chiseled_quartz_block_from_identifier_and_properties(properties) + } + "minecraft:quartz_pillar" => { + Self::quartz_pillar_from_identifier_and_properties(properties) + } + "minecraft:quartz_stairs" => { + Self::quartz_stairs_from_identifier_and_properties(properties) + } + "minecraft:activator_rail" => { + Self::activator_rail_from_identifier_and_properties(properties) + } + "minecraft:dropper" => Self::dropper_from_identifier_and_properties(properties), + "minecraft:white_terracotta" => { + Self::white_terracotta_from_identifier_and_properties(properties) + } + "minecraft:orange_terracotta" => { + Self::orange_terracotta_from_identifier_and_properties(properties) + } + "minecraft:magenta_terracotta" => { + Self::magenta_terracotta_from_identifier_and_properties(properties) + } + "minecraft:light_blue_terracotta" => { + Self::light_blue_terracotta_from_identifier_and_properties(properties) + } + "minecraft:yellow_terracotta" => { + Self::yellow_terracotta_from_identifier_and_properties(properties) + } + "minecraft:lime_terracotta" => { + Self::lime_terracotta_from_identifier_and_properties(properties) + } + "minecraft:pink_terracotta" => { + Self::pink_terracotta_from_identifier_and_properties(properties) + } + "minecraft:gray_terracotta" => { + Self::gray_terracotta_from_identifier_and_properties(properties) + } + "minecraft:light_gray_terracotta" => { + Self::light_gray_terracotta_from_identifier_and_properties(properties) + } + "minecraft:cyan_terracotta" => { + Self::cyan_terracotta_from_identifier_and_properties(properties) + } + "minecraft:purple_terracotta" => { + Self::purple_terracotta_from_identifier_and_properties(properties) + } + "minecraft:blue_terracotta" => { + Self::blue_terracotta_from_identifier_and_properties(properties) + } + "minecraft:brown_terracotta" => { + Self::brown_terracotta_from_identifier_and_properties(properties) + } + "minecraft:green_terracotta" => { + Self::green_terracotta_from_identifier_and_properties(properties) + } + "minecraft:red_terracotta" => { + Self::red_terracotta_from_identifier_and_properties(properties) + } + "minecraft:black_terracotta" => { + Self::black_terracotta_from_identifier_and_properties(properties) + } + "minecraft:white_stained_glass_pane" => { + Self::white_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:orange_stained_glass_pane" => { + Self::orange_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:magenta_stained_glass_pane" => { + Self::magenta_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:light_blue_stained_glass_pane" => { + Self::light_blue_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:yellow_stained_glass_pane" => { + Self::yellow_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:lime_stained_glass_pane" => { + Self::lime_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:pink_stained_glass_pane" => { + Self::pink_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:gray_stained_glass_pane" => { + Self::gray_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:light_gray_stained_glass_pane" => { + Self::light_gray_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:cyan_stained_glass_pane" => { + Self::cyan_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:purple_stained_glass_pane" => { + Self::purple_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:blue_stained_glass_pane" => { + Self::blue_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:brown_stained_glass_pane" => { + Self::brown_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:green_stained_glass_pane" => { + Self::green_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:red_stained_glass_pane" => { + Self::red_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:black_stained_glass_pane" => { + Self::black_stained_glass_pane_from_identifier_and_properties(properties) + } + "minecraft:acacia_stairs" => { + Self::acacia_stairs_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_stairs" => { + Self::dark_oak_stairs_from_identifier_and_properties(properties) + } + "minecraft:slime_block" => Self::slime_block_from_identifier_and_properties(properties), + "minecraft:barrier" => Self::barrier_from_identifier_and_properties(properties), + "minecraft:iron_trapdoor" => { + Self::iron_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:prismarine" => Self::prismarine_from_identifier_and_properties(properties), + "minecraft:prismarine_bricks" => { + Self::prismarine_bricks_from_identifier_and_properties(properties) + } + "minecraft:dark_prismarine" => { + Self::dark_prismarine_from_identifier_and_properties(properties) + } + "minecraft:prismarine_stairs" => { + Self::prismarine_stairs_from_identifier_and_properties(properties) + } + "minecraft:prismarine_brick_stairs" => { + Self::prismarine_brick_stairs_from_identifier_and_properties(properties) + } + "minecraft:dark_prismarine_stairs" => { + Self::dark_prismarine_stairs_from_identifier_and_properties(properties) + } + "minecraft:prismarine_slab" => { + Self::prismarine_slab_from_identifier_and_properties(properties) + } + "minecraft:prismarine_brick_slab" => { + Self::prismarine_brick_slab_from_identifier_and_properties(properties) + } + "minecraft:dark_prismarine_slab" => { + Self::dark_prismarine_slab_from_identifier_and_properties(properties) + } + "minecraft:sea_lantern" => Self::sea_lantern_from_identifier_and_properties(properties), + "minecraft:hay_block" => Self::hay_block_from_identifier_and_properties(properties), + "minecraft:white_carpet" => { + Self::white_carpet_from_identifier_and_properties(properties) + } + "minecraft:orange_carpet" => { + Self::orange_carpet_from_identifier_and_properties(properties) + } + "minecraft:magenta_carpet" => { + Self::magenta_carpet_from_identifier_and_properties(properties) + } + "minecraft:light_blue_carpet" => { + Self::light_blue_carpet_from_identifier_and_properties(properties) + } + "minecraft:yellow_carpet" => { + Self::yellow_carpet_from_identifier_and_properties(properties) + } + "minecraft:lime_carpet" => Self::lime_carpet_from_identifier_and_properties(properties), + "minecraft:pink_carpet" => Self::pink_carpet_from_identifier_and_properties(properties), + "minecraft:gray_carpet" => Self::gray_carpet_from_identifier_and_properties(properties), + "minecraft:light_gray_carpet" => { + Self::light_gray_carpet_from_identifier_and_properties(properties) + } + "minecraft:cyan_carpet" => Self::cyan_carpet_from_identifier_and_properties(properties), + "minecraft:purple_carpet" => { + Self::purple_carpet_from_identifier_and_properties(properties) + } + "minecraft:blue_carpet" => Self::blue_carpet_from_identifier_and_properties(properties), + "minecraft:brown_carpet" => { + Self::brown_carpet_from_identifier_and_properties(properties) + } + "minecraft:green_carpet" => { + Self::green_carpet_from_identifier_and_properties(properties) + } + "minecraft:red_carpet" => Self::red_carpet_from_identifier_and_properties(properties), + "minecraft:black_carpet" => { + Self::black_carpet_from_identifier_and_properties(properties) + } + "minecraft:terracotta" => Self::terracotta_from_identifier_and_properties(properties), + "minecraft:coal_block" => Self::coal_block_from_identifier_and_properties(properties), + "minecraft:packed_ice" => Self::packed_ice_from_identifier_and_properties(properties), + "minecraft:sunflower" => Self::sunflower_from_identifier_and_properties(properties), + "minecraft:lilac" => Self::lilac_from_identifier_and_properties(properties), + "minecraft:rose_bush" => Self::rose_bush_from_identifier_and_properties(properties), + "minecraft:peony" => Self::peony_from_identifier_and_properties(properties), + "minecraft:tall_grass" => Self::tall_grass_from_identifier_and_properties(properties), + "minecraft:large_fern" => Self::large_fern_from_identifier_and_properties(properties), + "minecraft:white_banner" => { + Self::white_banner_from_identifier_and_properties(properties) + } + "minecraft:orange_banner" => { + Self::orange_banner_from_identifier_and_properties(properties) + } + "minecraft:magenta_banner" => { + Self::magenta_banner_from_identifier_and_properties(properties) + } + "minecraft:light_blue_banner" => { + Self::light_blue_banner_from_identifier_and_properties(properties) + } + "minecraft:yellow_banner" => { + Self::yellow_banner_from_identifier_and_properties(properties) + } + "minecraft:lime_banner" => Self::lime_banner_from_identifier_and_properties(properties), + "minecraft:pink_banner" => Self::pink_banner_from_identifier_and_properties(properties), + "minecraft:gray_banner" => Self::gray_banner_from_identifier_and_properties(properties), + "minecraft:light_gray_banner" => { + Self::light_gray_banner_from_identifier_and_properties(properties) + } + "minecraft:cyan_banner" => Self::cyan_banner_from_identifier_and_properties(properties), + "minecraft:purple_banner" => { + Self::purple_banner_from_identifier_and_properties(properties) + } + "minecraft:blue_banner" => Self::blue_banner_from_identifier_and_properties(properties), + "minecraft:brown_banner" => { + Self::brown_banner_from_identifier_and_properties(properties) + } + "minecraft:green_banner" => { + Self::green_banner_from_identifier_and_properties(properties) + } + "minecraft:red_banner" => Self::red_banner_from_identifier_and_properties(properties), + "minecraft:black_banner" => { + Self::black_banner_from_identifier_and_properties(properties) + } + "minecraft:white_wall_banner" => { + Self::white_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:orange_wall_banner" => { + Self::orange_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:magenta_wall_banner" => { + Self::magenta_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:light_blue_wall_banner" => { + Self::light_blue_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:yellow_wall_banner" => { + Self::yellow_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:lime_wall_banner" => { + Self::lime_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:pink_wall_banner" => { + Self::pink_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:gray_wall_banner" => { + Self::gray_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:light_gray_wall_banner" => { + Self::light_gray_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:cyan_wall_banner" => { + Self::cyan_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:purple_wall_banner" => { + Self::purple_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:blue_wall_banner" => { + Self::blue_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:brown_wall_banner" => { + Self::brown_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:green_wall_banner" => { + Self::green_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:red_wall_banner" => { + Self::red_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:black_wall_banner" => { + Self::black_wall_banner_from_identifier_and_properties(properties) + } + "minecraft:red_sandstone" => { + Self::red_sandstone_from_identifier_and_properties(properties) + } + "minecraft:chiseled_red_sandstone" => { + Self::chiseled_red_sandstone_from_identifier_and_properties(properties) + } + "minecraft:cut_red_sandstone" => { + Self::cut_red_sandstone_from_identifier_and_properties(properties) + } + "minecraft:red_sandstone_stairs" => { + Self::red_sandstone_stairs_from_identifier_and_properties(properties) + } + "minecraft:oak_slab" => Self::oak_slab_from_identifier_and_properties(properties), + "minecraft:spruce_slab" => Self::spruce_slab_from_identifier_and_properties(properties), + "minecraft:birch_slab" => Self::birch_slab_from_identifier_and_properties(properties), + "minecraft:jungle_slab" => Self::jungle_slab_from_identifier_and_properties(properties), + "minecraft:acacia_slab" => Self::acacia_slab_from_identifier_and_properties(properties), + "minecraft:dark_oak_slab" => { + Self::dark_oak_slab_from_identifier_and_properties(properties) + } + "minecraft:stone_slab" => Self::stone_slab_from_identifier_and_properties(properties), + "minecraft:smooth_stone_slab" => { + Self::smooth_stone_slab_from_identifier_and_properties(properties) + } + "minecraft:sandstone_slab" => { + Self::sandstone_slab_from_identifier_and_properties(properties) + } + "minecraft:cut_sandstone_slab" => { + Self::cut_sandstone_slab_from_identifier_and_properties(properties) + } + "minecraft:petrified_oak_slab" => { + Self::petrified_oak_slab_from_identifier_and_properties(properties) + } + "minecraft:cobblestone_slab" => { + Self::cobblestone_slab_from_identifier_and_properties(properties) + } + "minecraft:brick_slab" => Self::brick_slab_from_identifier_and_properties(properties), + "minecraft:stone_brick_slab" => { + Self::stone_brick_slab_from_identifier_and_properties(properties) + } + "minecraft:nether_brick_slab" => { + Self::nether_brick_slab_from_identifier_and_properties(properties) + } + "minecraft:quartz_slab" => Self::quartz_slab_from_identifier_and_properties(properties), + "minecraft:red_sandstone_slab" => { + Self::red_sandstone_slab_from_identifier_and_properties(properties) + } + "minecraft:cut_red_sandstone_slab" => { + Self::cut_red_sandstone_slab_from_identifier_and_properties(properties) + } + "minecraft:purpur_slab" => Self::purpur_slab_from_identifier_and_properties(properties), + "minecraft:smooth_stone" => { + Self::smooth_stone_from_identifier_and_properties(properties) + } + "minecraft:smooth_sandstone" => { + Self::smooth_sandstone_from_identifier_and_properties(properties) + } + "minecraft:smooth_quartz" => { + Self::smooth_quartz_from_identifier_and_properties(properties) + } + "minecraft:smooth_red_sandstone" => { + Self::smooth_red_sandstone_from_identifier_and_properties(properties) + } + "minecraft:spruce_fence_gate" => { + Self::spruce_fence_gate_from_identifier_and_properties(properties) + } + "minecraft:birch_fence_gate" => { + Self::birch_fence_gate_from_identifier_and_properties(properties) + } + "minecraft:jungle_fence_gate" => { + Self::jungle_fence_gate_from_identifier_and_properties(properties) + } + "minecraft:acacia_fence_gate" => { + Self::acacia_fence_gate_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_fence_gate" => { + Self::dark_oak_fence_gate_from_identifier_and_properties(properties) + } + "minecraft:spruce_fence" => { + Self::spruce_fence_from_identifier_and_properties(properties) + } + "minecraft:birch_fence" => Self::birch_fence_from_identifier_and_properties(properties), + "minecraft:jungle_fence" => { + Self::jungle_fence_from_identifier_and_properties(properties) + } + "minecraft:acacia_fence" => { + Self::acacia_fence_from_identifier_and_properties(properties) + } + "minecraft:dark_oak_fence" => { + Self::dark_oak_fence_from_identifier_and_properties(properties) + } + "minecraft:spruce_door" => Self::spruce_door_from_identifier_and_properties(properties), + "minecraft:birch_door" => Self::birch_door_from_identifier_and_properties(properties), + "minecraft:jungle_door" => Self::jungle_door_from_identifier_and_properties(properties), + "minecraft:acacia_door" => Self::acacia_door_from_identifier_and_properties(properties), + "minecraft:dark_oak_door" => { + Self::dark_oak_door_from_identifier_and_properties(properties) + } + "minecraft:end_rod" => Self::end_rod_from_identifier_and_properties(properties), + "minecraft:chorus_plant" => { + Self::chorus_plant_from_identifier_and_properties(properties) + } + "minecraft:chorus_flower" => { + Self::chorus_flower_from_identifier_and_properties(properties) + } + "minecraft:purpur_block" => { + Self::purpur_block_from_identifier_and_properties(properties) + } + "minecraft:purpur_pillar" => { + Self::purpur_pillar_from_identifier_and_properties(properties) + } + "minecraft:purpur_stairs" => { + Self::purpur_stairs_from_identifier_and_properties(properties) + } + "minecraft:end_stone_bricks" => { + Self::end_stone_bricks_from_identifier_and_properties(properties) + } + "minecraft:beetroots" => Self::beetroots_from_identifier_and_properties(properties), + "minecraft:grass_path" => Self::grass_path_from_identifier_and_properties(properties), + "minecraft:end_gateway" => Self::end_gateway_from_identifier_and_properties(properties), + "minecraft:repeating_command_block" => { + Self::repeating_command_block_from_identifier_and_properties(properties) + } + "minecraft:chain_command_block" => { + Self::chain_command_block_from_identifier_and_properties(properties) + } + "minecraft:frosted_ice" => Self::frosted_ice_from_identifier_and_properties(properties), + "minecraft:magma_block" => Self::magma_block_from_identifier_and_properties(properties), + "minecraft:nether_wart_block" => { + Self::nether_wart_block_from_identifier_and_properties(properties) + } + "minecraft:red_nether_bricks" => { + Self::red_nether_bricks_from_identifier_and_properties(properties) + } + "minecraft:bone_block" => Self::bone_block_from_identifier_and_properties(properties), + "minecraft:structure_void" => { + Self::structure_void_from_identifier_and_properties(properties) + } + "minecraft:observer" => Self::observer_from_identifier_and_properties(properties), + "minecraft:shulker_box" => Self::shulker_box_from_identifier_and_properties(properties), + "minecraft:white_shulker_box" => { + Self::white_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:orange_shulker_box" => { + Self::orange_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:magenta_shulker_box" => { + Self::magenta_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:light_blue_shulker_box" => { + Self::light_blue_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:yellow_shulker_box" => { + Self::yellow_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:lime_shulker_box" => { + Self::lime_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:pink_shulker_box" => { + Self::pink_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:gray_shulker_box" => { + Self::gray_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:light_gray_shulker_box" => { + Self::light_gray_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:cyan_shulker_box" => { + Self::cyan_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:purple_shulker_box" => { + Self::purple_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:blue_shulker_box" => { + Self::blue_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:brown_shulker_box" => { + Self::brown_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:green_shulker_box" => { + Self::green_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:red_shulker_box" => { + Self::red_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:black_shulker_box" => { + Self::black_shulker_box_from_identifier_and_properties(properties) + } + "minecraft:white_glazed_terracotta" => { + Self::white_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:orange_glazed_terracotta" => { + Self::orange_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:magenta_glazed_terracotta" => { + Self::magenta_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:light_blue_glazed_terracotta" => { + Self::light_blue_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:yellow_glazed_terracotta" => { + Self::yellow_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:lime_glazed_terracotta" => { + Self::lime_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:pink_glazed_terracotta" => { + Self::pink_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:gray_glazed_terracotta" => { + Self::gray_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:light_gray_glazed_terracotta" => { + Self::light_gray_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:cyan_glazed_terracotta" => { + Self::cyan_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:purple_glazed_terracotta" => { + Self::purple_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:blue_glazed_terracotta" => { + Self::blue_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:brown_glazed_terracotta" => { + Self::brown_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:green_glazed_terracotta" => { + Self::green_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:red_glazed_terracotta" => { + Self::red_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:black_glazed_terracotta" => { + Self::black_glazed_terracotta_from_identifier_and_properties(properties) + } + "minecraft:white_concrete" => { + Self::white_concrete_from_identifier_and_properties(properties) + } + "minecraft:orange_concrete" => { + Self::orange_concrete_from_identifier_and_properties(properties) + } + "minecraft:magenta_concrete" => { + Self::magenta_concrete_from_identifier_and_properties(properties) + } + "minecraft:light_blue_concrete" => { + Self::light_blue_concrete_from_identifier_and_properties(properties) + } + "minecraft:yellow_concrete" => { + Self::yellow_concrete_from_identifier_and_properties(properties) + } + "minecraft:lime_concrete" => { + Self::lime_concrete_from_identifier_and_properties(properties) + } + "minecraft:pink_concrete" => { + Self::pink_concrete_from_identifier_and_properties(properties) + } + "minecraft:gray_concrete" => { + Self::gray_concrete_from_identifier_and_properties(properties) + } + "minecraft:light_gray_concrete" => { + Self::light_gray_concrete_from_identifier_and_properties(properties) + } + "minecraft:cyan_concrete" => { + Self::cyan_concrete_from_identifier_and_properties(properties) + } + "minecraft:purple_concrete" => { + Self::purple_concrete_from_identifier_and_properties(properties) + } + "minecraft:blue_concrete" => { + Self::blue_concrete_from_identifier_and_properties(properties) + } + "minecraft:brown_concrete" => { + Self::brown_concrete_from_identifier_and_properties(properties) + } + "minecraft:green_concrete" => { + Self::green_concrete_from_identifier_and_properties(properties) + } + "minecraft:red_concrete" => { + Self::red_concrete_from_identifier_and_properties(properties) + } + "minecraft:black_concrete" => { + Self::black_concrete_from_identifier_and_properties(properties) + } + "minecraft:white_concrete_powder" => { + Self::white_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:orange_concrete_powder" => { + Self::orange_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:magenta_concrete_powder" => { + Self::magenta_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:light_blue_concrete_powder" => { + Self::light_blue_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:yellow_concrete_powder" => { + Self::yellow_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:lime_concrete_powder" => { + Self::lime_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:pink_concrete_powder" => { + Self::pink_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:gray_concrete_powder" => { + Self::gray_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:light_gray_concrete_powder" => { + Self::light_gray_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:cyan_concrete_powder" => { + Self::cyan_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:purple_concrete_powder" => { + Self::purple_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:blue_concrete_powder" => { + Self::blue_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:brown_concrete_powder" => { + Self::brown_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:green_concrete_powder" => { + Self::green_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:red_concrete_powder" => { + Self::red_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:black_concrete_powder" => { + Self::black_concrete_powder_from_identifier_and_properties(properties) + } + "minecraft:kelp" => Self::kelp_from_identifier_and_properties(properties), + "minecraft:kelp_plant" => Self::kelp_plant_from_identifier_and_properties(properties), + "minecraft:dried_kelp_block" => { + Self::dried_kelp_block_from_identifier_and_properties(properties) + } + "minecraft:turtle_egg" => Self::turtle_egg_from_identifier_and_properties(properties), + "minecraft:dead_tube_coral_block" => { + Self::dead_tube_coral_block_from_identifier_and_properties(properties) + } + "minecraft:dead_brain_coral_block" => { + Self::dead_brain_coral_block_from_identifier_and_properties(properties) + } + "minecraft:dead_bubble_coral_block" => { + Self::dead_bubble_coral_block_from_identifier_and_properties(properties) + } + "minecraft:dead_fire_coral_block" => { + Self::dead_fire_coral_block_from_identifier_and_properties(properties) + } + "minecraft:dead_horn_coral_block" => { + Self::dead_horn_coral_block_from_identifier_and_properties(properties) + } + "minecraft:tube_coral_block" => { + Self::tube_coral_block_from_identifier_and_properties(properties) + } + "minecraft:brain_coral_block" => { + Self::brain_coral_block_from_identifier_and_properties(properties) + } + "minecraft:bubble_coral_block" => { + Self::bubble_coral_block_from_identifier_and_properties(properties) + } + "minecraft:fire_coral_block" => { + Self::fire_coral_block_from_identifier_and_properties(properties) + } + "minecraft:horn_coral_block" => { + Self::horn_coral_block_from_identifier_and_properties(properties) + } + "minecraft:dead_tube_coral" => { + Self::dead_tube_coral_from_identifier_and_properties(properties) + } + "minecraft:dead_brain_coral" => { + Self::dead_brain_coral_from_identifier_and_properties(properties) + } + "minecraft:dead_bubble_coral" => { + Self::dead_bubble_coral_from_identifier_and_properties(properties) + } + "minecraft:dead_fire_coral" => { + Self::dead_fire_coral_from_identifier_and_properties(properties) + } + "minecraft:dead_horn_coral" => { + Self::dead_horn_coral_from_identifier_and_properties(properties) + } + "minecraft:tube_coral" => Self::tube_coral_from_identifier_and_properties(properties), + "minecraft:brain_coral" => Self::brain_coral_from_identifier_and_properties(properties), + "minecraft:bubble_coral" => { + Self::bubble_coral_from_identifier_and_properties(properties) + } + "minecraft:fire_coral" => Self::fire_coral_from_identifier_and_properties(properties), + "minecraft:horn_coral" => Self::horn_coral_from_identifier_and_properties(properties), + "minecraft:dead_tube_coral_fan" => { + Self::dead_tube_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_brain_coral_fan" => { + Self::dead_brain_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_bubble_coral_fan" => { + Self::dead_bubble_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_fire_coral_fan" => { + Self::dead_fire_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_horn_coral_fan" => { + Self::dead_horn_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:tube_coral_fan" => { + Self::tube_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:brain_coral_fan" => { + Self::brain_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:bubble_coral_fan" => { + Self::bubble_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:fire_coral_fan" => { + Self::fire_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:horn_coral_fan" => { + Self::horn_coral_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_tube_coral_wall_fan" => { + Self::dead_tube_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_brain_coral_wall_fan" => { + Self::dead_brain_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_bubble_coral_wall_fan" => { + Self::dead_bubble_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_fire_coral_wall_fan" => { + Self::dead_fire_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:dead_horn_coral_wall_fan" => { + Self::dead_horn_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:tube_coral_wall_fan" => { + Self::tube_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:brain_coral_wall_fan" => { + Self::brain_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:bubble_coral_wall_fan" => { + Self::bubble_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:fire_coral_wall_fan" => { + Self::fire_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:horn_coral_wall_fan" => { + Self::horn_coral_wall_fan_from_identifier_and_properties(properties) + } + "minecraft:sea_pickle" => Self::sea_pickle_from_identifier_and_properties(properties), + "minecraft:blue_ice" => Self::blue_ice_from_identifier_and_properties(properties), + "minecraft:conduit" => Self::conduit_from_identifier_and_properties(properties), + "minecraft:bamboo_sapling" => { + Self::bamboo_sapling_from_identifier_and_properties(properties) + } + "minecraft:bamboo" => Self::bamboo_from_identifier_and_properties(properties), + "minecraft:potted_bamboo" => { + Self::potted_bamboo_from_identifier_and_properties(properties) + } + "minecraft:void_air" => Self::void_air_from_identifier_and_properties(properties), + "minecraft:cave_air" => Self::cave_air_from_identifier_and_properties(properties), + "minecraft:bubble_column" => { + Self::bubble_column_from_identifier_and_properties(properties) + } + "minecraft:polished_granite_stairs" => { + Self::polished_granite_stairs_from_identifier_and_properties(properties) + } + "minecraft:smooth_red_sandstone_stairs" => { + Self::smooth_red_sandstone_stairs_from_identifier_and_properties(properties) + } + "minecraft:mossy_stone_brick_stairs" => { + Self::mossy_stone_brick_stairs_from_identifier_and_properties(properties) + } + "minecraft:polished_diorite_stairs" => { + Self::polished_diorite_stairs_from_identifier_and_properties(properties) + } + "minecraft:mossy_cobblestone_stairs" => { + Self::mossy_cobblestone_stairs_from_identifier_and_properties(properties) + } + "minecraft:end_stone_brick_stairs" => { + Self::end_stone_brick_stairs_from_identifier_and_properties(properties) + } + "minecraft:stone_stairs" => { + Self::stone_stairs_from_identifier_and_properties(properties) + } + "minecraft:smooth_sandstone_stairs" => { + Self::smooth_sandstone_stairs_from_identifier_and_properties(properties) + } + "minecraft:smooth_quartz_stairs" => { + Self::smooth_quartz_stairs_from_identifier_and_properties(properties) + } + "minecraft:granite_stairs" => { + Self::granite_stairs_from_identifier_and_properties(properties) + } + "minecraft:andesite_stairs" => { + Self::andesite_stairs_from_identifier_and_properties(properties) + } + "minecraft:red_nether_brick_stairs" => { + Self::red_nether_brick_stairs_from_identifier_and_properties(properties) + } + "minecraft:polished_andesite_stairs" => { + Self::polished_andesite_stairs_from_identifier_and_properties(properties) + } + "minecraft:diorite_stairs" => { + Self::diorite_stairs_from_identifier_and_properties(properties) + } + "minecraft:polished_granite_slab" => { + Self::polished_granite_slab_from_identifier_and_properties(properties) + } + "minecraft:smooth_red_sandstone_slab" => { + Self::smooth_red_sandstone_slab_from_identifier_and_properties(properties) + } + "minecraft:mossy_stone_brick_slab" => { + Self::mossy_stone_brick_slab_from_identifier_and_properties(properties) + } + "minecraft:polished_diorite_slab" => { + Self::polished_diorite_slab_from_identifier_and_properties(properties) + } + "minecraft:mossy_cobblestone_slab" => { + Self::mossy_cobblestone_slab_from_identifier_and_properties(properties) + } + "minecraft:end_stone_brick_slab" => { + Self::end_stone_brick_slab_from_identifier_and_properties(properties) + } + "minecraft:smooth_sandstone_slab" => { + Self::smooth_sandstone_slab_from_identifier_and_properties(properties) + } + "minecraft:smooth_quartz_slab" => { + Self::smooth_quartz_slab_from_identifier_and_properties(properties) + } + "minecraft:granite_slab" => { + Self::granite_slab_from_identifier_and_properties(properties) + } + "minecraft:andesite_slab" => { + Self::andesite_slab_from_identifier_and_properties(properties) + } + "minecraft:red_nether_brick_slab" => { + Self::red_nether_brick_slab_from_identifier_and_properties(properties) + } + "minecraft:polished_andesite_slab" => { + Self::polished_andesite_slab_from_identifier_and_properties(properties) + } + "minecraft:diorite_slab" => { + Self::diorite_slab_from_identifier_and_properties(properties) + } + "minecraft:brick_wall" => Self::brick_wall_from_identifier_and_properties(properties), + "minecraft:prismarine_wall" => { + Self::prismarine_wall_from_identifier_and_properties(properties) + } + "minecraft:red_sandstone_wall" => { + Self::red_sandstone_wall_from_identifier_and_properties(properties) + } + "minecraft:mossy_stone_brick_wall" => { + Self::mossy_stone_brick_wall_from_identifier_and_properties(properties) + } + "minecraft:granite_wall" => { + Self::granite_wall_from_identifier_and_properties(properties) + } + "minecraft:stone_brick_wall" => { + Self::stone_brick_wall_from_identifier_and_properties(properties) + } + "minecraft:nether_brick_wall" => { + Self::nether_brick_wall_from_identifier_and_properties(properties) + } + "minecraft:andesite_wall" => { + Self::andesite_wall_from_identifier_and_properties(properties) + } + "minecraft:red_nether_brick_wall" => { + Self::red_nether_brick_wall_from_identifier_and_properties(properties) + } + "minecraft:sandstone_wall" => { + Self::sandstone_wall_from_identifier_and_properties(properties) + } + "minecraft:end_stone_brick_wall" => { + Self::end_stone_brick_wall_from_identifier_and_properties(properties) + } + "minecraft:diorite_wall" => { + Self::diorite_wall_from_identifier_and_properties(properties) + } + "minecraft:scaffolding" => Self::scaffolding_from_identifier_and_properties(properties), + "minecraft:loom" => Self::loom_from_identifier_and_properties(properties), + "minecraft:barrel" => Self::barrel_from_identifier_and_properties(properties), + "minecraft:smoker" => Self::smoker_from_identifier_and_properties(properties), + "minecraft:blast_furnace" => { + Self::blast_furnace_from_identifier_and_properties(properties) + } + "minecraft:cartography_table" => { + Self::cartography_table_from_identifier_and_properties(properties) + } + "minecraft:fletching_table" => { + Self::fletching_table_from_identifier_and_properties(properties) + } + "minecraft:grindstone" => Self::grindstone_from_identifier_and_properties(properties), + "minecraft:lectern" => Self::lectern_from_identifier_and_properties(properties), + "minecraft:smithing_table" => { + Self::smithing_table_from_identifier_and_properties(properties) + } + "minecraft:stonecutter" => Self::stonecutter_from_identifier_and_properties(properties), + "minecraft:bell" => Self::bell_from_identifier_and_properties(properties), + "minecraft:lantern" => Self::lantern_from_identifier_and_properties(properties), + "minecraft:soul_lantern" => { + Self::soul_lantern_from_identifier_and_properties(properties) + } + "minecraft:campfire" => Self::campfire_from_identifier_and_properties(properties), + "minecraft:soul_campfire" => { + Self::soul_campfire_from_identifier_and_properties(properties) + } + "minecraft:sweet_berry_bush" => { + Self::sweet_berry_bush_from_identifier_and_properties(properties) + } + "minecraft:warped_stem" => Self::warped_stem_from_identifier_and_properties(properties), + "minecraft:stripped_warped_stem" => { + Self::stripped_warped_stem_from_identifier_and_properties(properties) + } + "minecraft:warped_hyphae" => { + Self::warped_hyphae_from_identifier_and_properties(properties) + } + "minecraft:stripped_warped_hyphae" => { + Self::stripped_warped_hyphae_from_identifier_and_properties(properties) + } + "minecraft:warped_nylium" => { + Self::warped_nylium_from_identifier_and_properties(properties) + } + "minecraft:warped_fungus" => { + Self::warped_fungus_from_identifier_and_properties(properties) + } + "minecraft:warped_wart_block" => { + Self::warped_wart_block_from_identifier_and_properties(properties) + } + "minecraft:warped_roots" => { + Self::warped_roots_from_identifier_and_properties(properties) + } + "minecraft:nether_sprouts" => { + Self::nether_sprouts_from_identifier_and_properties(properties) + } + "minecraft:crimson_stem" => { + Self::crimson_stem_from_identifier_and_properties(properties) + } + "minecraft:stripped_crimson_stem" => { + Self::stripped_crimson_stem_from_identifier_and_properties(properties) + } + "minecraft:crimson_hyphae" => { + Self::crimson_hyphae_from_identifier_and_properties(properties) + } + "minecraft:stripped_crimson_hyphae" => { + Self::stripped_crimson_hyphae_from_identifier_and_properties(properties) + } + "minecraft:crimson_nylium" => { + Self::crimson_nylium_from_identifier_and_properties(properties) + } + "minecraft:crimson_fungus" => { + Self::crimson_fungus_from_identifier_and_properties(properties) + } + "minecraft:shroomlight" => Self::shroomlight_from_identifier_and_properties(properties), + "minecraft:weeping_vines" => { + Self::weeping_vines_from_identifier_and_properties(properties) + } + "minecraft:weeping_vines_plant" => { + Self::weeping_vines_plant_from_identifier_and_properties(properties) + } + "minecraft:twisting_vines" => { + Self::twisting_vines_from_identifier_and_properties(properties) + } + "minecraft:twisting_vines_plant" => { + Self::twisting_vines_plant_from_identifier_and_properties(properties) + } + "minecraft:crimson_roots" => { + Self::crimson_roots_from_identifier_and_properties(properties) + } + "minecraft:crimson_planks" => { + Self::crimson_planks_from_identifier_and_properties(properties) + } + "minecraft:warped_planks" => { + Self::warped_planks_from_identifier_and_properties(properties) + } + "minecraft:crimson_slab" => { + Self::crimson_slab_from_identifier_and_properties(properties) + } + "minecraft:warped_slab" => Self::warped_slab_from_identifier_and_properties(properties), + "minecraft:crimson_pressure_plate" => { + Self::crimson_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:warped_pressure_plate" => { + Self::warped_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:crimson_fence" => { + Self::crimson_fence_from_identifier_and_properties(properties) + } + "minecraft:warped_fence" => { + Self::warped_fence_from_identifier_and_properties(properties) + } + "minecraft:crimson_trapdoor" => { + Self::crimson_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:warped_trapdoor" => { + Self::warped_trapdoor_from_identifier_and_properties(properties) + } + "minecraft:crimson_fence_gate" => { + Self::crimson_fence_gate_from_identifier_and_properties(properties) + } + "minecraft:warped_fence_gate" => { + Self::warped_fence_gate_from_identifier_and_properties(properties) + } + "minecraft:crimson_stairs" => { + Self::crimson_stairs_from_identifier_and_properties(properties) + } + "minecraft:warped_stairs" => { + Self::warped_stairs_from_identifier_and_properties(properties) + } + "minecraft:crimson_button" => { + Self::crimson_button_from_identifier_and_properties(properties) + } + "minecraft:warped_button" => { + Self::warped_button_from_identifier_and_properties(properties) + } + "minecraft:crimson_door" => { + Self::crimson_door_from_identifier_and_properties(properties) + } + "minecraft:warped_door" => Self::warped_door_from_identifier_and_properties(properties), + "minecraft:crimson_sign" => { + Self::crimson_sign_from_identifier_and_properties(properties) + } + "minecraft:warped_sign" => Self::warped_sign_from_identifier_and_properties(properties), + "minecraft:crimson_wall_sign" => { + Self::crimson_wall_sign_from_identifier_and_properties(properties) + } + "minecraft:warped_wall_sign" => { + Self::warped_wall_sign_from_identifier_and_properties(properties) + } + "minecraft:structure_block" => { + Self::structure_block_from_identifier_and_properties(properties) + } + "minecraft:jigsaw" => Self::jigsaw_from_identifier_and_properties(properties), + "minecraft:composter" => Self::composter_from_identifier_and_properties(properties), + "minecraft:target" => Self::target_from_identifier_and_properties(properties), + "minecraft:bee_nest" => Self::bee_nest_from_identifier_and_properties(properties), + "minecraft:beehive" => Self::beehive_from_identifier_and_properties(properties), + "minecraft:honey_block" => Self::honey_block_from_identifier_and_properties(properties), + "minecraft:honeycomb_block" => { + Self::honeycomb_block_from_identifier_and_properties(properties) + } + "minecraft:netherite_block" => { + Self::netherite_block_from_identifier_and_properties(properties) + } + "minecraft:ancient_debris" => { + Self::ancient_debris_from_identifier_and_properties(properties) + } + "minecraft:crying_obsidian" => { + Self::crying_obsidian_from_identifier_and_properties(properties) + } + "minecraft:respawn_anchor" => { + Self::respawn_anchor_from_identifier_and_properties(properties) + } + "minecraft:potted_crimson_fungus" => { + Self::potted_crimson_fungus_from_identifier_and_properties(properties) + } + "minecraft:potted_warped_fungus" => { + Self::potted_warped_fungus_from_identifier_and_properties(properties) + } + "minecraft:potted_crimson_roots" => { + Self::potted_crimson_roots_from_identifier_and_properties(properties) + } + "minecraft:potted_warped_roots" => { + Self::potted_warped_roots_from_identifier_and_properties(properties) + } + "minecraft:lodestone" => Self::lodestone_from_identifier_and_properties(properties), + "minecraft:blackstone" => Self::blackstone_from_identifier_and_properties(properties), + "minecraft:blackstone_stairs" => { + Self::blackstone_stairs_from_identifier_and_properties(properties) + } + "minecraft:blackstone_wall" => { + Self::blackstone_wall_from_identifier_and_properties(properties) + } + "minecraft:blackstone_slab" => { + Self::blackstone_slab_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone" => { + Self::polished_blackstone_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_bricks" => { + Self::polished_blackstone_bricks_from_identifier_and_properties(properties) + } + "minecraft:cracked_polished_blackstone_bricks" => { + Self::cracked_polished_blackstone_bricks_from_identifier_and_properties(properties) + } + "minecraft:chiseled_polished_blackstone" => { + Self::chiseled_polished_blackstone_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_brick_slab" => { + Self::polished_blackstone_brick_slab_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_brick_stairs" => { + Self::polished_blackstone_brick_stairs_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_brick_wall" => { + Self::polished_blackstone_brick_wall_from_identifier_and_properties(properties) + } + "minecraft:gilded_blackstone" => { + Self::gilded_blackstone_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_stairs" => { + Self::polished_blackstone_stairs_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_slab" => { + Self::polished_blackstone_slab_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_pressure_plate" => { + Self::polished_blackstone_pressure_plate_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_button" => { + Self::polished_blackstone_button_from_identifier_and_properties(properties) + } + "minecraft:polished_blackstone_wall" => { + Self::polished_blackstone_wall_from_identifier_and_properties(properties) + } + "minecraft:chiseled_nether_bricks" => { + Self::chiseled_nether_bricks_from_identifier_and_properties(properties) + } + "minecraft:cracked_nether_bricks" => { + Self::cracked_nether_bricks_from_identifier_and_properties(properties) + } + "minecraft:quartz_bricks" => { + Self::quartz_bricks_from_identifier_and_properties(properties) + } + _ => None, + } + } + fn air_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::air(); + Some(block) + } + fn stone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::stone(); + Some(block) + } + fn granite_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::granite(); + Some(block) + } + fn polished_granite_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_granite(); + Some(block) + } + fn diorite_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::diorite(); + Some(block) + } + fn polished_diorite_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_diorite(); + Some(block) + } + fn andesite_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::andesite(); + Some(block) + } + fn polished_andesite_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_andesite(); + Some(block) + } + fn grass_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::grass_block(); + let snowy = map.get("snowy")?; + let snowy = bool::from_str(snowy).ok()?; + block.set_snowy(snowy); + Some(block) + } + fn dirt_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::dirt(); + Some(block) + } + fn coarse_dirt_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::coarse_dirt(); + Some(block) + } + fn podzol_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::podzol(); + let snowy = map.get("snowy")?; + let snowy = bool::from_str(snowy).ok()?; + block.set_snowy(snowy); + Some(block) + } + fn cobblestone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cobblestone(); + Some(block) + } + fn oak_planks_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_planks(); + Some(block) + } + fn spruce_planks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_planks(); + Some(block) + } + fn birch_planks_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_planks(); + Some(block) + } + fn jungle_planks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_planks(); + Some(block) + } + fn acacia_planks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_planks(); + Some(block) + } + fn dark_oak_planks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_planks(); + Some(block) + } + fn oak_sapling_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_sapling(); + let stage = map.get("stage")?; + let stage = { + let x = i32::from_str(stage).ok()?; + if !(0i32..=1i32).contains(&x) { + return None; + } + x + }; + block.set_stage(stage); + Some(block) + } + fn spruce_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_sapling(); + let stage = map.get("stage")?; + let stage = { + let x = i32::from_str(stage).ok()?; + if !(0i32..=1i32).contains(&x) { + return None; + } + x + }; + block.set_stage(stage); + Some(block) + } + fn birch_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::birch_sapling(); + let stage = map.get("stage")?; + let stage = { + let x = i32::from_str(stage).ok()?; + if !(0i32..=1i32).contains(&x) { + return None; + } + x + }; + block.set_stage(stage); + Some(block) + } + fn jungle_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_sapling(); + let stage = map.get("stage")?; + let stage = { + let x = i32::from_str(stage).ok()?; + if !(0i32..=1i32).contains(&x) { + return None; + } + x + }; + block.set_stage(stage); + Some(block) + } + fn acacia_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_sapling(); + let stage = map.get("stage")?; + let stage = { + let x = i32::from_str(stage).ok()?; + if !(0i32..=1i32).contains(&x) { + return None; + } + x + }; + block.set_stage(stage); + Some(block) + } + fn dark_oak_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_sapling(); + let stage = map.get("stage")?; + let stage = { + let x = i32::from_str(stage).ok()?; + if !(0i32..=1i32).contains(&x) { + return None; + } + x + }; + block.set_stage(stage); + Some(block) + } + fn bedrock_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::bedrock(); + Some(block) + } + fn water_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::water(); + let water_level = map.get("level")?; + let water_level = { + let x = i32::from_str(water_level).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_water_level(water_level); + Some(block) + } + fn lava_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lava(); + let water_level = map.get("level")?; + let water_level = { + let x = i32::from_str(water_level).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_water_level(water_level); + Some(block) + } + fn sand_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::sand(); + Some(block) + } + fn red_sand_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::red_sand(); + Some(block) + } + fn gravel_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::gravel(); + Some(block) + } + fn gold_ore_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::gold_ore(); + Some(block) + } + fn iron_ore_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::iron_ore(); + Some(block) + } + fn coal_ore_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::coal_ore(); + Some(block) + } + fn nether_gold_ore_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_gold_ore(); + Some(block) + } + fn oak_log_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn spruce_log_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::spruce_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn birch_log_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn jungle_log_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::jungle_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn acacia_log_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::acacia_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn dark_oak_log_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::dark_oak_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_spruce_log_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_spruce_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_birch_log_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_birch_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_jungle_log_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_jungle_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_acacia_log_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_acacia_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_dark_oak_log_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_dark_oak_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_oak_log_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_oak_log(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn oak_wood_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn spruce_wood_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::spruce_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn birch_wood_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn jungle_wood_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::jungle_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn acacia_wood_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::acacia_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn dark_oak_wood_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_oak_wood_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_oak_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_spruce_wood_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_spruce_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_birch_wood_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_birch_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_jungle_wood_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_jungle_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_acacia_wood_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_acacia_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_dark_oak_wood_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_dark_oak_wood(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn oak_leaves_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_leaves(); + let distance_1_7 = map.get("distance")?; + let distance_1_7 = { + let x = i32::from_str(distance_1_7).ok()?; + if !(1i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_distance_1_7(distance_1_7); + let persistent = map.get("persistent")?; + let persistent = bool::from_str(persistent).ok()?; + block.set_persistent(persistent); + Some(block) + } + fn spruce_leaves_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_leaves(); + let distance_1_7 = map.get("distance")?; + let distance_1_7 = { + let x = i32::from_str(distance_1_7).ok()?; + if !(1i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_distance_1_7(distance_1_7); + let persistent = map.get("persistent")?; + let persistent = bool::from_str(persistent).ok()?; + block.set_persistent(persistent); + Some(block) + } + fn birch_leaves_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_leaves(); + let distance_1_7 = map.get("distance")?; + let distance_1_7 = { + let x = i32::from_str(distance_1_7).ok()?; + if !(1i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_distance_1_7(distance_1_7); + let persistent = map.get("persistent")?; + let persistent = bool::from_str(persistent).ok()?; + block.set_persistent(persistent); + Some(block) + } + fn jungle_leaves_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_leaves(); + let distance_1_7 = map.get("distance")?; + let distance_1_7 = { + let x = i32::from_str(distance_1_7).ok()?; + if !(1i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_distance_1_7(distance_1_7); + let persistent = map.get("persistent")?; + let persistent = bool::from_str(persistent).ok()?; + block.set_persistent(persistent); + Some(block) + } + fn acacia_leaves_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_leaves(); + let distance_1_7 = map.get("distance")?; + let distance_1_7 = { + let x = i32::from_str(distance_1_7).ok()?; + if !(1i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_distance_1_7(distance_1_7); + let persistent = map.get("persistent")?; + let persistent = bool::from_str(persistent).ok()?; + block.set_persistent(persistent); + Some(block) + } + fn dark_oak_leaves_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_leaves(); + let distance_1_7 = map.get("distance")?; + let distance_1_7 = { + let x = i32::from_str(distance_1_7).ok()?; + if !(1i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_distance_1_7(distance_1_7); + let persistent = map.get("persistent")?; + let persistent = bool::from_str(persistent).ok()?; + block.set_persistent(persistent); + Some(block) + } + fn sponge_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::sponge(); + Some(block) + } + fn wet_sponge_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::wet_sponge(); + Some(block) + } + fn glass_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::glass(); + Some(block) + } + fn lapis_ore_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lapis_ore(); + Some(block) + } + fn lapis_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lapis_block(); + Some(block) + } + fn dispenser_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::dispenser(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + let triggered = map.get("triggered")?; + let triggered = bool::from_str(triggered).ok()?; + block.set_triggered(triggered); + Some(block) + } + fn sandstone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::sandstone(); + Some(block) + } + fn chiseled_sandstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chiseled_sandstone(); + Some(block) + } + fn cut_sandstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cut_sandstone(); + Some(block) + } + fn note_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::note_block(); + let instrument = map.get("instrument")?; + let instrument = Instrument::from_str(instrument).ok()?; + block.set_instrument(instrument); + let note = map.get("note")?; + let note = { + let x = i32::from_str(note).ok()?; + if !(0i32..=24i32).contains(&x) { + return None; + } + x + }; + block.set_note(note); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn white_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::white_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn orange_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::orange_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn magenta_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::magenta_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn light_blue_bed_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn yellow_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::yellow_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn lime_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lime_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn pink_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::pink_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn gray_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::gray_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn light_gray_bed_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn cyan_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cyan_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn purple_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::purple_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn blue_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::blue_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn brown_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::brown_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn green_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::green_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn red_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::red_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn black_bed_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::black_bed(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let occupied = map.get("occupied")?; + let occupied = bool::from_str(occupied).ok()?; + block.set_occupied(occupied); + let part = map.get("part")?; + let part = Part::from_str(part).ok()?; + block.set_part(part); + Some(block) + } + fn powered_rail_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::powered_rail(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let powered_rail_shape = map.get("shape")?; + let powered_rail_shape = PoweredRailShape::from_str(powered_rail_shape).ok()?; + block.set_powered_rail_shape(powered_rail_shape); + Some(block) + } + fn detector_rail_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::detector_rail(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let powered_rail_shape = map.get("shape")?; + let powered_rail_shape = PoweredRailShape::from_str(powered_rail_shape).ok()?; + block.set_powered_rail_shape(powered_rail_shape); + Some(block) + } + fn sticky_piston_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::sticky_piston(); + let extended = map.get("extended")?; + let extended = bool::from_str(extended).ok()?; + block.set_extended(extended); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn cobweb_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cobweb(); + Some(block) + } + fn grass_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::grass(); + Some(block) + } + fn fern_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::fern(); + Some(block) + } + fn dead_bush_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::dead_bush(); + Some(block) + } + fn seagrass_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::seagrass(); + Some(block) + } + fn tall_seagrass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::tall_seagrass(); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + Some(block) + } + fn piston_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::piston(); + let extended = map.get("extended")?; + let extended = bool::from_str(extended).ok()?; + block.set_extended(extended); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn piston_head_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::piston_head(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + let piston_kind = map.get("type")?; + let piston_kind = PistonKind::from_str(piston_kind).ok()?; + block.set_piston_kind(piston_kind); + let short = map.get("short")?; + let short = bool::from_str(short).ok()?; + block.set_short(short); + Some(block) + } + fn white_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::white_wool(); + Some(block) + } + fn orange_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::orange_wool(); + Some(block) + } + fn magenta_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::magenta_wool(); + Some(block) + } + fn light_blue_wool_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_wool(); + Some(block) + } + fn yellow_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::yellow_wool(); + Some(block) + } + fn lime_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lime_wool(); + Some(block) + } + fn pink_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::pink_wool(); + Some(block) + } + fn gray_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::gray_wool(); + Some(block) + } + fn light_gray_wool_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_wool(); + Some(block) + } + fn cyan_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cyan_wool(); + Some(block) + } + fn purple_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::purple_wool(); + Some(block) + } + fn blue_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::blue_wool(); + Some(block) + } + fn brown_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::brown_wool(); + Some(block) + } + fn green_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::green_wool(); + Some(block) + } + fn red_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::red_wool(); + Some(block) + } + fn black_wool_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::black_wool(); + Some(block) + } + fn moving_piston_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::moving_piston(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + let piston_kind = map.get("type")?; + let piston_kind = PistonKind::from_str(piston_kind).ok()?; + block.set_piston_kind(piston_kind); + Some(block) + } + fn dandelion_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::dandelion(); + Some(block) + } + fn poppy_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::poppy(); + Some(block) + } + fn blue_orchid_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::blue_orchid(); + Some(block) + } + fn allium_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::allium(); + Some(block) + } + fn azure_bluet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::azure_bluet(); + Some(block) + } + fn red_tulip_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::red_tulip(); + Some(block) + } + fn orange_tulip_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::orange_tulip(); + Some(block) + } + fn white_tulip_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::white_tulip(); + Some(block) + } + fn pink_tulip_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::pink_tulip(); + Some(block) + } + fn oxeye_daisy_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oxeye_daisy(); + Some(block) + } + fn cornflower_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cornflower(); + Some(block) + } + fn wither_rose_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::wither_rose(); + Some(block) + } + fn lily_of_the_valley_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lily_of_the_valley(); + Some(block) + } + fn brown_mushroom_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_mushroom(); + Some(block) + } + fn red_mushroom_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::red_mushroom(); + Some(block) + } + fn gold_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::gold_block(); + Some(block) + } + fn iron_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::iron_block(); + Some(block) + } + fn bricks_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::bricks(); + Some(block) + } + fn tnt_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::tnt(); + let unstable = map.get("unstable")?; + let unstable = bool::from_str(unstable).ok()?; + block.set_unstable(unstable); + Some(block) + } + fn bookshelf_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::bookshelf(); + Some(block) + } + fn mossy_cobblestone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mossy_cobblestone(); + Some(block) + } + fn obsidian_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::obsidian(); + Some(block) + } + fn torch_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::torch(); + Some(block) + } + fn wall_torch_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::wall_torch(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn fire_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::fire(); + let age_0_15 = map.get("age")?; + let age_0_15 = { + let x = i32::from_str(age_0_15).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_15(age_0_15); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn soul_fire_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::soul_fire(); + Some(block) + } + fn spawner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::spawner(); + Some(block) + } + fn oak_stairs_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn chest_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::chest(); + let chest_kind = map.get("type")?; + let chest_kind = ChestKind::from_str(chest_kind).ok()?; + block.set_chest_kind(chest_kind); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn redstone_wire_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::redstone_wire(); + let east_wire = map.get("east")?; + let east_wire = EastWire::from_str(east_wire).ok()?; + block.set_east_wire(east_wire); + let north_wire = map.get("north")?; + let north_wire = NorthWire::from_str(north_wire).ok()?; + block.set_north_wire(north_wire); + let power = map.get("power")?; + let power = { + let x = i32::from_str(power).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_power(power); + let south_wire = map.get("south")?; + let south_wire = SouthWire::from_str(south_wire).ok()?; + block.set_south_wire(south_wire); + let west_wire = map.get("west")?; + let west_wire = WestWire::from_str(west_wire).ok()?; + block.set_west_wire(west_wire); + Some(block) + } + fn diamond_ore_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::diamond_ore(); + Some(block) + } + fn diamond_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::diamond_block(); + Some(block) + } + fn crafting_table_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crafting_table(); + Some(block) + } + fn wheat_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::wheat(); + let age_0_7 = map.get("age")?; + let age_0_7 = { + let x = i32::from_str(age_0_7).ok()?; + if !(0i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_7(age_0_7); + Some(block) + } + fn farmland_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::farmland(); + let moisture = map.get("moisture")?; + let moisture = { + let x = i32::from_str(moisture).ok()?; + if !(0i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_moisture(moisture); + Some(block) + } + fn furnace_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::furnace(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + Some(block) + } + fn oak_sign_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_sign(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn spruce_sign_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::spruce_sign(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn birch_sign_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_sign(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn acacia_sign_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::acacia_sign(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn jungle_sign_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::jungle_sign(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dark_oak_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_sign(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn oak_door_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn ladder_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::ladder(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn rail_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::rail(); + let rail_shape = map.get("shape")?; + let rail_shape = RailShape::from_str(rail_shape).ok()?; + block.set_rail_shape(rail_shape); + Some(block) + } + fn cobblestone_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cobblestone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn oak_wall_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::oak_wall_sign(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn spruce_wall_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_wall_sign(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn birch_wall_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::birch_wall_sign(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn acacia_wall_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_wall_sign(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn jungle_wall_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_wall_sign(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dark_oak_wall_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_wall_sign(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn lever_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lever(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn stone_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stone_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn iron_door_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::iron_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn oak_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::oak_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn spruce_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn birch_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::birch_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn jungle_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn acacia_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn dark_oak_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn redstone_ore_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::redstone_ore(); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + Some(block) + } + fn redstone_torch_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::redstone_torch(); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + Some(block) + } + fn redstone_wall_torch_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::redstone_wall_torch(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + Some(block) + } + fn stone_button_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::stone_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn snow_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::snow(); + let layers = map.get("layers")?; + let layers = { + let x = i32::from_str(layers).ok()?; + if !(1i32..=8i32).contains(&x) { + return None; + } + x + }; + block.set_layers(layers); + Some(block) + } + fn ice_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::ice(); + Some(block) + } + fn snow_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::snow_block(); + Some(block) + } + fn cactus_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cactus(); + let age_0_15 = map.get("age")?; + let age_0_15 = { + let x = i32::from_str(age_0_15).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_15(age_0_15); + Some(block) + } + fn clay_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::clay(); + Some(block) + } + fn sugar_cane_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::sugar_cane(); + let age_0_15 = map.get("age")?; + let age_0_15 = { + let x = i32::from_str(age_0_15).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_15(age_0_15); + Some(block) + } + fn jukebox_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::jukebox(); + let has_record = map.get("has_record")?; + let has_record = bool::from_str(has_record).ok()?; + block.set_has_record(has_record); + Some(block) + } + fn oak_fence_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn pumpkin_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::pumpkin(); + Some(block) + } + fn netherrack_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::netherrack(); + Some(block) + } + fn soul_sand_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::soul_sand(); + Some(block) + } + fn soul_soil_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::soul_soil(); + Some(block) + } + fn basalt_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::basalt(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn polished_basalt_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_basalt(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn soul_torch_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::soul_torch(); + Some(block) + } + fn soul_wall_torch_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::soul_wall_torch(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn glowstone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::glowstone(); + Some(block) + } + fn nether_portal_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_portal(); + let axis_xz = map.get("axis")?; + let axis_xz = AxisXz::from_str(axis_xz).ok()?; + block.set_axis_xz(axis_xz); + Some(block) + } + fn carved_pumpkin_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::carved_pumpkin(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn jack_o_lantern_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jack_o_lantern(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn cake_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cake(); + let bites = map.get("bites")?; + let bites = { + let x = i32::from_str(bites).ok()?; + if !(0i32..=6i32).contains(&x) { + return None; + } + x + }; + block.set_bites(bites); + Some(block) + } + fn repeater_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::repeater(); + let delay = map.get("delay")?; + let delay = { + let x = i32::from_str(delay).ok()?; + if !(1i32..=4i32).contains(&x) { + return None; + } + x + }; + block.set_delay(delay); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let locked = map.get("locked")?; + let locked = bool::from_str(locked).ok()?; + block.set_locked(locked); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn white_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::white_stained_glass(); + Some(block) + } + fn orange_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_stained_glass(); + Some(block) + } + fn magenta_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_stained_glass(); + Some(block) + } + fn light_blue_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_stained_glass(); + Some(block) + } + fn yellow_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_stained_glass(); + Some(block) + } + fn lime_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lime_stained_glass(); + Some(block) + } + fn pink_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::pink_stained_glass(); + Some(block) + } + fn gray_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gray_stained_glass(); + Some(block) + } + fn light_gray_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_stained_glass(); + Some(block) + } + fn cyan_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cyan_stained_glass(); + Some(block) + } + fn purple_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_stained_glass(); + Some(block) + } + fn blue_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blue_stained_glass(); + Some(block) + } + fn brown_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_stained_glass(); + Some(block) + } + fn green_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::green_stained_glass(); + Some(block) + } + fn red_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_stained_glass(); + Some(block) + } + fn black_stained_glass_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::black_stained_glass(); + Some(block) + } + fn oak_trapdoor_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn spruce_trapdoor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn birch_trapdoor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::birch_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn jungle_trapdoor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn acacia_trapdoor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dark_oak_trapdoor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn stone_bricks_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::stone_bricks(); + Some(block) + } + fn mossy_stone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mossy_stone_bricks(); + Some(block) + } + fn cracked_stone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cracked_stone_bricks(); + Some(block) + } + fn chiseled_stone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chiseled_stone_bricks(); + Some(block) + } + fn infested_stone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::infested_stone(); + Some(block) + } + fn infested_cobblestone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::infested_cobblestone(); + Some(block) + } + fn infested_stone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::infested_stone_bricks(); + Some(block) + } + fn infested_mossy_stone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::infested_mossy_stone_bricks(); + Some(block) + } + fn infested_cracked_stone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::infested_cracked_stone_bricks(); + Some(block) + } + fn infested_chiseled_stone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::infested_chiseled_stone_bricks(); + Some(block) + } + fn brown_mushroom_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_mushroom_block(); + let down = map.get("down")?; + let down = bool::from_str(down).ok()?; + block.set_down(down); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn red_mushroom_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_mushroom_block(); + let down = map.get("down")?; + let down = bool::from_str(down).ok()?; + block.set_down(down); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn mushroom_stem_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mushroom_stem(); + let down = map.get("down")?; + let down = bool::from_str(down).ok()?; + block.set_down(down); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn iron_bars_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::iron_bars(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn chain_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::chain(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn glass_pane_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn melon_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::melon(); + Some(block) + } + fn attached_pumpkin_stem_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::attached_pumpkin_stem(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn attached_melon_stem_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::attached_melon_stem(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn pumpkin_stem_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::pumpkin_stem(); + let age_0_7 = map.get("age")?; + let age_0_7 = { + let x = i32::from_str(age_0_7).ok()?; + if !(0i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_7(age_0_7); + Some(block) + } + fn melon_stem_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::melon_stem(); + let age_0_7 = map.get("age")?; + let age_0_7 = { + let x = i32::from_str(age_0_7).ok()?; + if !(0i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_7(age_0_7); + Some(block) + } + fn vine_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::vine(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn oak_fence_gate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::oak_fence_gate(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let in_wall = map.get("in_wall")?; + let in_wall = bool::from_str(in_wall).ok()?; + block.set_in_wall(in_wall); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn brick_stairs_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::brick_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn stone_brick_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stone_brick_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn mycelium_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::mycelium(); + let snowy = map.get("snowy")?; + let snowy = bool::from_str(snowy).ok()?; + block.set_snowy(snowy); + Some(block) + } + fn lily_pad_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lily_pad(); + Some(block) + } + fn nether_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_bricks(); + Some(block) + } + fn nether_brick_fence_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_brick_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn nether_brick_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_brick_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn nether_wart_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::nether_wart(); + let age_0_3 = map.get("age")?; + let age_0_3 = { + let x = i32::from_str(age_0_3).ok()?; + if !(0i32..=3i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_3(age_0_3); + Some(block) + } + fn enchanting_table_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::enchanting_table(); + Some(block) + } + fn brewing_stand_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brewing_stand(); + let has_bottle_0 = map.get("has_bottle_0")?; + let has_bottle_0 = bool::from_str(has_bottle_0).ok()?; + block.set_has_bottle_0(has_bottle_0); + let has_bottle_1 = map.get("has_bottle_1")?; + let has_bottle_1 = bool::from_str(has_bottle_1).ok()?; + block.set_has_bottle_1(has_bottle_1); + let has_bottle_2 = map.get("has_bottle_2")?; + let has_bottle_2 = bool::from_str(has_bottle_2).ok()?; + block.set_has_bottle_2(has_bottle_2); + Some(block) + } + fn cauldron_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cauldron(); + let cauldron_level = map.get("level")?; + let cauldron_level = { + let x = i32::from_str(cauldron_level).ok()?; + if !(0i32..=3i32).contains(&x) { + return None; + } + x + }; + block.set_cauldron_level(cauldron_level); + Some(block) + } + fn end_portal_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::end_portal(); + Some(block) + } + fn end_portal_frame_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::end_portal_frame(); + let eye = map.get("eye")?; + let eye = bool::from_str(eye).ok()?; + block.set_eye(eye); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn end_stone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::end_stone(); + Some(block) + } + fn dragon_egg_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::dragon_egg(); + Some(block) + } + fn redstone_lamp_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::redstone_lamp(); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + Some(block) + } + fn cocoa_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cocoa(); + let age_0_2 = map.get("age")?; + let age_0_2 = { + let x = i32::from_str(age_0_2).ok()?; + if !(0i32..=2i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_2(age_0_2); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn sandstone_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::sandstone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn emerald_ore_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::emerald_ore(); + Some(block) + } + fn ender_chest_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::ender_chest(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn tripwire_hook_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::tripwire_hook(); + let attached = map.get("attached")?; + let attached = bool::from_str(attached).ok()?; + block.set_attached(attached); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn tripwire_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::tripwire(); + let attached = map.get("attached")?; + let attached = bool::from_str(attached).ok()?; + block.set_attached(attached); + let disarmed = map.get("disarmed")?; + let disarmed = bool::from_str(disarmed).ok()?; + block.set_disarmed(disarmed); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn emerald_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::emerald_block(); + Some(block) + } + fn spruce_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn birch_stairs_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn jungle_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn command_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::command_block(); + let conditional = map.get("conditional")?; + let conditional = bool::from_str(conditional).ok()?; + block.set_conditional(conditional); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn beacon_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::beacon(); + Some(block) + } + fn cobblestone_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cobblestone_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn mossy_cobblestone_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mossy_cobblestone_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn flower_pot_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::flower_pot(); + Some(block) + } + fn potted_oak_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_oak_sapling(); + Some(block) + } + fn potted_spruce_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_spruce_sapling(); + Some(block) + } + fn potted_birch_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_birch_sapling(); + Some(block) + } + fn potted_jungle_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_jungle_sapling(); + Some(block) + } + fn potted_acacia_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_acacia_sapling(); + Some(block) + } + fn potted_dark_oak_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_dark_oak_sapling(); + Some(block) + } + fn potted_fern_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::potted_fern(); + Some(block) + } + fn potted_dandelion_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_dandelion(); + Some(block) + } + fn potted_poppy_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::potted_poppy(); + Some(block) + } + fn potted_blue_orchid_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_blue_orchid(); + Some(block) + } + fn potted_allium_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_allium(); + Some(block) + } + fn potted_azure_bluet_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_azure_bluet(); + Some(block) + } + fn potted_red_tulip_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_red_tulip(); + Some(block) + } + fn potted_orange_tulip_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_orange_tulip(); + Some(block) + } + fn potted_white_tulip_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_white_tulip(); + Some(block) + } + fn potted_pink_tulip_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_pink_tulip(); + Some(block) + } + fn potted_oxeye_daisy_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_oxeye_daisy(); + Some(block) + } + fn potted_cornflower_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_cornflower(); + Some(block) + } + fn potted_lily_of_the_valley_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_lily_of_the_valley(); + Some(block) + } + fn potted_wither_rose_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_wither_rose(); + Some(block) + } + fn potted_red_mushroom_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_red_mushroom(); + Some(block) + } + fn potted_brown_mushroom_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_brown_mushroom(); + Some(block) + } + fn potted_dead_bush_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_dead_bush(); + Some(block) + } + fn potted_cactus_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_cactus(); + Some(block) + } + fn carrots_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::carrots(); + let age_0_7 = map.get("age")?; + let age_0_7 = { + let x = i32::from_str(age_0_7).ok()?; + if !(0i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_7(age_0_7); + Some(block) + } + fn potatoes_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::potatoes(); + let age_0_7 = map.get("age")?; + let age_0_7 = { + let x = i32::from_str(age_0_7).ok()?; + if !(0i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_7(age_0_7); + Some(block) + } + fn oak_button_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn spruce_button_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn birch_button_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn jungle_button_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn acacia_button_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn dark_oak_button_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn skeleton_skull_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::skeleton_skull(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn skeleton_wall_skull_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::skeleton_wall_skull(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn wither_skeleton_skull_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::wither_skeleton_skull(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn wither_skeleton_wall_skull_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::wither_skeleton_wall_skull(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn zombie_head_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::zombie_head(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn zombie_wall_head_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::zombie_wall_head(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn player_head_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::player_head(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn player_wall_head_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::player_wall_head(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn creeper_head_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::creeper_head(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn creeper_wall_head_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::creeper_wall_head(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn dragon_head_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::dragon_head(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn dragon_wall_head_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dragon_wall_head(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn anvil_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::anvil(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn chipped_anvil_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chipped_anvil(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn damaged_anvil_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::damaged_anvil(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn trapped_chest_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::trapped_chest(); + let chest_kind = map.get("type")?; + let chest_kind = ChestKind::from_str(chest_kind).ok()?; + block.set_chest_kind(chest_kind); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn light_weighted_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_weighted_pressure_plate(); + let power = map.get("power")?; + let power = { + let x = i32::from_str(power).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_power(power); + Some(block) + } + fn heavy_weighted_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::heavy_weighted_pressure_plate(); + let power = map.get("power")?; + let power = { + let x = i32::from_str(power).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_power(power); + Some(block) + } + fn comparator_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::comparator(); + let comparator_mode = map.get("mode")?; + let comparator_mode = ComparatorMode::from_str(comparator_mode).ok()?; + block.set_comparator_mode(comparator_mode); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn daylight_detector_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::daylight_detector(); + let inverted = map.get("inverted")?; + let inverted = bool::from_str(inverted).ok()?; + block.set_inverted(inverted); + let power = map.get("power")?; + let power = { + let x = i32::from_str(power).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_power(power); + Some(block) + } + fn redstone_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::redstone_block(); + Some(block) + } + fn nether_quartz_ore_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_quartz_ore(); + Some(block) + } + fn hopper_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::hopper(); + let enabled = map.get("enabled")?; + let enabled = bool::from_str(enabled).ok()?; + block.set_enabled(enabled); + let facing_cardinal_and_down = map.get("facing")?; + let facing_cardinal_and_down = + FacingCardinalAndDown::from_str(facing_cardinal_and_down).ok()?; + block.set_facing_cardinal_and_down(facing_cardinal_and_down); + Some(block) + } + fn quartz_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::quartz_block(); + Some(block) + } + fn chiseled_quartz_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chiseled_quartz_block(); + Some(block) + } + fn quartz_pillar_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::quartz_pillar(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn quartz_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::quartz_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn activator_rail_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::activator_rail(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let powered_rail_shape = map.get("shape")?; + let powered_rail_shape = PoweredRailShape::from_str(powered_rail_shape).ok()?; + block.set_powered_rail_shape(powered_rail_shape); + Some(block) + } + fn dropper_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::dropper(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + let triggered = map.get("triggered")?; + let triggered = bool::from_str(triggered).ok()?; + block.set_triggered(triggered); + Some(block) + } + fn white_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::white_terracotta(); + Some(block) + } + fn orange_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_terracotta(); + Some(block) + } + fn magenta_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_terracotta(); + Some(block) + } + fn light_blue_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_terracotta(); + Some(block) + } + fn yellow_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_terracotta(); + Some(block) + } + fn lime_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lime_terracotta(); + Some(block) + } + fn pink_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::pink_terracotta(); + Some(block) + } + fn gray_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gray_terracotta(); + Some(block) + } + fn light_gray_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_terracotta(); + Some(block) + } + fn cyan_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cyan_terracotta(); + Some(block) + } + fn purple_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_terracotta(); + Some(block) + } + fn blue_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blue_terracotta(); + Some(block) + } + fn brown_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_terracotta(); + Some(block) + } + fn green_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::green_terracotta(); + Some(block) + } + fn red_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_terracotta(); + Some(block) + } + fn black_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::black_terracotta(); + Some(block) + } + fn white_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::white_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn orange_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn magenta_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn light_blue_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn yellow_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn lime_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lime_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn pink_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::pink_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn gray_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gray_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn light_gray_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn cyan_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cyan_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn purple_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn blue_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blue_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn brown_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn green_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::green_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn red_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn black_stained_glass_pane_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::black_stained_glass_pane(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn acacia_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dark_oak_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn slime_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::slime_block(); + Some(block) + } + fn barrier_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::barrier(); + Some(block) + } + fn iron_trapdoor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::iron_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn prismarine_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::prismarine(); + Some(block) + } + fn prismarine_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::prismarine_bricks(); + Some(block) + } + fn dark_prismarine_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_prismarine(); + Some(block) + } + fn prismarine_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::prismarine_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn prismarine_brick_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::prismarine_brick_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dark_prismarine_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_prismarine_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn prismarine_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::prismarine_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn prismarine_brick_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::prismarine_brick_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dark_prismarine_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_prismarine_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn sea_lantern_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::sea_lantern(); + Some(block) + } + fn hay_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::hay_block(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn white_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::white_carpet(); + Some(block) + } + fn orange_carpet_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_carpet(); + Some(block) + } + fn magenta_carpet_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_carpet(); + Some(block) + } + fn light_blue_carpet_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_carpet(); + Some(block) + } + fn yellow_carpet_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_carpet(); + Some(block) + } + fn lime_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lime_carpet(); + Some(block) + } + fn pink_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::pink_carpet(); + Some(block) + } + fn gray_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::gray_carpet(); + Some(block) + } + fn light_gray_carpet_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_carpet(); + Some(block) + } + fn cyan_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cyan_carpet(); + Some(block) + } + fn purple_carpet_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_carpet(); + Some(block) + } + fn blue_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::blue_carpet(); + Some(block) + } + fn brown_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::brown_carpet(); + Some(block) + } + fn green_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::green_carpet(); + Some(block) + } + fn red_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::red_carpet(); + Some(block) + } + fn black_carpet_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::black_carpet(); + Some(block) + } + fn terracotta_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::terracotta(); + Some(block) + } + fn coal_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::coal_block(); + Some(block) + } + fn packed_ice_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::packed_ice(); + Some(block) + } + fn sunflower_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::sunflower(); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + Some(block) + } + fn lilac_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lilac(); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + Some(block) + } + fn rose_bush_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::rose_bush(); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + Some(block) + } + fn peony_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::peony(); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + Some(block) + } + fn tall_grass_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::tall_grass(); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + Some(block) + } + fn large_fern_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::large_fern(); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + Some(block) + } + fn white_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::white_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn orange_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn magenta_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn light_blue_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn yellow_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn lime_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lime_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn pink_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::pink_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn gray_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::gray_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn light_gray_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn cyan_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cyan_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn purple_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn blue_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::blue_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn brown_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::brown_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn green_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::green_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn red_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::red_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn black_banner_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::black_banner(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + Some(block) + } + fn white_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::white_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn orange_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn magenta_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn light_blue_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn yellow_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn lime_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lime_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn pink_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::pink_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn gray_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gray_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn light_gray_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn cyan_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cyan_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn purple_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn blue_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blue_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn brown_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn green_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::green_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn red_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn black_wall_banner_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::black_wall_banner(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn red_sandstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_sandstone(); + Some(block) + } + fn chiseled_red_sandstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chiseled_red_sandstone(); + Some(block) + } + fn cut_red_sandstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cut_red_sandstone(); + Some(block) + } + fn red_sandstone_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_sandstone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn oak_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::oak_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn spruce_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::spruce_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn birch_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn jungle_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::jungle_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn acacia_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::acacia_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dark_oak_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn stone_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::stone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn smooth_stone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_stone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn sandstone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::sandstone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn cut_sandstone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cut_sandstone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn petrified_oak_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::petrified_oak_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn cobblestone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cobblestone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn brick_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::brick_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn stone_brick_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stone_brick_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn nether_brick_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_brick_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn quartz_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::quartz_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn red_sandstone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_sandstone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn cut_red_sandstone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cut_red_sandstone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn purpur_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::purpur_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn smooth_stone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::smooth_stone(); + Some(block) + } + fn smooth_sandstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_sandstone(); + Some(block) + } + fn smooth_quartz_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_quartz(); + Some(block) + } + fn smooth_red_sandstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_red_sandstone(); + Some(block) + } + fn spruce_fence_gate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::spruce_fence_gate(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let in_wall = map.get("in_wall")?; + let in_wall = bool::from_str(in_wall).ok()?; + block.set_in_wall(in_wall); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn birch_fence_gate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::birch_fence_gate(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let in_wall = map.get("in_wall")?; + let in_wall = bool::from_str(in_wall).ok()?; + block.set_in_wall(in_wall); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn jungle_fence_gate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::jungle_fence_gate(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let in_wall = map.get("in_wall")?; + let in_wall = bool::from_str(in_wall).ok()?; + block.set_in_wall(in_wall); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn acacia_fence_gate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::acacia_fence_gate(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let in_wall = map.get("in_wall")?; + let in_wall = bool::from_str(in_wall).ok()?; + block.set_in_wall(in_wall); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn dark_oak_fence_gate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_fence_gate(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let in_wall = map.get("in_wall")?; + let in_wall = bool::from_str(in_wall).ok()?; + block.set_in_wall(in_wall); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn spruce_fence_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::spruce_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn birch_fence_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn jungle_fence_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::jungle_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn acacia_fence_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::acacia_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn dark_oak_fence_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn spruce_door_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::spruce_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn birch_door_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::birch_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn jungle_door_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::jungle_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn acacia_door_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::acacia_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn dark_oak_door_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dark_oak_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn end_rod_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::end_rod(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn chorus_plant_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::chorus_plant(); + let down = map.get("down")?; + let down = bool::from_str(down).ok()?; + block.set_down(down); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn chorus_flower_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chorus_flower(); + let age_0_5 = map.get("age")?; + let age_0_5 = { + let x = i32::from_str(age_0_5).ok()?; + if !(0i32..=5i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_5(age_0_5); + Some(block) + } + fn purpur_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::purpur_block(); + Some(block) + } + fn purpur_pillar_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purpur_pillar(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn purpur_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purpur_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn end_stone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::end_stone_bricks(); + Some(block) + } + fn beetroots_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::beetroots(); + let age_0_3 = map.get("age")?; + let age_0_3 = { + let x = i32::from_str(age_0_3).ok()?; + if !(0i32..=3i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_3(age_0_3); + Some(block) + } + fn grass_path_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::grass_path(); + Some(block) + } + fn end_gateway_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::end_gateway(); + Some(block) + } + fn repeating_command_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::repeating_command_block(); + let conditional = map.get("conditional")?; + let conditional = bool::from_str(conditional).ok()?; + block.set_conditional(conditional); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn chain_command_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chain_command_block(); + let conditional = map.get("conditional")?; + let conditional = bool::from_str(conditional).ok()?; + block.set_conditional(conditional); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn frosted_ice_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::frosted_ice(); + let age_0_3 = map.get("age")?; + let age_0_3 = { + let x = i32::from_str(age_0_3).ok()?; + if !(0i32..=3i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_3(age_0_3); + Some(block) + } + fn magma_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::magma_block(); + Some(block) + } + fn nether_wart_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_wart_block(); + Some(block) + } + fn red_nether_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_nether_bricks(); + Some(block) + } + fn bone_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::bone_block(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn structure_void_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::structure_void(); + Some(block) + } + fn observer_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::observer(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn shulker_box_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn white_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::white_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn orange_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn magenta_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn light_blue_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn yellow_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn lime_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lime_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn pink_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::pink_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn gray_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gray_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn light_gray_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn cyan_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cyan_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn purple_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn blue_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blue_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn brown_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn green_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::green_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn red_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn black_shulker_box_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::black_shulker_box(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + Some(block) + } + fn white_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::white_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn orange_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn magenta_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn light_blue_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn yellow_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn lime_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lime_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn pink_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::pink_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn gray_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gray_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn light_gray_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn cyan_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cyan_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn purple_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn blue_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blue_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn brown_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn green_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::green_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn red_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn black_glazed_terracotta_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::black_glazed_terracotta(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn white_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::white_concrete(); + Some(block) + } + fn orange_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_concrete(); + Some(block) + } + fn magenta_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_concrete(); + Some(block) + } + fn light_blue_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_concrete(); + Some(block) + } + fn yellow_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_concrete(); + Some(block) + } + fn lime_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lime_concrete(); + Some(block) + } + fn pink_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::pink_concrete(); + Some(block) + } + fn gray_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gray_concrete(); + Some(block) + } + fn light_gray_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_concrete(); + Some(block) + } + fn cyan_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cyan_concrete(); + Some(block) + } + fn purple_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_concrete(); + Some(block) + } + fn blue_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blue_concrete(); + Some(block) + } + fn brown_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_concrete(); + Some(block) + } + fn green_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::green_concrete(); + Some(block) + } + fn red_concrete_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::red_concrete(); + Some(block) + } + fn black_concrete_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::black_concrete(); + Some(block) + } + fn white_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::white_concrete_powder(); + Some(block) + } + fn orange_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::orange_concrete_powder(); + Some(block) + } + fn magenta_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::magenta_concrete_powder(); + Some(block) + } + fn light_blue_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_blue_concrete_powder(); + Some(block) + } + fn yellow_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::yellow_concrete_powder(); + Some(block) + } + fn lime_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::lime_concrete_powder(); + Some(block) + } + fn pink_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::pink_concrete_powder(); + Some(block) + } + fn gray_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gray_concrete_powder(); + Some(block) + } + fn light_gray_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::light_gray_concrete_powder(); + Some(block) + } + fn cyan_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cyan_concrete_powder(); + Some(block) + } + fn purple_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::purple_concrete_powder(); + Some(block) + } + fn blue_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blue_concrete_powder(); + Some(block) + } + fn brown_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brown_concrete_powder(); + Some(block) + } + fn green_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::green_concrete_powder(); + Some(block) + } + fn red_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_concrete_powder(); + Some(block) + } + fn black_concrete_powder_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::black_concrete_powder(); + Some(block) + } + fn kelp_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::kelp(); + let age_0_25 = map.get("age")?; + let age_0_25 = { + let x = i32::from_str(age_0_25).ok()?; + if !(0i32..=25i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_25(age_0_25); + Some(block) + } + fn kelp_plant_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::kelp_plant(); + Some(block) + } + fn dried_kelp_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dried_kelp_block(); + Some(block) + } + fn turtle_egg_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::turtle_egg(); + let eggs = map.get("eggs")?; + let eggs = { + let x = i32::from_str(eggs).ok()?; + if !(1i32..=4i32).contains(&x) { + return None; + } + x + }; + block.set_eggs(eggs); + let hatch = map.get("hatch")?; + let hatch = { + let x = i32::from_str(hatch).ok()?; + if !(0i32..=2i32).contains(&x) { + return None; + } + x + }; + block.set_hatch(hatch); + Some(block) + } + fn dead_tube_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_tube_coral_block(); + Some(block) + } + fn dead_brain_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_brain_coral_block(); + Some(block) + } + fn dead_bubble_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_bubble_coral_block(); + Some(block) + } + fn dead_fire_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_fire_coral_block(); + Some(block) + } + fn dead_horn_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_horn_coral_block(); + Some(block) + } + fn tube_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::tube_coral_block(); + Some(block) + } + fn brain_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brain_coral_block(); + Some(block) + } + fn bubble_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::bubble_coral_block(); + Some(block) + } + fn fire_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::fire_coral_block(); + Some(block) + } + fn horn_coral_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::horn_coral_block(); + Some(block) + } + fn dead_tube_coral_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_tube_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_brain_coral_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_brain_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_bubble_coral_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_bubble_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_fire_coral_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_fire_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_horn_coral_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_horn_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn tube_coral_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::tube_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn brain_coral_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::brain_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn bubble_coral_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::bubble_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn fire_coral_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::fire_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn horn_coral_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::horn_coral(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_tube_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_tube_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_brain_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_brain_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_bubble_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_bubble_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_fire_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_fire_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_horn_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_horn_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn tube_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::tube_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn brain_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brain_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn bubble_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::bubble_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn fire_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::fire_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn horn_coral_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::horn_coral_fan(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_tube_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_tube_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_brain_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_brain_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_bubble_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_bubble_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_fire_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_fire_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn dead_horn_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::dead_horn_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn tube_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::tube_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn brain_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::brain_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn bubble_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::bubble_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn fire_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::fire_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn horn_coral_wall_fan_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::horn_coral_wall_fan(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn sea_pickle_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::sea_pickle(); + let pickles = map.get("pickles")?; + let pickles = { + let x = i32::from_str(pickles).ok()?; + if !(1i32..=4i32).contains(&x) { + return None; + } + x + }; + block.set_pickles(pickles); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn blue_ice_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::blue_ice(); + Some(block) + } + fn conduit_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::conduit(); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn bamboo_sapling_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::bamboo_sapling(); + Some(block) + } + fn bamboo_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::bamboo(); + let age_0_1 = map.get("age")?; + let age_0_1 = { + let x = i32::from_str(age_0_1).ok()?; + if !(0i32..=1i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_1(age_0_1); + let leaves = map.get("leaves")?; + let leaves = Leaves::from_str(leaves).ok()?; + block.set_leaves(leaves); + let stage = map.get("stage")?; + let stage = { + let x = i32::from_str(stage).ok()?; + if !(0i32..=1i32).contains(&x) { + return None; + } + x + }; + block.set_stage(stage); + Some(block) + } + fn potted_bamboo_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_bamboo(); + Some(block) + } + fn void_air_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::void_air(); + Some(block) + } + fn cave_air_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::cave_air(); + Some(block) + } + fn bubble_column_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::bubble_column(); + let drag = map.get("drag")?; + let drag = bool::from_str(drag).ok()?; + block.set_drag(drag); + Some(block) + } + fn polished_granite_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_granite_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn smooth_red_sandstone_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_red_sandstone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn mossy_stone_brick_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mossy_stone_brick_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_diorite_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_diorite_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn mossy_cobblestone_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mossy_cobblestone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn end_stone_brick_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::end_stone_brick_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn stone_stairs_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::stone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn smooth_sandstone_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_sandstone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn smooth_quartz_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_quartz_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn granite_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::granite_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn andesite_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::andesite_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn red_nether_brick_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_nether_brick_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_andesite_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_andesite_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn diorite_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::diorite_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_granite_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_granite_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn smooth_red_sandstone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_red_sandstone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn mossy_stone_brick_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mossy_stone_brick_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_diorite_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_diorite_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn mossy_cobblestone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mossy_cobblestone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn end_stone_brick_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::end_stone_brick_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn smooth_sandstone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_sandstone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn smooth_quartz_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smooth_quartz_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn granite_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::granite_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn andesite_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::andesite_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn red_nether_brick_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_nether_brick_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_andesite_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_andesite_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn diorite_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::diorite_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn brick_wall_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::brick_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn prismarine_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::prismarine_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn red_sandstone_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_sandstone_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn mossy_stone_brick_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::mossy_stone_brick_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn granite_wall_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::granite_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn stone_brick_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stone_brick_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn nether_brick_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_brick_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn andesite_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::andesite_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn red_nether_brick_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::red_nether_brick_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn sandstone_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::sandstone_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn end_stone_brick_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::end_stone_brick_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn diorite_wall_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::diorite_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn scaffolding_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::scaffolding(); + let bottom = map.get("bottom")?; + let bottom = bool::from_str(bottom).ok()?; + block.set_bottom(bottom); + let distance_0_7 = map.get("distance")?; + let distance_0_7 = { + let x = i32::from_str(distance_0_7).ok()?; + if !(0i32..=7i32).contains(&x) { + return None; + } + x + }; + block.set_distance_0_7(distance_0_7); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn loom_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::loom(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn barrel_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::barrel(); + let facing_cubic = map.get("facing")?; + let facing_cubic = FacingCubic::from_str(facing_cubic).ok()?; + block.set_facing_cubic(facing_cubic); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + Some(block) + } + fn smoker_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::smoker(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + Some(block) + } + fn blast_furnace_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blast_furnace(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + Some(block) + } + fn cartography_table_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cartography_table(); + Some(block) + } + fn fletching_table_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::fletching_table(); + Some(block) + } + fn grindstone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::grindstone(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn lectern_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lectern(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let has_book = map.get("has_book")?; + let has_book = bool::from_str(has_book).ok()?; + block.set_has_book(has_book); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn smithing_table_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::smithing_table(); + Some(block) + } + fn stonecutter_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::stonecutter(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + Some(block) + } + fn bell_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::bell(); + let attachment = map.get("attachment")?; + let attachment = Attachment::from_str(attachment).ok()?; + block.set_attachment(attachment); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn lantern_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lantern(); + let hanging = map.get("hanging")?; + let hanging = bool::from_str(hanging).ok()?; + block.set_hanging(hanging); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn soul_lantern_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::soul_lantern(); + let hanging = map.get("hanging")?; + let hanging = bool::from_str(hanging).ok()?; + block.set_hanging(hanging); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn campfire_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::campfire(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + let signal_fire = map.get("signal_fire")?; + let signal_fire = bool::from_str(signal_fire).ok()?; + block.set_signal_fire(signal_fire); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn soul_campfire_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::soul_campfire(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let lit = map.get("lit")?; + let lit = bool::from_str(lit).ok()?; + block.set_lit(lit); + let signal_fire = map.get("signal_fire")?; + let signal_fire = bool::from_str(signal_fire).ok()?; + block.set_signal_fire(signal_fire); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn sweet_berry_bush_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::sweet_berry_bush(); + let age_0_3 = map.get("age")?; + let age_0_3 = { + let x = i32::from_str(age_0_3).ok()?; + if !(0i32..=3i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_3(age_0_3); + Some(block) + } + fn warped_stem_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::warped_stem(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_warped_stem_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_warped_stem(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn warped_hyphae_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_hyphae(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_warped_hyphae_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_warped_hyphae(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn warped_nylium_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_nylium(); + Some(block) + } + fn warped_fungus_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_fungus(); + Some(block) + } + fn warped_wart_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_wart_block(); + Some(block) + } + fn warped_roots_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::warped_roots(); + Some(block) + } + fn nether_sprouts_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::nether_sprouts(); + Some(block) + } + fn crimson_stem_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::crimson_stem(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_crimson_stem_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_crimson_stem(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn crimson_hyphae_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_hyphae(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn stripped_crimson_hyphae_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::stripped_crimson_hyphae(); + let axis_xyz = map.get("axis")?; + let axis_xyz = AxisXyz::from_str(axis_xyz).ok()?; + block.set_axis_xyz(axis_xyz); + Some(block) + } + fn crimson_nylium_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_nylium(); + Some(block) + } + fn crimson_fungus_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_fungus(); + Some(block) + } + fn shroomlight_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::shroomlight(); + Some(block) + } + fn weeping_vines_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::weeping_vines(); + let age_0_25 = map.get("age")?; + let age_0_25 = { + let x = i32::from_str(age_0_25).ok()?; + if !(0i32..=25i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_25(age_0_25); + Some(block) + } + fn weeping_vines_plant_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::weeping_vines_plant(); + Some(block) + } + fn twisting_vines_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::twisting_vines(); + let age_0_25 = map.get("age")?; + let age_0_25 = { + let x = i32::from_str(age_0_25).ok()?; + if !(0i32..=25i32).contains(&x) { + return None; + } + x + }; + block.set_age_0_25(age_0_25); + Some(block) + } + fn twisting_vines_plant_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::twisting_vines_plant(); + Some(block) + } + fn crimson_roots_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_roots(); + Some(block) + } + fn crimson_planks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_planks(); + Some(block) + } + fn warped_planks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_planks(); + Some(block) + } + fn crimson_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::crimson_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn warped_slab_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::warped_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn crimson_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn warped_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn crimson_fence_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn warped_fence_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::warped_fence(); + let east_connected = map.get("east")?; + let east_connected = bool::from_str(east_connected).ok()?; + block.set_east_connected(east_connected); + let north_connected = map.get("north")?; + let north_connected = bool::from_str(north_connected).ok()?; + block.set_north_connected(north_connected); + let south_connected = map.get("south")?; + let south_connected = bool::from_str(south_connected).ok()?; + block.set_south_connected(south_connected); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_connected = map.get("west")?; + let west_connected = bool::from_str(west_connected).ok()?; + block.set_west_connected(west_connected); + Some(block) + } + fn crimson_trapdoor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn warped_trapdoor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_trapdoor(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn crimson_fence_gate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_fence_gate(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let in_wall = map.get("in_wall")?; + let in_wall = bool::from_str(in_wall).ok()?; + block.set_in_wall(in_wall); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn warped_fence_gate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_fence_gate(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let in_wall = map.get("in_wall")?; + let in_wall = bool::from_str(in_wall).ok()?; + block.set_in_wall(in_wall); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn crimson_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn warped_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn crimson_button_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn warped_button_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn crimson_door_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::crimson_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn warped_door_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::warped_door(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_upper_lower = map.get("half")?; + let half_upper_lower = HalfUpperLower::from_str(half_upper_lower).ok()?; + block.set_half_upper_lower(half_upper_lower); + let hinge = map.get("hinge")?; + let hinge = Hinge::from_str(hinge).ok()?; + block.set_hinge(hinge); + let open = map.get("open")?; + let open = bool::from_str(open).ok()?; + block.set_open(open); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn crimson_sign_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::crimson_sign(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn warped_sign_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::warped_sign(); + let rotation = map.get("rotation")?; + let rotation = { + let x = i32::from_str(rotation).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_rotation(rotation); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn crimson_wall_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crimson_wall_sign(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn warped_wall_sign_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::warped_wall_sign(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn structure_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::structure_block(); + let structure_block_mode = map.get("mode")?; + let structure_block_mode = StructureBlockMode::from_str(structure_block_mode).ok()?; + block.set_structure_block_mode(structure_block_mode); + Some(block) + } + fn jigsaw_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::jigsaw(); + let orientation = map.get("orientation")?; + let orientation = Orientation::from_str(orientation).ok()?; + block.set_orientation(orientation); + Some(block) + } + fn composter_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::composter(); + let level_0_8 = map.get("level")?; + let level_0_8 = { + let x = i32::from_str(level_0_8).ok()?; + if !(0i32..=8i32).contains(&x) { + return None; + } + x + }; + block.set_level_0_8(level_0_8); + Some(block) + } + fn target_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::target(); + let power = map.get("power")?; + let power = { + let x = i32::from_str(power).ok()?; + if !(0i32..=15i32).contains(&x) { + return None; + } + x + }; + block.set_power(power); + Some(block) + } + fn bee_nest_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::bee_nest(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let honey_level = map.get("honey_level")?; + let honey_level = { + let x = i32::from_str(honey_level).ok()?; + if !(0i32..=5i32).contains(&x) { + return None; + } + x + }; + block.set_honey_level(honey_level); + Some(block) + } + fn beehive_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::beehive(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let honey_level = map.get("honey_level")?; + let honey_level = { + let x = i32::from_str(honey_level).ok()?; + if !(0i32..=5i32).contains(&x) { + return None; + } + x + }; + block.set_honey_level(honey_level); + Some(block) + } + fn honey_block_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::honey_block(); + Some(block) + } + fn honeycomb_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::honeycomb_block(); + Some(block) + } + fn netherite_block_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::netherite_block(); + Some(block) + } + fn ancient_debris_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::ancient_debris(); + Some(block) + } + fn crying_obsidian_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::crying_obsidian(); + Some(block) + } + fn respawn_anchor_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::respawn_anchor(); + let charges = map.get("charges")?; + let charges = { + let x = i32::from_str(charges).ok()?; + if !(0i32..=4i32).contains(&x) { + return None; + } + x + }; + block.set_charges(charges); + Some(block) + } + fn potted_crimson_fungus_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_crimson_fungus(); + Some(block) + } + fn potted_warped_fungus_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_warped_fungus(); + Some(block) + } + fn potted_crimson_roots_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_crimson_roots(); + Some(block) + } + fn potted_warped_roots_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::potted_warped_roots(); + Some(block) + } + fn lodestone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::lodestone(); + Some(block) + } + fn blackstone_from_identifier_and_properties(map: &BTreeMap) -> Option { + let mut block = BlockId::blackstone(); + Some(block) + } + fn blackstone_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blackstone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn blackstone_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blackstone_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn blackstone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::blackstone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_blackstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone(); + Some(block) + } + fn polished_blackstone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_bricks(); + Some(block) + } + fn cracked_polished_blackstone_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cracked_polished_blackstone_bricks(); + Some(block) + } + fn chiseled_polished_blackstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chiseled_polished_blackstone(); + Some(block) + } + fn polished_blackstone_brick_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_brick_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_blackstone_brick_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_brick_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_blackstone_brick_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_brick_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn gilded_blackstone_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::gilded_blackstone(); + Some(block) + } + fn polished_blackstone_stairs_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_stairs(); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let half_top_bottom = map.get("half")?; + let half_top_bottom = HalfTopBottom::from_str(half_top_bottom).ok()?; + block.set_half_top_bottom(half_top_bottom); + let stairs_shape = map.get("shape")?; + let stairs_shape = StairsShape::from_str(stairs_shape).ok()?; + block.set_stairs_shape(stairs_shape); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_blackstone_slab_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_slab(); + let slab_kind = map.get("type")?; + let slab_kind = SlabKind::from_str(slab_kind).ok()?; + block.set_slab_kind(slab_kind); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + Some(block) + } + fn polished_blackstone_pressure_plate_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_pressure_plate(); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn polished_blackstone_button_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_button(); + let face = map.get("face")?; + let face = Face::from_str(face).ok()?; + block.set_face(face); + let facing_cardinal = map.get("facing")?; + let facing_cardinal = FacingCardinal::from_str(facing_cardinal).ok()?; + block.set_facing_cardinal(facing_cardinal); + let powered = map.get("powered")?; + let powered = bool::from_str(powered).ok()?; + block.set_powered(powered); + Some(block) + } + fn polished_blackstone_wall_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::polished_blackstone_wall(); + let east_nlt = map.get("east")?; + let east_nlt = EastNlt::from_str(east_nlt).ok()?; + block.set_east_nlt(east_nlt); + let north_nlt = map.get("north")?; + let north_nlt = NorthNlt::from_str(north_nlt).ok()?; + block.set_north_nlt(north_nlt); + let south_nlt = map.get("south")?; + let south_nlt = SouthNlt::from_str(south_nlt).ok()?; + block.set_south_nlt(south_nlt); + let up = map.get("up")?; + let up = bool::from_str(up).ok()?; + block.set_up(up); + let waterlogged = map.get("waterlogged")?; + let waterlogged = bool::from_str(waterlogged).ok()?; + block.set_waterlogged(waterlogged); + let west_nlt = map.get("west")?; + let west_nlt = WestNlt::from_str(west_nlt).ok()?; + block.set_west_nlt(west_nlt); + Some(block) + } + fn chiseled_nether_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::chiseled_nether_bricks(); + Some(block) + } + fn cracked_nether_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::cracked_nether_bricks(); + Some(block) + } + fn quartz_bricks_from_identifier_and_properties( + map: &BTreeMap, + ) -> Option { + let mut block = BlockId::quartz_bricks(); + Some(block) + } + #[doc = "Attempts to convert a block identifier to a block with default property values."] + pub fn from_identifier(identifier: &str) -> Option { + match identifier { + "minecraft:air" => Some(Self::air()), + "minecraft:stone" => Some(Self::stone()), + "minecraft:granite" => Some(Self::granite()), + "minecraft:polished_granite" => Some(Self::polished_granite()), + "minecraft:diorite" => Some(Self::diorite()), + "minecraft:polished_diorite" => Some(Self::polished_diorite()), + "minecraft:andesite" => Some(Self::andesite()), + "minecraft:polished_andesite" => Some(Self::polished_andesite()), + "minecraft:grass_block" => Some(Self::grass_block()), + "minecraft:dirt" => Some(Self::dirt()), + "minecraft:coarse_dirt" => Some(Self::coarse_dirt()), + "minecraft:podzol" => Some(Self::podzol()), + "minecraft:cobblestone" => Some(Self::cobblestone()), + "minecraft:oak_planks" => Some(Self::oak_planks()), + "minecraft:spruce_planks" => Some(Self::spruce_planks()), + "minecraft:birch_planks" => Some(Self::birch_planks()), + "minecraft:jungle_planks" => Some(Self::jungle_planks()), + "minecraft:acacia_planks" => Some(Self::acacia_planks()), + "minecraft:dark_oak_planks" => Some(Self::dark_oak_planks()), + "minecraft:oak_sapling" => Some(Self::oak_sapling()), + "minecraft:spruce_sapling" => Some(Self::spruce_sapling()), + "minecraft:birch_sapling" => Some(Self::birch_sapling()), + "minecraft:jungle_sapling" => Some(Self::jungle_sapling()), + "minecraft:acacia_sapling" => Some(Self::acacia_sapling()), + "minecraft:dark_oak_sapling" => Some(Self::dark_oak_sapling()), + "minecraft:bedrock" => Some(Self::bedrock()), + "minecraft:water" => Some(Self::water()), + "minecraft:lava" => Some(Self::lava()), + "minecraft:sand" => Some(Self::sand()), + "minecraft:red_sand" => Some(Self::red_sand()), + "minecraft:gravel" => Some(Self::gravel()), + "minecraft:gold_ore" => Some(Self::gold_ore()), + "minecraft:iron_ore" => Some(Self::iron_ore()), + "minecraft:coal_ore" => Some(Self::coal_ore()), + "minecraft:nether_gold_ore" => Some(Self::nether_gold_ore()), + "minecraft:oak_log" => Some(Self::oak_log()), + "minecraft:spruce_log" => Some(Self::spruce_log()), + "minecraft:birch_log" => Some(Self::birch_log()), + "minecraft:jungle_log" => Some(Self::jungle_log()), + "minecraft:acacia_log" => Some(Self::acacia_log()), + "minecraft:dark_oak_log" => Some(Self::dark_oak_log()), + "minecraft:stripped_spruce_log" => Some(Self::stripped_spruce_log()), + "minecraft:stripped_birch_log" => Some(Self::stripped_birch_log()), + "minecraft:stripped_jungle_log" => Some(Self::stripped_jungle_log()), + "minecraft:stripped_acacia_log" => Some(Self::stripped_acacia_log()), + "minecraft:stripped_dark_oak_log" => Some(Self::stripped_dark_oak_log()), + "minecraft:stripped_oak_log" => Some(Self::stripped_oak_log()), + "minecraft:oak_wood" => Some(Self::oak_wood()), + "minecraft:spruce_wood" => Some(Self::spruce_wood()), + "minecraft:birch_wood" => Some(Self::birch_wood()), + "minecraft:jungle_wood" => Some(Self::jungle_wood()), + "minecraft:acacia_wood" => Some(Self::acacia_wood()), + "minecraft:dark_oak_wood" => Some(Self::dark_oak_wood()), + "minecraft:stripped_oak_wood" => Some(Self::stripped_oak_wood()), + "minecraft:stripped_spruce_wood" => Some(Self::stripped_spruce_wood()), + "minecraft:stripped_birch_wood" => Some(Self::stripped_birch_wood()), + "minecraft:stripped_jungle_wood" => Some(Self::stripped_jungle_wood()), + "minecraft:stripped_acacia_wood" => Some(Self::stripped_acacia_wood()), + "minecraft:stripped_dark_oak_wood" => Some(Self::stripped_dark_oak_wood()), + "minecraft:oak_leaves" => Some(Self::oak_leaves()), + "minecraft:spruce_leaves" => Some(Self::spruce_leaves()), + "minecraft:birch_leaves" => Some(Self::birch_leaves()), + "minecraft:jungle_leaves" => Some(Self::jungle_leaves()), + "minecraft:acacia_leaves" => Some(Self::acacia_leaves()), + "minecraft:dark_oak_leaves" => Some(Self::dark_oak_leaves()), + "minecraft:sponge" => Some(Self::sponge()), + "minecraft:wet_sponge" => Some(Self::wet_sponge()), + "minecraft:glass" => Some(Self::glass()), + "minecraft:lapis_ore" => Some(Self::lapis_ore()), + "minecraft:lapis_block" => Some(Self::lapis_block()), + "minecraft:dispenser" => Some(Self::dispenser()), + "minecraft:sandstone" => Some(Self::sandstone()), + "minecraft:chiseled_sandstone" => Some(Self::chiseled_sandstone()), + "minecraft:cut_sandstone" => Some(Self::cut_sandstone()), + "minecraft:note_block" => Some(Self::note_block()), + "minecraft:white_bed" => Some(Self::white_bed()), + "minecraft:orange_bed" => Some(Self::orange_bed()), + "minecraft:magenta_bed" => Some(Self::magenta_bed()), + "minecraft:light_blue_bed" => Some(Self::light_blue_bed()), + "minecraft:yellow_bed" => Some(Self::yellow_bed()), + "minecraft:lime_bed" => Some(Self::lime_bed()), + "minecraft:pink_bed" => Some(Self::pink_bed()), + "minecraft:gray_bed" => Some(Self::gray_bed()), + "minecraft:light_gray_bed" => Some(Self::light_gray_bed()), + "minecraft:cyan_bed" => Some(Self::cyan_bed()), + "minecraft:purple_bed" => Some(Self::purple_bed()), + "minecraft:blue_bed" => Some(Self::blue_bed()), + "minecraft:brown_bed" => Some(Self::brown_bed()), + "minecraft:green_bed" => Some(Self::green_bed()), + "minecraft:red_bed" => Some(Self::red_bed()), + "minecraft:black_bed" => Some(Self::black_bed()), + "minecraft:powered_rail" => Some(Self::powered_rail()), + "minecraft:detector_rail" => Some(Self::detector_rail()), + "minecraft:sticky_piston" => Some(Self::sticky_piston()), + "minecraft:cobweb" => Some(Self::cobweb()), + "minecraft:grass" => Some(Self::grass()), + "minecraft:fern" => Some(Self::fern()), + "minecraft:dead_bush" => Some(Self::dead_bush()), + "minecraft:seagrass" => Some(Self::seagrass()), + "minecraft:tall_seagrass" => Some(Self::tall_seagrass()), + "minecraft:piston" => Some(Self::piston()), + "minecraft:piston_head" => Some(Self::piston_head()), + "minecraft:white_wool" => Some(Self::white_wool()), + "minecraft:orange_wool" => Some(Self::orange_wool()), + "minecraft:magenta_wool" => Some(Self::magenta_wool()), + "minecraft:light_blue_wool" => Some(Self::light_blue_wool()), + "minecraft:yellow_wool" => Some(Self::yellow_wool()), + "minecraft:lime_wool" => Some(Self::lime_wool()), + "minecraft:pink_wool" => Some(Self::pink_wool()), + "minecraft:gray_wool" => Some(Self::gray_wool()), + "minecraft:light_gray_wool" => Some(Self::light_gray_wool()), + "minecraft:cyan_wool" => Some(Self::cyan_wool()), + "minecraft:purple_wool" => Some(Self::purple_wool()), + "minecraft:blue_wool" => Some(Self::blue_wool()), + "minecraft:brown_wool" => Some(Self::brown_wool()), + "minecraft:green_wool" => Some(Self::green_wool()), + "minecraft:red_wool" => Some(Self::red_wool()), + "minecraft:black_wool" => Some(Self::black_wool()), + "minecraft:moving_piston" => Some(Self::moving_piston()), + "minecraft:dandelion" => Some(Self::dandelion()), + "minecraft:poppy" => Some(Self::poppy()), + "minecraft:blue_orchid" => Some(Self::blue_orchid()), + "minecraft:allium" => Some(Self::allium()), + "minecraft:azure_bluet" => Some(Self::azure_bluet()), + "minecraft:red_tulip" => Some(Self::red_tulip()), + "minecraft:orange_tulip" => Some(Self::orange_tulip()), + "minecraft:white_tulip" => Some(Self::white_tulip()), + "minecraft:pink_tulip" => Some(Self::pink_tulip()), + "minecraft:oxeye_daisy" => Some(Self::oxeye_daisy()), + "minecraft:cornflower" => Some(Self::cornflower()), + "minecraft:wither_rose" => Some(Self::wither_rose()), + "minecraft:lily_of_the_valley" => Some(Self::lily_of_the_valley()), + "minecraft:brown_mushroom" => Some(Self::brown_mushroom()), + "minecraft:red_mushroom" => Some(Self::red_mushroom()), + "minecraft:gold_block" => Some(Self::gold_block()), + "minecraft:iron_block" => Some(Self::iron_block()), + "minecraft:bricks" => Some(Self::bricks()), + "minecraft:tnt" => Some(Self::tnt()), + "minecraft:bookshelf" => Some(Self::bookshelf()), + "minecraft:mossy_cobblestone" => Some(Self::mossy_cobblestone()), + "minecraft:obsidian" => Some(Self::obsidian()), + "minecraft:torch" => Some(Self::torch()), + "minecraft:wall_torch" => Some(Self::wall_torch()), + "minecraft:fire" => Some(Self::fire()), + "minecraft:soul_fire" => Some(Self::soul_fire()), + "minecraft:spawner" => Some(Self::spawner()), + "minecraft:oak_stairs" => Some(Self::oak_stairs()), + "minecraft:chest" => Some(Self::chest()), + "minecraft:redstone_wire" => Some(Self::redstone_wire()), + "minecraft:diamond_ore" => Some(Self::diamond_ore()), + "minecraft:diamond_block" => Some(Self::diamond_block()), + "minecraft:crafting_table" => Some(Self::crafting_table()), + "minecraft:wheat" => Some(Self::wheat()), + "minecraft:farmland" => Some(Self::farmland()), + "minecraft:furnace" => Some(Self::furnace()), + "minecraft:oak_sign" => Some(Self::oak_sign()), + "minecraft:spruce_sign" => Some(Self::spruce_sign()), + "minecraft:birch_sign" => Some(Self::birch_sign()), + "minecraft:acacia_sign" => Some(Self::acacia_sign()), + "minecraft:jungle_sign" => Some(Self::jungle_sign()), + "minecraft:dark_oak_sign" => Some(Self::dark_oak_sign()), + "minecraft:oak_door" => Some(Self::oak_door()), + "minecraft:ladder" => Some(Self::ladder()), + "minecraft:rail" => Some(Self::rail()), + "minecraft:cobblestone_stairs" => Some(Self::cobblestone_stairs()), + "minecraft:oak_wall_sign" => Some(Self::oak_wall_sign()), + "minecraft:spruce_wall_sign" => Some(Self::spruce_wall_sign()), + "minecraft:birch_wall_sign" => Some(Self::birch_wall_sign()), + "minecraft:acacia_wall_sign" => Some(Self::acacia_wall_sign()), + "minecraft:jungle_wall_sign" => Some(Self::jungle_wall_sign()), + "minecraft:dark_oak_wall_sign" => Some(Self::dark_oak_wall_sign()), + "minecraft:lever" => Some(Self::lever()), + "minecraft:stone_pressure_plate" => Some(Self::stone_pressure_plate()), + "minecraft:iron_door" => Some(Self::iron_door()), + "minecraft:oak_pressure_plate" => Some(Self::oak_pressure_plate()), + "minecraft:spruce_pressure_plate" => Some(Self::spruce_pressure_plate()), + "minecraft:birch_pressure_plate" => Some(Self::birch_pressure_plate()), + "minecraft:jungle_pressure_plate" => Some(Self::jungle_pressure_plate()), + "minecraft:acacia_pressure_plate" => Some(Self::acacia_pressure_plate()), + "minecraft:dark_oak_pressure_plate" => Some(Self::dark_oak_pressure_plate()), + "minecraft:redstone_ore" => Some(Self::redstone_ore()), + "minecraft:redstone_torch" => Some(Self::redstone_torch()), + "minecraft:redstone_wall_torch" => Some(Self::redstone_wall_torch()), + "minecraft:stone_button" => Some(Self::stone_button()), + "minecraft:snow" => Some(Self::snow()), + "minecraft:ice" => Some(Self::ice()), + "minecraft:snow_block" => Some(Self::snow_block()), + "minecraft:cactus" => Some(Self::cactus()), + "minecraft:clay" => Some(Self::clay()), + "minecraft:sugar_cane" => Some(Self::sugar_cane()), + "minecraft:jukebox" => Some(Self::jukebox()), + "minecraft:oak_fence" => Some(Self::oak_fence()), + "minecraft:pumpkin" => Some(Self::pumpkin()), + "minecraft:netherrack" => Some(Self::netherrack()), + "minecraft:soul_sand" => Some(Self::soul_sand()), + "minecraft:soul_soil" => Some(Self::soul_soil()), + "minecraft:basalt" => Some(Self::basalt()), + "minecraft:polished_basalt" => Some(Self::polished_basalt()), + "minecraft:soul_torch" => Some(Self::soul_torch()), + "minecraft:soul_wall_torch" => Some(Self::soul_wall_torch()), + "minecraft:glowstone" => Some(Self::glowstone()), + "minecraft:nether_portal" => Some(Self::nether_portal()), + "minecraft:carved_pumpkin" => Some(Self::carved_pumpkin()), + "minecraft:jack_o_lantern" => Some(Self::jack_o_lantern()), + "minecraft:cake" => Some(Self::cake()), + "minecraft:repeater" => Some(Self::repeater()), + "minecraft:white_stained_glass" => Some(Self::white_stained_glass()), + "minecraft:orange_stained_glass" => Some(Self::orange_stained_glass()), + "minecraft:magenta_stained_glass" => Some(Self::magenta_stained_glass()), + "minecraft:light_blue_stained_glass" => Some(Self::light_blue_stained_glass()), + "minecraft:yellow_stained_glass" => Some(Self::yellow_stained_glass()), + "minecraft:lime_stained_glass" => Some(Self::lime_stained_glass()), + "minecraft:pink_stained_glass" => Some(Self::pink_stained_glass()), + "minecraft:gray_stained_glass" => Some(Self::gray_stained_glass()), + "minecraft:light_gray_stained_glass" => Some(Self::light_gray_stained_glass()), + "minecraft:cyan_stained_glass" => Some(Self::cyan_stained_glass()), + "minecraft:purple_stained_glass" => Some(Self::purple_stained_glass()), + "minecraft:blue_stained_glass" => Some(Self::blue_stained_glass()), + "minecraft:brown_stained_glass" => Some(Self::brown_stained_glass()), + "minecraft:green_stained_glass" => Some(Self::green_stained_glass()), + "minecraft:red_stained_glass" => Some(Self::red_stained_glass()), + "minecraft:black_stained_glass" => Some(Self::black_stained_glass()), + "minecraft:oak_trapdoor" => Some(Self::oak_trapdoor()), + "minecraft:spruce_trapdoor" => Some(Self::spruce_trapdoor()), + "minecraft:birch_trapdoor" => Some(Self::birch_trapdoor()), + "minecraft:jungle_trapdoor" => Some(Self::jungle_trapdoor()), + "minecraft:acacia_trapdoor" => Some(Self::acacia_trapdoor()), + "minecraft:dark_oak_trapdoor" => Some(Self::dark_oak_trapdoor()), + "minecraft:stone_bricks" => Some(Self::stone_bricks()), + "minecraft:mossy_stone_bricks" => Some(Self::mossy_stone_bricks()), + "minecraft:cracked_stone_bricks" => Some(Self::cracked_stone_bricks()), + "minecraft:chiseled_stone_bricks" => Some(Self::chiseled_stone_bricks()), + "minecraft:infested_stone" => Some(Self::infested_stone()), + "minecraft:infested_cobblestone" => Some(Self::infested_cobblestone()), + "minecraft:infested_stone_bricks" => Some(Self::infested_stone_bricks()), + "minecraft:infested_mossy_stone_bricks" => Some(Self::infested_mossy_stone_bricks()), + "minecraft:infested_cracked_stone_bricks" => { + Some(Self::infested_cracked_stone_bricks()) + } + "minecraft:infested_chiseled_stone_bricks" => { + Some(Self::infested_chiseled_stone_bricks()) + } + "minecraft:brown_mushroom_block" => Some(Self::brown_mushroom_block()), + "minecraft:red_mushroom_block" => Some(Self::red_mushroom_block()), + "minecraft:mushroom_stem" => Some(Self::mushroom_stem()), + "minecraft:iron_bars" => Some(Self::iron_bars()), + "minecraft:chain" => Some(Self::chain()), + "minecraft:glass_pane" => Some(Self::glass_pane()), + "minecraft:melon" => Some(Self::melon()), + "minecraft:attached_pumpkin_stem" => Some(Self::attached_pumpkin_stem()), + "minecraft:attached_melon_stem" => Some(Self::attached_melon_stem()), + "minecraft:pumpkin_stem" => Some(Self::pumpkin_stem()), + "minecraft:melon_stem" => Some(Self::melon_stem()), + "minecraft:vine" => Some(Self::vine()), + "minecraft:oak_fence_gate" => Some(Self::oak_fence_gate()), + "minecraft:brick_stairs" => Some(Self::brick_stairs()), + "minecraft:stone_brick_stairs" => Some(Self::stone_brick_stairs()), + "minecraft:mycelium" => Some(Self::mycelium()), + "minecraft:lily_pad" => Some(Self::lily_pad()), + "minecraft:nether_bricks" => Some(Self::nether_bricks()), + "minecraft:nether_brick_fence" => Some(Self::nether_brick_fence()), + "minecraft:nether_brick_stairs" => Some(Self::nether_brick_stairs()), + "minecraft:nether_wart" => Some(Self::nether_wart()), + "minecraft:enchanting_table" => Some(Self::enchanting_table()), + "minecraft:brewing_stand" => Some(Self::brewing_stand()), + "minecraft:cauldron" => Some(Self::cauldron()), + "minecraft:end_portal" => Some(Self::end_portal()), + "minecraft:end_portal_frame" => Some(Self::end_portal_frame()), + "minecraft:end_stone" => Some(Self::end_stone()), + "minecraft:dragon_egg" => Some(Self::dragon_egg()), + "minecraft:redstone_lamp" => Some(Self::redstone_lamp()), + "minecraft:cocoa" => Some(Self::cocoa()), + "minecraft:sandstone_stairs" => Some(Self::sandstone_stairs()), + "minecraft:emerald_ore" => Some(Self::emerald_ore()), + "minecraft:ender_chest" => Some(Self::ender_chest()), + "minecraft:tripwire_hook" => Some(Self::tripwire_hook()), + "minecraft:tripwire" => Some(Self::tripwire()), + "minecraft:emerald_block" => Some(Self::emerald_block()), + "minecraft:spruce_stairs" => Some(Self::spruce_stairs()), + "minecraft:birch_stairs" => Some(Self::birch_stairs()), + "minecraft:jungle_stairs" => Some(Self::jungle_stairs()), + "minecraft:command_block" => Some(Self::command_block()), + "minecraft:beacon" => Some(Self::beacon()), + "minecraft:cobblestone_wall" => Some(Self::cobblestone_wall()), + "minecraft:mossy_cobblestone_wall" => Some(Self::mossy_cobblestone_wall()), + "minecraft:flower_pot" => Some(Self::flower_pot()), + "minecraft:potted_oak_sapling" => Some(Self::potted_oak_sapling()), + "minecraft:potted_spruce_sapling" => Some(Self::potted_spruce_sapling()), + "minecraft:potted_birch_sapling" => Some(Self::potted_birch_sapling()), + "minecraft:potted_jungle_sapling" => Some(Self::potted_jungle_sapling()), + "minecraft:potted_acacia_sapling" => Some(Self::potted_acacia_sapling()), + "minecraft:potted_dark_oak_sapling" => Some(Self::potted_dark_oak_sapling()), + "minecraft:potted_fern" => Some(Self::potted_fern()), + "minecraft:potted_dandelion" => Some(Self::potted_dandelion()), + "minecraft:potted_poppy" => Some(Self::potted_poppy()), + "minecraft:potted_blue_orchid" => Some(Self::potted_blue_orchid()), + "minecraft:potted_allium" => Some(Self::potted_allium()), + "minecraft:potted_azure_bluet" => Some(Self::potted_azure_bluet()), + "minecraft:potted_red_tulip" => Some(Self::potted_red_tulip()), + "minecraft:potted_orange_tulip" => Some(Self::potted_orange_tulip()), + "minecraft:potted_white_tulip" => Some(Self::potted_white_tulip()), + "minecraft:potted_pink_tulip" => Some(Self::potted_pink_tulip()), + "minecraft:potted_oxeye_daisy" => Some(Self::potted_oxeye_daisy()), + "minecraft:potted_cornflower" => Some(Self::potted_cornflower()), + "minecraft:potted_lily_of_the_valley" => Some(Self::potted_lily_of_the_valley()), + "minecraft:potted_wither_rose" => Some(Self::potted_wither_rose()), + "minecraft:potted_red_mushroom" => Some(Self::potted_red_mushroom()), + "minecraft:potted_brown_mushroom" => Some(Self::potted_brown_mushroom()), + "minecraft:potted_dead_bush" => Some(Self::potted_dead_bush()), + "minecraft:potted_cactus" => Some(Self::potted_cactus()), + "minecraft:carrots" => Some(Self::carrots()), + "minecraft:potatoes" => Some(Self::potatoes()), + "minecraft:oak_button" => Some(Self::oak_button()), + "minecraft:spruce_button" => Some(Self::spruce_button()), + "minecraft:birch_button" => Some(Self::birch_button()), + "minecraft:jungle_button" => Some(Self::jungle_button()), + "minecraft:acacia_button" => Some(Self::acacia_button()), + "minecraft:dark_oak_button" => Some(Self::dark_oak_button()), + "minecraft:skeleton_skull" => Some(Self::skeleton_skull()), + "minecraft:skeleton_wall_skull" => Some(Self::skeleton_wall_skull()), + "minecraft:wither_skeleton_skull" => Some(Self::wither_skeleton_skull()), + "minecraft:wither_skeleton_wall_skull" => Some(Self::wither_skeleton_wall_skull()), + "minecraft:zombie_head" => Some(Self::zombie_head()), + "minecraft:zombie_wall_head" => Some(Self::zombie_wall_head()), + "minecraft:player_head" => Some(Self::player_head()), + "minecraft:player_wall_head" => Some(Self::player_wall_head()), + "minecraft:creeper_head" => Some(Self::creeper_head()), + "minecraft:creeper_wall_head" => Some(Self::creeper_wall_head()), + "minecraft:dragon_head" => Some(Self::dragon_head()), + "minecraft:dragon_wall_head" => Some(Self::dragon_wall_head()), + "minecraft:anvil" => Some(Self::anvil()), + "minecraft:chipped_anvil" => Some(Self::chipped_anvil()), + "minecraft:damaged_anvil" => Some(Self::damaged_anvil()), + "minecraft:trapped_chest" => Some(Self::trapped_chest()), + "minecraft:light_weighted_pressure_plate" => { + Some(Self::light_weighted_pressure_plate()) + } + "minecraft:heavy_weighted_pressure_plate" => { + Some(Self::heavy_weighted_pressure_plate()) + } + "minecraft:comparator" => Some(Self::comparator()), + "minecraft:daylight_detector" => Some(Self::daylight_detector()), + "minecraft:redstone_block" => Some(Self::redstone_block()), + "minecraft:nether_quartz_ore" => Some(Self::nether_quartz_ore()), + "minecraft:hopper" => Some(Self::hopper()), + "minecraft:quartz_block" => Some(Self::quartz_block()), + "minecraft:chiseled_quartz_block" => Some(Self::chiseled_quartz_block()), + "minecraft:quartz_pillar" => Some(Self::quartz_pillar()), + "minecraft:quartz_stairs" => Some(Self::quartz_stairs()), + "minecraft:activator_rail" => Some(Self::activator_rail()), + "minecraft:dropper" => Some(Self::dropper()), + "minecraft:white_terracotta" => Some(Self::white_terracotta()), + "minecraft:orange_terracotta" => Some(Self::orange_terracotta()), + "minecraft:magenta_terracotta" => Some(Self::magenta_terracotta()), + "minecraft:light_blue_terracotta" => Some(Self::light_blue_terracotta()), + "minecraft:yellow_terracotta" => Some(Self::yellow_terracotta()), + "minecraft:lime_terracotta" => Some(Self::lime_terracotta()), + "minecraft:pink_terracotta" => Some(Self::pink_terracotta()), + "minecraft:gray_terracotta" => Some(Self::gray_terracotta()), + "minecraft:light_gray_terracotta" => Some(Self::light_gray_terracotta()), + "minecraft:cyan_terracotta" => Some(Self::cyan_terracotta()), + "minecraft:purple_terracotta" => Some(Self::purple_terracotta()), + "minecraft:blue_terracotta" => Some(Self::blue_terracotta()), + "minecraft:brown_terracotta" => Some(Self::brown_terracotta()), + "minecraft:green_terracotta" => Some(Self::green_terracotta()), + "minecraft:red_terracotta" => Some(Self::red_terracotta()), + "minecraft:black_terracotta" => Some(Self::black_terracotta()), + "minecraft:white_stained_glass_pane" => Some(Self::white_stained_glass_pane()), + "minecraft:orange_stained_glass_pane" => Some(Self::orange_stained_glass_pane()), + "minecraft:magenta_stained_glass_pane" => Some(Self::magenta_stained_glass_pane()), + "minecraft:light_blue_stained_glass_pane" => { + Some(Self::light_blue_stained_glass_pane()) + } + "minecraft:yellow_stained_glass_pane" => Some(Self::yellow_stained_glass_pane()), + "minecraft:lime_stained_glass_pane" => Some(Self::lime_stained_glass_pane()), + "minecraft:pink_stained_glass_pane" => Some(Self::pink_stained_glass_pane()), + "minecraft:gray_stained_glass_pane" => Some(Self::gray_stained_glass_pane()), + "minecraft:light_gray_stained_glass_pane" => { + Some(Self::light_gray_stained_glass_pane()) + } + "minecraft:cyan_stained_glass_pane" => Some(Self::cyan_stained_glass_pane()), + "minecraft:purple_stained_glass_pane" => Some(Self::purple_stained_glass_pane()), + "minecraft:blue_stained_glass_pane" => Some(Self::blue_stained_glass_pane()), + "minecraft:brown_stained_glass_pane" => Some(Self::brown_stained_glass_pane()), + "minecraft:green_stained_glass_pane" => Some(Self::green_stained_glass_pane()), + "minecraft:red_stained_glass_pane" => Some(Self::red_stained_glass_pane()), + "minecraft:black_stained_glass_pane" => Some(Self::black_stained_glass_pane()), + "minecraft:acacia_stairs" => Some(Self::acacia_stairs()), + "minecraft:dark_oak_stairs" => Some(Self::dark_oak_stairs()), + "minecraft:slime_block" => Some(Self::slime_block()), + "minecraft:barrier" => Some(Self::barrier()), + "minecraft:iron_trapdoor" => Some(Self::iron_trapdoor()), + "minecraft:prismarine" => Some(Self::prismarine()), + "minecraft:prismarine_bricks" => Some(Self::prismarine_bricks()), + "minecraft:dark_prismarine" => Some(Self::dark_prismarine()), + "minecraft:prismarine_stairs" => Some(Self::prismarine_stairs()), + "minecraft:prismarine_brick_stairs" => Some(Self::prismarine_brick_stairs()), + "minecraft:dark_prismarine_stairs" => Some(Self::dark_prismarine_stairs()), + "minecraft:prismarine_slab" => Some(Self::prismarine_slab()), + "minecraft:prismarine_brick_slab" => Some(Self::prismarine_brick_slab()), + "minecraft:dark_prismarine_slab" => Some(Self::dark_prismarine_slab()), + "minecraft:sea_lantern" => Some(Self::sea_lantern()), + "minecraft:hay_block" => Some(Self::hay_block()), + "minecraft:white_carpet" => Some(Self::white_carpet()), + "minecraft:orange_carpet" => Some(Self::orange_carpet()), + "minecraft:magenta_carpet" => Some(Self::magenta_carpet()), + "minecraft:light_blue_carpet" => Some(Self::light_blue_carpet()), + "minecraft:yellow_carpet" => Some(Self::yellow_carpet()), + "minecraft:lime_carpet" => Some(Self::lime_carpet()), + "minecraft:pink_carpet" => Some(Self::pink_carpet()), + "minecraft:gray_carpet" => Some(Self::gray_carpet()), + "minecraft:light_gray_carpet" => Some(Self::light_gray_carpet()), + "minecraft:cyan_carpet" => Some(Self::cyan_carpet()), + "minecraft:purple_carpet" => Some(Self::purple_carpet()), + "minecraft:blue_carpet" => Some(Self::blue_carpet()), + "minecraft:brown_carpet" => Some(Self::brown_carpet()), + "minecraft:green_carpet" => Some(Self::green_carpet()), + "minecraft:red_carpet" => Some(Self::red_carpet()), + "minecraft:black_carpet" => Some(Self::black_carpet()), + "minecraft:terracotta" => Some(Self::terracotta()), + "minecraft:coal_block" => Some(Self::coal_block()), + "minecraft:packed_ice" => Some(Self::packed_ice()), + "minecraft:sunflower" => Some(Self::sunflower()), + "minecraft:lilac" => Some(Self::lilac()), + "minecraft:rose_bush" => Some(Self::rose_bush()), + "minecraft:peony" => Some(Self::peony()), + "minecraft:tall_grass" => Some(Self::tall_grass()), + "minecraft:large_fern" => Some(Self::large_fern()), + "minecraft:white_banner" => Some(Self::white_banner()), + "minecraft:orange_banner" => Some(Self::orange_banner()), + "minecraft:magenta_banner" => Some(Self::magenta_banner()), + "minecraft:light_blue_banner" => Some(Self::light_blue_banner()), + "minecraft:yellow_banner" => Some(Self::yellow_banner()), + "minecraft:lime_banner" => Some(Self::lime_banner()), + "minecraft:pink_banner" => Some(Self::pink_banner()), + "minecraft:gray_banner" => Some(Self::gray_banner()), + "minecraft:light_gray_banner" => Some(Self::light_gray_banner()), + "minecraft:cyan_banner" => Some(Self::cyan_banner()), + "minecraft:purple_banner" => Some(Self::purple_banner()), + "minecraft:blue_banner" => Some(Self::blue_banner()), + "minecraft:brown_banner" => Some(Self::brown_banner()), + "minecraft:green_banner" => Some(Self::green_banner()), + "minecraft:red_banner" => Some(Self::red_banner()), + "minecraft:black_banner" => Some(Self::black_banner()), + "minecraft:white_wall_banner" => Some(Self::white_wall_banner()), + "minecraft:orange_wall_banner" => Some(Self::orange_wall_banner()), + "minecraft:magenta_wall_banner" => Some(Self::magenta_wall_banner()), + "minecraft:light_blue_wall_banner" => Some(Self::light_blue_wall_banner()), + "minecraft:yellow_wall_banner" => Some(Self::yellow_wall_banner()), + "minecraft:lime_wall_banner" => Some(Self::lime_wall_banner()), + "minecraft:pink_wall_banner" => Some(Self::pink_wall_banner()), + "minecraft:gray_wall_banner" => Some(Self::gray_wall_banner()), + "minecraft:light_gray_wall_banner" => Some(Self::light_gray_wall_banner()), + "minecraft:cyan_wall_banner" => Some(Self::cyan_wall_banner()), + "minecraft:purple_wall_banner" => Some(Self::purple_wall_banner()), + "minecraft:blue_wall_banner" => Some(Self::blue_wall_banner()), + "minecraft:brown_wall_banner" => Some(Self::brown_wall_banner()), + "minecraft:green_wall_banner" => Some(Self::green_wall_banner()), + "minecraft:red_wall_banner" => Some(Self::red_wall_banner()), + "minecraft:black_wall_banner" => Some(Self::black_wall_banner()), + "minecraft:red_sandstone" => Some(Self::red_sandstone()), + "minecraft:chiseled_red_sandstone" => Some(Self::chiseled_red_sandstone()), + "minecraft:cut_red_sandstone" => Some(Self::cut_red_sandstone()), + "minecraft:red_sandstone_stairs" => Some(Self::red_sandstone_stairs()), + "minecraft:oak_slab" => Some(Self::oak_slab()), + "minecraft:spruce_slab" => Some(Self::spruce_slab()), + "minecraft:birch_slab" => Some(Self::birch_slab()), + "minecraft:jungle_slab" => Some(Self::jungle_slab()), + "minecraft:acacia_slab" => Some(Self::acacia_slab()), + "minecraft:dark_oak_slab" => Some(Self::dark_oak_slab()), + "minecraft:stone_slab" => Some(Self::stone_slab()), + "minecraft:smooth_stone_slab" => Some(Self::smooth_stone_slab()), + "minecraft:sandstone_slab" => Some(Self::sandstone_slab()), + "minecraft:cut_sandstone_slab" => Some(Self::cut_sandstone_slab()), + "minecraft:petrified_oak_slab" => Some(Self::petrified_oak_slab()), + "minecraft:cobblestone_slab" => Some(Self::cobblestone_slab()), + "minecraft:brick_slab" => Some(Self::brick_slab()), + "minecraft:stone_brick_slab" => Some(Self::stone_brick_slab()), + "minecraft:nether_brick_slab" => Some(Self::nether_brick_slab()), + "minecraft:quartz_slab" => Some(Self::quartz_slab()), + "minecraft:red_sandstone_slab" => Some(Self::red_sandstone_slab()), + "minecraft:cut_red_sandstone_slab" => Some(Self::cut_red_sandstone_slab()), + "minecraft:purpur_slab" => Some(Self::purpur_slab()), + "minecraft:smooth_stone" => Some(Self::smooth_stone()), + "minecraft:smooth_sandstone" => Some(Self::smooth_sandstone()), + "minecraft:smooth_quartz" => Some(Self::smooth_quartz()), + "minecraft:smooth_red_sandstone" => Some(Self::smooth_red_sandstone()), + "minecraft:spruce_fence_gate" => Some(Self::spruce_fence_gate()), + "minecraft:birch_fence_gate" => Some(Self::birch_fence_gate()), + "minecraft:jungle_fence_gate" => Some(Self::jungle_fence_gate()), + "minecraft:acacia_fence_gate" => Some(Self::acacia_fence_gate()), + "minecraft:dark_oak_fence_gate" => Some(Self::dark_oak_fence_gate()), + "minecraft:spruce_fence" => Some(Self::spruce_fence()), + "minecraft:birch_fence" => Some(Self::birch_fence()), + "minecraft:jungle_fence" => Some(Self::jungle_fence()), + "minecraft:acacia_fence" => Some(Self::acacia_fence()), + "minecraft:dark_oak_fence" => Some(Self::dark_oak_fence()), + "minecraft:spruce_door" => Some(Self::spruce_door()), + "minecraft:birch_door" => Some(Self::birch_door()), + "minecraft:jungle_door" => Some(Self::jungle_door()), + "minecraft:acacia_door" => Some(Self::acacia_door()), + "minecraft:dark_oak_door" => Some(Self::dark_oak_door()), + "minecraft:end_rod" => Some(Self::end_rod()), + "minecraft:chorus_plant" => Some(Self::chorus_plant()), + "minecraft:chorus_flower" => Some(Self::chorus_flower()), + "minecraft:purpur_block" => Some(Self::purpur_block()), + "minecraft:purpur_pillar" => Some(Self::purpur_pillar()), + "minecraft:purpur_stairs" => Some(Self::purpur_stairs()), + "minecraft:end_stone_bricks" => Some(Self::end_stone_bricks()), + "minecraft:beetroots" => Some(Self::beetroots()), + "minecraft:grass_path" => Some(Self::grass_path()), + "minecraft:end_gateway" => Some(Self::end_gateway()), + "minecraft:repeating_command_block" => Some(Self::repeating_command_block()), + "minecraft:chain_command_block" => Some(Self::chain_command_block()), + "minecraft:frosted_ice" => Some(Self::frosted_ice()), + "minecraft:magma_block" => Some(Self::magma_block()), + "minecraft:nether_wart_block" => Some(Self::nether_wart_block()), + "minecraft:red_nether_bricks" => Some(Self::red_nether_bricks()), + "minecraft:bone_block" => Some(Self::bone_block()), + "minecraft:structure_void" => Some(Self::structure_void()), + "minecraft:observer" => Some(Self::observer()), + "minecraft:shulker_box" => Some(Self::shulker_box()), + "minecraft:white_shulker_box" => Some(Self::white_shulker_box()), + "minecraft:orange_shulker_box" => Some(Self::orange_shulker_box()), + "minecraft:magenta_shulker_box" => Some(Self::magenta_shulker_box()), + "minecraft:light_blue_shulker_box" => Some(Self::light_blue_shulker_box()), + "minecraft:yellow_shulker_box" => Some(Self::yellow_shulker_box()), + "minecraft:lime_shulker_box" => Some(Self::lime_shulker_box()), + "minecraft:pink_shulker_box" => Some(Self::pink_shulker_box()), + "minecraft:gray_shulker_box" => Some(Self::gray_shulker_box()), + "minecraft:light_gray_shulker_box" => Some(Self::light_gray_shulker_box()), + "minecraft:cyan_shulker_box" => Some(Self::cyan_shulker_box()), + "minecraft:purple_shulker_box" => Some(Self::purple_shulker_box()), + "minecraft:blue_shulker_box" => Some(Self::blue_shulker_box()), + "minecraft:brown_shulker_box" => Some(Self::brown_shulker_box()), + "minecraft:green_shulker_box" => Some(Self::green_shulker_box()), + "minecraft:red_shulker_box" => Some(Self::red_shulker_box()), + "minecraft:black_shulker_box" => Some(Self::black_shulker_box()), + "minecraft:white_glazed_terracotta" => Some(Self::white_glazed_terracotta()), + "minecraft:orange_glazed_terracotta" => Some(Self::orange_glazed_terracotta()), + "minecraft:magenta_glazed_terracotta" => Some(Self::magenta_glazed_terracotta()), + "minecraft:light_blue_glazed_terracotta" => Some(Self::light_blue_glazed_terracotta()), + "minecraft:yellow_glazed_terracotta" => Some(Self::yellow_glazed_terracotta()), + "minecraft:lime_glazed_terracotta" => Some(Self::lime_glazed_terracotta()), + "minecraft:pink_glazed_terracotta" => Some(Self::pink_glazed_terracotta()), + "minecraft:gray_glazed_terracotta" => Some(Self::gray_glazed_terracotta()), + "minecraft:light_gray_glazed_terracotta" => Some(Self::light_gray_glazed_terracotta()), + "minecraft:cyan_glazed_terracotta" => Some(Self::cyan_glazed_terracotta()), + "minecraft:purple_glazed_terracotta" => Some(Self::purple_glazed_terracotta()), + "minecraft:blue_glazed_terracotta" => Some(Self::blue_glazed_terracotta()), + "minecraft:brown_glazed_terracotta" => Some(Self::brown_glazed_terracotta()), + "minecraft:green_glazed_terracotta" => Some(Self::green_glazed_terracotta()), + "minecraft:red_glazed_terracotta" => Some(Self::red_glazed_terracotta()), + "minecraft:black_glazed_terracotta" => Some(Self::black_glazed_terracotta()), + "minecraft:white_concrete" => Some(Self::white_concrete()), + "minecraft:orange_concrete" => Some(Self::orange_concrete()), + "minecraft:magenta_concrete" => Some(Self::magenta_concrete()), + "minecraft:light_blue_concrete" => Some(Self::light_blue_concrete()), + "minecraft:yellow_concrete" => Some(Self::yellow_concrete()), + "minecraft:lime_concrete" => Some(Self::lime_concrete()), + "minecraft:pink_concrete" => Some(Self::pink_concrete()), + "minecraft:gray_concrete" => Some(Self::gray_concrete()), + "minecraft:light_gray_concrete" => Some(Self::light_gray_concrete()), + "minecraft:cyan_concrete" => Some(Self::cyan_concrete()), + "minecraft:purple_concrete" => Some(Self::purple_concrete()), + "minecraft:blue_concrete" => Some(Self::blue_concrete()), + "minecraft:brown_concrete" => Some(Self::brown_concrete()), + "minecraft:green_concrete" => Some(Self::green_concrete()), + "minecraft:red_concrete" => Some(Self::red_concrete()), + "minecraft:black_concrete" => Some(Self::black_concrete()), + "minecraft:white_concrete_powder" => Some(Self::white_concrete_powder()), + "minecraft:orange_concrete_powder" => Some(Self::orange_concrete_powder()), + "minecraft:magenta_concrete_powder" => Some(Self::magenta_concrete_powder()), + "minecraft:light_blue_concrete_powder" => Some(Self::light_blue_concrete_powder()), + "minecraft:yellow_concrete_powder" => Some(Self::yellow_concrete_powder()), + "minecraft:lime_concrete_powder" => Some(Self::lime_concrete_powder()), + "minecraft:pink_concrete_powder" => Some(Self::pink_concrete_powder()), + "minecraft:gray_concrete_powder" => Some(Self::gray_concrete_powder()), + "minecraft:light_gray_concrete_powder" => Some(Self::light_gray_concrete_powder()), + "minecraft:cyan_concrete_powder" => Some(Self::cyan_concrete_powder()), + "minecraft:purple_concrete_powder" => Some(Self::purple_concrete_powder()), + "minecraft:blue_concrete_powder" => Some(Self::blue_concrete_powder()), + "minecraft:brown_concrete_powder" => Some(Self::brown_concrete_powder()), + "minecraft:green_concrete_powder" => Some(Self::green_concrete_powder()), + "minecraft:red_concrete_powder" => Some(Self::red_concrete_powder()), + "minecraft:black_concrete_powder" => Some(Self::black_concrete_powder()), + "minecraft:kelp" => Some(Self::kelp()), + "minecraft:kelp_plant" => Some(Self::kelp_plant()), + "minecraft:dried_kelp_block" => Some(Self::dried_kelp_block()), + "minecraft:turtle_egg" => Some(Self::turtle_egg()), + "minecraft:dead_tube_coral_block" => Some(Self::dead_tube_coral_block()), + "minecraft:dead_brain_coral_block" => Some(Self::dead_brain_coral_block()), + "minecraft:dead_bubble_coral_block" => Some(Self::dead_bubble_coral_block()), + "minecraft:dead_fire_coral_block" => Some(Self::dead_fire_coral_block()), + "minecraft:dead_horn_coral_block" => Some(Self::dead_horn_coral_block()), + "minecraft:tube_coral_block" => Some(Self::tube_coral_block()), + "minecraft:brain_coral_block" => Some(Self::brain_coral_block()), + "minecraft:bubble_coral_block" => Some(Self::bubble_coral_block()), + "minecraft:fire_coral_block" => Some(Self::fire_coral_block()), + "minecraft:horn_coral_block" => Some(Self::horn_coral_block()), + "minecraft:dead_tube_coral" => Some(Self::dead_tube_coral()), + "minecraft:dead_brain_coral" => Some(Self::dead_brain_coral()), + "minecraft:dead_bubble_coral" => Some(Self::dead_bubble_coral()), + "minecraft:dead_fire_coral" => Some(Self::dead_fire_coral()), + "minecraft:dead_horn_coral" => Some(Self::dead_horn_coral()), + "minecraft:tube_coral" => Some(Self::tube_coral()), + "minecraft:brain_coral" => Some(Self::brain_coral()), + "minecraft:bubble_coral" => Some(Self::bubble_coral()), + "minecraft:fire_coral" => Some(Self::fire_coral()), + "minecraft:horn_coral" => Some(Self::horn_coral()), + "minecraft:dead_tube_coral_fan" => Some(Self::dead_tube_coral_fan()), + "minecraft:dead_brain_coral_fan" => Some(Self::dead_brain_coral_fan()), + "minecraft:dead_bubble_coral_fan" => Some(Self::dead_bubble_coral_fan()), + "minecraft:dead_fire_coral_fan" => Some(Self::dead_fire_coral_fan()), + "minecraft:dead_horn_coral_fan" => Some(Self::dead_horn_coral_fan()), + "minecraft:tube_coral_fan" => Some(Self::tube_coral_fan()), + "minecraft:brain_coral_fan" => Some(Self::brain_coral_fan()), + "minecraft:bubble_coral_fan" => Some(Self::bubble_coral_fan()), + "minecraft:fire_coral_fan" => Some(Self::fire_coral_fan()), + "minecraft:horn_coral_fan" => Some(Self::horn_coral_fan()), + "minecraft:dead_tube_coral_wall_fan" => Some(Self::dead_tube_coral_wall_fan()), + "minecraft:dead_brain_coral_wall_fan" => Some(Self::dead_brain_coral_wall_fan()), + "minecraft:dead_bubble_coral_wall_fan" => Some(Self::dead_bubble_coral_wall_fan()), + "minecraft:dead_fire_coral_wall_fan" => Some(Self::dead_fire_coral_wall_fan()), + "minecraft:dead_horn_coral_wall_fan" => Some(Self::dead_horn_coral_wall_fan()), + "minecraft:tube_coral_wall_fan" => Some(Self::tube_coral_wall_fan()), + "minecraft:brain_coral_wall_fan" => Some(Self::brain_coral_wall_fan()), + "minecraft:bubble_coral_wall_fan" => Some(Self::bubble_coral_wall_fan()), + "minecraft:fire_coral_wall_fan" => Some(Self::fire_coral_wall_fan()), + "minecraft:horn_coral_wall_fan" => Some(Self::horn_coral_wall_fan()), + "minecraft:sea_pickle" => Some(Self::sea_pickle()), + "minecraft:blue_ice" => Some(Self::blue_ice()), + "minecraft:conduit" => Some(Self::conduit()), + "minecraft:bamboo_sapling" => Some(Self::bamboo_sapling()), + "minecraft:bamboo" => Some(Self::bamboo()), + "minecraft:potted_bamboo" => Some(Self::potted_bamboo()), + "minecraft:void_air" => Some(Self::void_air()), + "minecraft:cave_air" => Some(Self::cave_air()), + "minecraft:bubble_column" => Some(Self::bubble_column()), + "minecraft:polished_granite_stairs" => Some(Self::polished_granite_stairs()), + "minecraft:smooth_red_sandstone_stairs" => Some(Self::smooth_red_sandstone_stairs()), + "minecraft:mossy_stone_brick_stairs" => Some(Self::mossy_stone_brick_stairs()), + "minecraft:polished_diorite_stairs" => Some(Self::polished_diorite_stairs()), + "minecraft:mossy_cobblestone_stairs" => Some(Self::mossy_cobblestone_stairs()), + "minecraft:end_stone_brick_stairs" => Some(Self::end_stone_brick_stairs()), + "minecraft:stone_stairs" => Some(Self::stone_stairs()), + "minecraft:smooth_sandstone_stairs" => Some(Self::smooth_sandstone_stairs()), + "minecraft:smooth_quartz_stairs" => Some(Self::smooth_quartz_stairs()), + "minecraft:granite_stairs" => Some(Self::granite_stairs()), + "minecraft:andesite_stairs" => Some(Self::andesite_stairs()), + "minecraft:red_nether_brick_stairs" => Some(Self::red_nether_brick_stairs()), + "minecraft:polished_andesite_stairs" => Some(Self::polished_andesite_stairs()), + "minecraft:diorite_stairs" => Some(Self::diorite_stairs()), + "minecraft:polished_granite_slab" => Some(Self::polished_granite_slab()), + "minecraft:smooth_red_sandstone_slab" => Some(Self::smooth_red_sandstone_slab()), + "minecraft:mossy_stone_brick_slab" => Some(Self::mossy_stone_brick_slab()), + "minecraft:polished_diorite_slab" => Some(Self::polished_diorite_slab()), + "minecraft:mossy_cobblestone_slab" => Some(Self::mossy_cobblestone_slab()), + "minecraft:end_stone_brick_slab" => Some(Self::end_stone_brick_slab()), + "minecraft:smooth_sandstone_slab" => Some(Self::smooth_sandstone_slab()), + "minecraft:smooth_quartz_slab" => Some(Self::smooth_quartz_slab()), + "minecraft:granite_slab" => Some(Self::granite_slab()), + "minecraft:andesite_slab" => Some(Self::andesite_slab()), + "minecraft:red_nether_brick_slab" => Some(Self::red_nether_brick_slab()), + "minecraft:polished_andesite_slab" => Some(Self::polished_andesite_slab()), + "minecraft:diorite_slab" => Some(Self::diorite_slab()), + "minecraft:brick_wall" => Some(Self::brick_wall()), + "minecraft:prismarine_wall" => Some(Self::prismarine_wall()), + "minecraft:red_sandstone_wall" => Some(Self::red_sandstone_wall()), + "minecraft:mossy_stone_brick_wall" => Some(Self::mossy_stone_brick_wall()), + "minecraft:granite_wall" => Some(Self::granite_wall()), + "minecraft:stone_brick_wall" => Some(Self::stone_brick_wall()), + "minecraft:nether_brick_wall" => Some(Self::nether_brick_wall()), + "minecraft:andesite_wall" => Some(Self::andesite_wall()), + "minecraft:red_nether_brick_wall" => Some(Self::red_nether_brick_wall()), + "minecraft:sandstone_wall" => Some(Self::sandstone_wall()), + "minecraft:end_stone_brick_wall" => Some(Self::end_stone_brick_wall()), + "minecraft:diorite_wall" => Some(Self::diorite_wall()), + "minecraft:scaffolding" => Some(Self::scaffolding()), + "minecraft:loom" => Some(Self::loom()), + "minecraft:barrel" => Some(Self::barrel()), + "minecraft:smoker" => Some(Self::smoker()), + "minecraft:blast_furnace" => Some(Self::blast_furnace()), + "minecraft:cartography_table" => Some(Self::cartography_table()), + "minecraft:fletching_table" => Some(Self::fletching_table()), + "minecraft:grindstone" => Some(Self::grindstone()), + "minecraft:lectern" => Some(Self::lectern()), + "minecraft:smithing_table" => Some(Self::smithing_table()), + "minecraft:stonecutter" => Some(Self::stonecutter()), + "minecraft:bell" => Some(Self::bell()), + "minecraft:lantern" => Some(Self::lantern()), + "minecraft:soul_lantern" => Some(Self::soul_lantern()), + "minecraft:campfire" => Some(Self::campfire()), + "minecraft:soul_campfire" => Some(Self::soul_campfire()), + "minecraft:sweet_berry_bush" => Some(Self::sweet_berry_bush()), + "minecraft:warped_stem" => Some(Self::warped_stem()), + "minecraft:stripped_warped_stem" => Some(Self::stripped_warped_stem()), + "minecraft:warped_hyphae" => Some(Self::warped_hyphae()), + "minecraft:stripped_warped_hyphae" => Some(Self::stripped_warped_hyphae()), + "minecraft:warped_nylium" => Some(Self::warped_nylium()), + "minecraft:warped_fungus" => Some(Self::warped_fungus()), + "minecraft:warped_wart_block" => Some(Self::warped_wart_block()), + "minecraft:warped_roots" => Some(Self::warped_roots()), + "minecraft:nether_sprouts" => Some(Self::nether_sprouts()), + "minecraft:crimson_stem" => Some(Self::crimson_stem()), + "minecraft:stripped_crimson_stem" => Some(Self::stripped_crimson_stem()), + "minecraft:crimson_hyphae" => Some(Self::crimson_hyphae()), + "minecraft:stripped_crimson_hyphae" => Some(Self::stripped_crimson_hyphae()), + "minecraft:crimson_nylium" => Some(Self::crimson_nylium()), + "minecraft:crimson_fungus" => Some(Self::crimson_fungus()), + "minecraft:shroomlight" => Some(Self::shroomlight()), + "minecraft:weeping_vines" => Some(Self::weeping_vines()), + "minecraft:weeping_vines_plant" => Some(Self::weeping_vines_plant()), + "minecraft:twisting_vines" => Some(Self::twisting_vines()), + "minecraft:twisting_vines_plant" => Some(Self::twisting_vines_plant()), + "minecraft:crimson_roots" => Some(Self::crimson_roots()), + "minecraft:crimson_planks" => Some(Self::crimson_planks()), + "minecraft:warped_planks" => Some(Self::warped_planks()), + "minecraft:crimson_slab" => Some(Self::crimson_slab()), + "minecraft:warped_slab" => Some(Self::warped_slab()), + "minecraft:crimson_pressure_plate" => Some(Self::crimson_pressure_plate()), + "minecraft:warped_pressure_plate" => Some(Self::warped_pressure_plate()), + "minecraft:crimson_fence" => Some(Self::crimson_fence()), + "minecraft:warped_fence" => Some(Self::warped_fence()), + "minecraft:crimson_trapdoor" => Some(Self::crimson_trapdoor()), + "minecraft:warped_trapdoor" => Some(Self::warped_trapdoor()), + "minecraft:crimson_fence_gate" => Some(Self::crimson_fence_gate()), + "minecraft:warped_fence_gate" => Some(Self::warped_fence_gate()), + "minecraft:crimson_stairs" => Some(Self::crimson_stairs()), + "minecraft:warped_stairs" => Some(Self::warped_stairs()), + "minecraft:crimson_button" => Some(Self::crimson_button()), + "minecraft:warped_button" => Some(Self::warped_button()), + "minecraft:crimson_door" => Some(Self::crimson_door()), + "minecraft:warped_door" => Some(Self::warped_door()), + "minecraft:crimson_sign" => Some(Self::crimson_sign()), + "minecraft:warped_sign" => Some(Self::warped_sign()), + "minecraft:crimson_wall_sign" => Some(Self::crimson_wall_sign()), + "minecraft:warped_wall_sign" => Some(Self::warped_wall_sign()), + "minecraft:structure_block" => Some(Self::structure_block()), + "minecraft:jigsaw" => Some(Self::jigsaw()), + "minecraft:composter" => Some(Self::composter()), + "minecraft:target" => Some(Self::target()), + "minecraft:bee_nest" => Some(Self::bee_nest()), + "minecraft:beehive" => Some(Self::beehive()), + "minecraft:honey_block" => Some(Self::honey_block()), + "minecraft:honeycomb_block" => Some(Self::honeycomb_block()), + "minecraft:netherite_block" => Some(Self::netherite_block()), + "minecraft:ancient_debris" => Some(Self::ancient_debris()), + "minecraft:crying_obsidian" => Some(Self::crying_obsidian()), + "minecraft:respawn_anchor" => Some(Self::respawn_anchor()), + "minecraft:potted_crimson_fungus" => Some(Self::potted_crimson_fungus()), + "minecraft:potted_warped_fungus" => Some(Self::potted_warped_fungus()), + "minecraft:potted_crimson_roots" => Some(Self::potted_crimson_roots()), + "minecraft:potted_warped_roots" => Some(Self::potted_warped_roots()), + "minecraft:lodestone" => Some(Self::lodestone()), + "minecraft:blackstone" => Some(Self::blackstone()), + "minecraft:blackstone_stairs" => Some(Self::blackstone_stairs()), + "minecraft:blackstone_wall" => Some(Self::blackstone_wall()), + "minecraft:blackstone_slab" => Some(Self::blackstone_slab()), + "minecraft:polished_blackstone" => Some(Self::polished_blackstone()), + "minecraft:polished_blackstone_bricks" => Some(Self::polished_blackstone_bricks()), + "minecraft:cracked_polished_blackstone_bricks" => { + Some(Self::cracked_polished_blackstone_bricks()) + } + "minecraft:chiseled_polished_blackstone" => Some(Self::chiseled_polished_blackstone()), + "minecraft:polished_blackstone_brick_slab" => { + Some(Self::polished_blackstone_brick_slab()) + } + "minecraft:polished_blackstone_brick_stairs" => { + Some(Self::polished_blackstone_brick_stairs()) + } + "minecraft:polished_blackstone_brick_wall" => { + Some(Self::polished_blackstone_brick_wall()) + } + "minecraft:gilded_blackstone" => Some(Self::gilded_blackstone()), + "minecraft:polished_blackstone_stairs" => Some(Self::polished_blackstone_stairs()), + "minecraft:polished_blackstone_slab" => Some(Self::polished_blackstone_slab()), + "minecraft:polished_blackstone_pressure_plate" => { + Some(Self::polished_blackstone_pressure_plate()) + } + "minecraft:polished_blackstone_button" => Some(Self::polished_blackstone_button()), + "minecraft:polished_blackstone_wall" => Some(Self::polished_blackstone_wall()), + "minecraft:chiseled_nether_bricks" => Some(Self::chiseled_nether_bricks()), + "minecraft:cracked_nether_bricks" => Some(Self::cracked_nether_bricks()), + "minecraft:quartz_bricks" => Some(Self::quartz_bricks()), + _ => None, + } + } +} diff --git a/feather/blocks/src/generated/mod.rs b/feather/blocks/src/generated/mod.rs new file mode 100644 index 000000000..7f94368d3 --- /dev/null +++ b/feather/blocks/src/generated/mod.rs @@ -0,0 +1,3 @@ +mod block_fns; +mod properties; +pub mod table; diff --git a/feather/blocks/src/generated/properties.rs b/feather/blocks/src/generated/properties.rs new file mode 100644 index 000000000..2f3838a73 --- /dev/null +++ b/feather/blocks/src/generated/properties.rs @@ -0,0 +1,1612 @@ +use crate::{BlockId, BlockKind}; +impl BlockId { + #[doc = "Determines whether or not a block has the `age_0_1` property."] + pub fn has_age_0_1(self) -> bool { + match self.kind() { + BlockKind::Bamboo => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `age_0_15` property."] + pub fn has_age_0_15(self) -> bool { + match self.kind() { + BlockKind::Fire | BlockKind::Cactus | BlockKind::SugarCane => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `age_0_2` property."] + pub fn has_age_0_2(self) -> bool { + match self.kind() { + BlockKind::Cocoa => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `age_0_25` property."] + pub fn has_age_0_25(self) -> bool { + match self.kind() { + BlockKind::Kelp | BlockKind::WeepingVines | BlockKind::TwistingVines => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `age_0_3` property."] + pub fn has_age_0_3(self) -> bool { + match self.kind() { + BlockKind::NetherWart + | BlockKind::Beetroots + | BlockKind::FrostedIce + | BlockKind::SweetBerryBush => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `age_0_5` property."] + pub fn has_age_0_5(self) -> bool { + match self.kind() { + BlockKind::ChorusFlower => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `age_0_7` property."] + pub fn has_age_0_7(self) -> bool { + match self.kind() { + BlockKind::Wheat + | BlockKind::PumpkinStem + | BlockKind::MelonStem + | BlockKind::Carrots + | BlockKind::Potatoes => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `attached` property."] + pub fn has_attached(self) -> bool { + match self.kind() { + BlockKind::TripwireHook | BlockKind::Tripwire => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `attachment` property."] + pub fn has_attachment(self) -> bool { + match self.kind() { + BlockKind::Bell => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `axis_xyz` property."] + pub fn has_axis_xyz(self) -> bool { + match self.kind() { + BlockKind::OakLog + | BlockKind::SpruceLog + | BlockKind::BirchLog + | BlockKind::JungleLog + | BlockKind::AcaciaLog + | BlockKind::DarkOakLog + | BlockKind::StrippedSpruceLog + | BlockKind::StrippedBirchLog + | BlockKind::StrippedJungleLog + | BlockKind::StrippedAcaciaLog + | BlockKind::StrippedDarkOakLog + | BlockKind::StrippedOakLog + | BlockKind::OakWood + | BlockKind::SpruceWood + | BlockKind::BirchWood + | BlockKind::JungleWood + | BlockKind::AcaciaWood + | BlockKind::DarkOakWood + | BlockKind::StrippedOakWood + | BlockKind::StrippedSpruceWood + | BlockKind::StrippedBirchWood + | BlockKind::StrippedJungleWood + | BlockKind::StrippedAcaciaWood + | BlockKind::StrippedDarkOakWood + | BlockKind::Basalt + | BlockKind::PolishedBasalt + | BlockKind::Chain + | BlockKind::QuartzPillar + | BlockKind::HayBlock + | BlockKind::PurpurPillar + | BlockKind::BoneBlock + | BlockKind::WarpedStem + | BlockKind::StrippedWarpedStem + | BlockKind::WarpedHyphae + | BlockKind::StrippedWarpedHyphae + | BlockKind::CrimsonStem + | BlockKind::StrippedCrimsonStem + | BlockKind::CrimsonHyphae + | BlockKind::StrippedCrimsonHyphae => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `axis_xz` property."] + pub fn has_axis_xz(self) -> bool { + match self.kind() { + BlockKind::NetherPortal => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `bites` property."] + pub fn has_bites(self) -> bool { + match self.kind() { + BlockKind::Cake => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `bottom` property."] + pub fn has_bottom(self) -> bool { + match self.kind() { + BlockKind::Scaffolding => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `cauldron_level` property."] + pub fn has_cauldron_level(self) -> bool { + match self.kind() { + BlockKind::Cauldron => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `charges` property."] + pub fn has_charges(self) -> bool { + match self.kind() { + BlockKind::RespawnAnchor => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `chest_kind` property."] + pub fn has_chest_kind(self) -> bool { + match self.kind() { + BlockKind::Chest | BlockKind::TrappedChest => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `comparator_mode` property."] + pub fn has_comparator_mode(self) -> bool { + match self.kind() { + BlockKind::Comparator => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `conditional` property."] + pub fn has_conditional(self) -> bool { + match self.kind() { + BlockKind::CommandBlock + | BlockKind::RepeatingCommandBlock + | BlockKind::ChainCommandBlock => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `delay` property."] + pub fn has_delay(self) -> bool { + match self.kind() { + BlockKind::Repeater => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `disarmed` property."] + pub fn has_disarmed(self) -> bool { + match self.kind() { + BlockKind::Tripwire => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `distance_0_7` property."] + pub fn has_distance_0_7(self) -> bool { + match self.kind() { + BlockKind::Scaffolding => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `distance_1_7` property."] + pub fn has_distance_1_7(self) -> bool { + match self.kind() { + BlockKind::OakLeaves + | BlockKind::SpruceLeaves + | BlockKind::BirchLeaves + | BlockKind::JungleLeaves + | BlockKind::AcaciaLeaves + | BlockKind::DarkOakLeaves => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `down` property."] + pub fn has_down(self) -> bool { + match self.kind() { + BlockKind::BrownMushroomBlock + | BlockKind::RedMushroomBlock + | BlockKind::MushroomStem + | BlockKind::ChorusPlant => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `drag` property."] + pub fn has_drag(self) -> bool { + match self.kind() { + BlockKind::BubbleColumn => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `east_connected` property."] + pub fn has_east_connected(self) -> bool { + match self.kind() { + BlockKind::Fire + | BlockKind::OakFence + | BlockKind::BrownMushroomBlock + | BlockKind::RedMushroomBlock + | BlockKind::MushroomStem + | BlockKind::IronBars + | BlockKind::GlassPane + | BlockKind::Vine + | BlockKind::NetherBrickFence + | BlockKind::Tripwire + | BlockKind::WhiteStainedGlassPane + | BlockKind::OrangeStainedGlassPane + | BlockKind::MagentaStainedGlassPane + | BlockKind::LightBlueStainedGlassPane + | BlockKind::YellowStainedGlassPane + | BlockKind::LimeStainedGlassPane + | BlockKind::PinkStainedGlassPane + | BlockKind::GrayStainedGlassPane + | BlockKind::LightGrayStainedGlassPane + | BlockKind::CyanStainedGlassPane + | BlockKind::PurpleStainedGlassPane + | BlockKind::BlueStainedGlassPane + | BlockKind::BrownStainedGlassPane + | BlockKind::GreenStainedGlassPane + | BlockKind::RedStainedGlassPane + | BlockKind::BlackStainedGlassPane + | BlockKind::SpruceFence + | BlockKind::BirchFence + | BlockKind::JungleFence + | BlockKind::AcaciaFence + | BlockKind::DarkOakFence + | BlockKind::ChorusPlant + | BlockKind::CrimsonFence + | BlockKind::WarpedFence => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `east_nlt` property."] + pub fn has_east_nlt(self) -> bool { + match self.kind() { + BlockKind::CobblestoneWall + | BlockKind::MossyCobblestoneWall + | BlockKind::BrickWall + | BlockKind::PrismarineWall + | BlockKind::RedSandstoneWall + | BlockKind::MossyStoneBrickWall + | BlockKind::GraniteWall + | BlockKind::StoneBrickWall + | BlockKind::NetherBrickWall + | BlockKind::AndesiteWall + | BlockKind::RedNetherBrickWall + | BlockKind::SandstoneWall + | BlockKind::EndStoneBrickWall + | BlockKind::DioriteWall + | BlockKind::BlackstoneWall + | BlockKind::PolishedBlackstoneBrickWall + | BlockKind::PolishedBlackstoneWall => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `east_wire` property."] + pub fn has_east_wire(self) -> bool { + match self.kind() { + BlockKind::RedstoneWire => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `eggs` property."] + pub fn has_eggs(self) -> bool { + match self.kind() { + BlockKind::TurtleEgg => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `enabled` property."] + pub fn has_enabled(self) -> bool { + match self.kind() { + BlockKind::Hopper => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `extended` property."] + pub fn has_extended(self) -> bool { + match self.kind() { + BlockKind::StickyPiston | BlockKind::Piston => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `eye` property."] + pub fn has_eye(self) -> bool { + match self.kind() { + BlockKind::EndPortalFrame => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `face` property."] + pub fn has_face(self) -> bool { + match self.kind() { + BlockKind::Lever + | BlockKind::StoneButton + | BlockKind::OakButton + | BlockKind::SpruceButton + | BlockKind::BirchButton + | BlockKind::JungleButton + | BlockKind::AcaciaButton + | BlockKind::DarkOakButton + | BlockKind::Grindstone + | BlockKind::CrimsonButton + | BlockKind::WarpedButton + | BlockKind::PolishedBlackstoneButton => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `facing_cardinal` property."] + pub fn has_facing_cardinal(self) -> bool { + match self.kind() { + BlockKind::WhiteBed + | BlockKind::OrangeBed + | BlockKind::MagentaBed + | BlockKind::LightBlueBed + | BlockKind::YellowBed + | BlockKind::LimeBed + | BlockKind::PinkBed + | BlockKind::GrayBed + | BlockKind::LightGrayBed + | BlockKind::CyanBed + | BlockKind::PurpleBed + | BlockKind::BlueBed + | BlockKind::BrownBed + | BlockKind::GreenBed + | BlockKind::RedBed + | BlockKind::BlackBed + | BlockKind::WallTorch + | BlockKind::OakStairs + | BlockKind::Chest + | BlockKind::Furnace + | BlockKind::OakDoor + | BlockKind::Ladder + | BlockKind::CobblestoneStairs + | BlockKind::OakWallSign + | BlockKind::SpruceWallSign + | BlockKind::BirchWallSign + | BlockKind::AcaciaWallSign + | BlockKind::JungleWallSign + | BlockKind::DarkOakWallSign + | BlockKind::Lever + | BlockKind::IronDoor + | BlockKind::RedstoneWallTorch + | BlockKind::StoneButton + | BlockKind::SoulWallTorch + | BlockKind::CarvedPumpkin + | BlockKind::JackOLantern + | BlockKind::Repeater + | BlockKind::OakTrapdoor + | BlockKind::SpruceTrapdoor + | BlockKind::BirchTrapdoor + | BlockKind::JungleTrapdoor + | BlockKind::AcaciaTrapdoor + | BlockKind::DarkOakTrapdoor + | BlockKind::AttachedPumpkinStem + | BlockKind::AttachedMelonStem + | BlockKind::OakFenceGate + | BlockKind::BrickStairs + | BlockKind::StoneBrickStairs + | BlockKind::NetherBrickStairs + | BlockKind::EndPortalFrame + | BlockKind::Cocoa + | BlockKind::SandstoneStairs + | BlockKind::EnderChest + | BlockKind::TripwireHook + | BlockKind::SpruceStairs + | BlockKind::BirchStairs + | BlockKind::JungleStairs + | BlockKind::OakButton + | BlockKind::SpruceButton + | BlockKind::BirchButton + | BlockKind::JungleButton + | BlockKind::AcaciaButton + | BlockKind::DarkOakButton + | BlockKind::SkeletonWallSkull + | BlockKind::WitherSkeletonWallSkull + | BlockKind::ZombieWallHead + | BlockKind::PlayerWallHead + | BlockKind::CreeperWallHead + | BlockKind::DragonWallHead + | BlockKind::Anvil + | BlockKind::ChippedAnvil + | BlockKind::DamagedAnvil + | BlockKind::TrappedChest + | BlockKind::Comparator + | BlockKind::QuartzStairs + | BlockKind::AcaciaStairs + | BlockKind::DarkOakStairs + | BlockKind::IronTrapdoor + | BlockKind::PrismarineStairs + | BlockKind::PrismarineBrickStairs + | BlockKind::DarkPrismarineStairs + | BlockKind::WhiteWallBanner + | BlockKind::OrangeWallBanner + | BlockKind::MagentaWallBanner + | BlockKind::LightBlueWallBanner + | BlockKind::YellowWallBanner + | BlockKind::LimeWallBanner + | BlockKind::PinkWallBanner + | BlockKind::GrayWallBanner + | BlockKind::LightGrayWallBanner + | BlockKind::CyanWallBanner + | BlockKind::PurpleWallBanner + | BlockKind::BlueWallBanner + | BlockKind::BrownWallBanner + | BlockKind::GreenWallBanner + | BlockKind::RedWallBanner + | BlockKind::BlackWallBanner + | BlockKind::RedSandstoneStairs + | BlockKind::SpruceFenceGate + | BlockKind::BirchFenceGate + | BlockKind::JungleFenceGate + | BlockKind::AcaciaFenceGate + | BlockKind::DarkOakFenceGate + | BlockKind::SpruceDoor + | BlockKind::BirchDoor + | BlockKind::JungleDoor + | BlockKind::AcaciaDoor + | BlockKind::DarkOakDoor + | BlockKind::PurpurStairs + | BlockKind::WhiteGlazedTerracotta + | BlockKind::OrangeGlazedTerracotta + | BlockKind::MagentaGlazedTerracotta + | BlockKind::LightBlueGlazedTerracotta + | BlockKind::YellowGlazedTerracotta + | BlockKind::LimeGlazedTerracotta + | BlockKind::PinkGlazedTerracotta + | BlockKind::GrayGlazedTerracotta + | BlockKind::LightGrayGlazedTerracotta + | BlockKind::CyanGlazedTerracotta + | BlockKind::PurpleGlazedTerracotta + | BlockKind::BlueGlazedTerracotta + | BlockKind::BrownGlazedTerracotta + | BlockKind::GreenGlazedTerracotta + | BlockKind::RedGlazedTerracotta + | BlockKind::BlackGlazedTerracotta + | BlockKind::DeadTubeCoralWallFan + | BlockKind::DeadBrainCoralWallFan + | BlockKind::DeadBubbleCoralWallFan + | BlockKind::DeadFireCoralWallFan + | BlockKind::DeadHornCoralWallFan + | BlockKind::TubeCoralWallFan + | BlockKind::BrainCoralWallFan + | BlockKind::BubbleCoralWallFan + | BlockKind::FireCoralWallFan + | BlockKind::HornCoralWallFan + | BlockKind::PolishedGraniteStairs + | BlockKind::SmoothRedSandstoneStairs + | BlockKind::MossyStoneBrickStairs + | BlockKind::PolishedDioriteStairs + | BlockKind::MossyCobblestoneStairs + | BlockKind::EndStoneBrickStairs + | BlockKind::StoneStairs + | BlockKind::SmoothSandstoneStairs + | BlockKind::SmoothQuartzStairs + | BlockKind::GraniteStairs + | BlockKind::AndesiteStairs + | BlockKind::RedNetherBrickStairs + | BlockKind::PolishedAndesiteStairs + | BlockKind::DioriteStairs + | BlockKind::Loom + | BlockKind::Smoker + | BlockKind::BlastFurnace + | BlockKind::Grindstone + | BlockKind::Lectern + | BlockKind::Stonecutter + | BlockKind::Bell + | BlockKind::Campfire + | BlockKind::SoulCampfire + | BlockKind::CrimsonTrapdoor + | BlockKind::WarpedTrapdoor + | BlockKind::CrimsonFenceGate + | BlockKind::WarpedFenceGate + | BlockKind::CrimsonStairs + | BlockKind::WarpedStairs + | BlockKind::CrimsonButton + | BlockKind::WarpedButton + | BlockKind::CrimsonDoor + | BlockKind::WarpedDoor + | BlockKind::CrimsonWallSign + | BlockKind::WarpedWallSign + | BlockKind::BeeNest + | BlockKind::Beehive + | BlockKind::BlackstoneStairs + | BlockKind::PolishedBlackstoneBrickStairs + | BlockKind::PolishedBlackstoneStairs + | BlockKind::PolishedBlackstoneButton => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `facing_cardinal_and_down` property."] + pub fn has_facing_cardinal_and_down(self) -> bool { + match self.kind() { + BlockKind::Hopper => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `facing_cubic` property."] + pub fn has_facing_cubic(self) -> bool { + match self.kind() { + BlockKind::Dispenser + | BlockKind::StickyPiston + | BlockKind::Piston + | BlockKind::PistonHead + | BlockKind::MovingPiston + | BlockKind::CommandBlock + | BlockKind::Dropper + | BlockKind::EndRod + | BlockKind::RepeatingCommandBlock + | BlockKind::ChainCommandBlock + | BlockKind::Observer + | BlockKind::ShulkerBox + | BlockKind::WhiteShulkerBox + | BlockKind::OrangeShulkerBox + | BlockKind::MagentaShulkerBox + | BlockKind::LightBlueShulkerBox + | BlockKind::YellowShulkerBox + | BlockKind::LimeShulkerBox + | BlockKind::PinkShulkerBox + | BlockKind::GrayShulkerBox + | BlockKind::LightGrayShulkerBox + | BlockKind::CyanShulkerBox + | BlockKind::PurpleShulkerBox + | BlockKind::BlueShulkerBox + | BlockKind::BrownShulkerBox + | BlockKind::GreenShulkerBox + | BlockKind::RedShulkerBox + | BlockKind::BlackShulkerBox + | BlockKind::Barrel => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `half_top_bottom` property."] + pub fn has_half_top_bottom(self) -> bool { + match self.kind() { + BlockKind::OakStairs + | BlockKind::CobblestoneStairs + | BlockKind::OakTrapdoor + | BlockKind::SpruceTrapdoor + | BlockKind::BirchTrapdoor + | BlockKind::JungleTrapdoor + | BlockKind::AcaciaTrapdoor + | BlockKind::DarkOakTrapdoor + | BlockKind::BrickStairs + | BlockKind::StoneBrickStairs + | BlockKind::NetherBrickStairs + | BlockKind::SandstoneStairs + | BlockKind::SpruceStairs + | BlockKind::BirchStairs + | BlockKind::JungleStairs + | BlockKind::QuartzStairs + | BlockKind::AcaciaStairs + | BlockKind::DarkOakStairs + | BlockKind::IronTrapdoor + | BlockKind::PrismarineStairs + | BlockKind::PrismarineBrickStairs + | BlockKind::DarkPrismarineStairs + | BlockKind::RedSandstoneStairs + | BlockKind::PurpurStairs + | BlockKind::PolishedGraniteStairs + | BlockKind::SmoothRedSandstoneStairs + | BlockKind::MossyStoneBrickStairs + | BlockKind::PolishedDioriteStairs + | BlockKind::MossyCobblestoneStairs + | BlockKind::EndStoneBrickStairs + | BlockKind::StoneStairs + | BlockKind::SmoothSandstoneStairs + | BlockKind::SmoothQuartzStairs + | BlockKind::GraniteStairs + | BlockKind::AndesiteStairs + | BlockKind::RedNetherBrickStairs + | BlockKind::PolishedAndesiteStairs + | BlockKind::DioriteStairs + | BlockKind::CrimsonTrapdoor + | BlockKind::WarpedTrapdoor + | BlockKind::CrimsonStairs + | BlockKind::WarpedStairs + | BlockKind::BlackstoneStairs + | BlockKind::PolishedBlackstoneBrickStairs + | BlockKind::PolishedBlackstoneStairs => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `half_upper_lower` property."] + pub fn has_half_upper_lower(self) -> bool { + match self.kind() { + BlockKind::TallSeagrass + | BlockKind::OakDoor + | BlockKind::IronDoor + | BlockKind::Sunflower + | BlockKind::Lilac + | BlockKind::RoseBush + | BlockKind::Peony + | BlockKind::TallGrass + | BlockKind::LargeFern + | BlockKind::SpruceDoor + | BlockKind::BirchDoor + | BlockKind::JungleDoor + | BlockKind::AcaciaDoor + | BlockKind::DarkOakDoor + | BlockKind::CrimsonDoor + | BlockKind::WarpedDoor => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `hanging` property."] + pub fn has_hanging(self) -> bool { + match self.kind() { + BlockKind::Lantern | BlockKind::SoulLantern => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `has_book` property."] + pub fn has_has_book(self) -> bool { + match self.kind() { + BlockKind::Lectern => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `has_bottle_0` property."] + pub fn has_has_bottle_0(self) -> bool { + match self.kind() { + BlockKind::BrewingStand => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `has_bottle_1` property."] + pub fn has_has_bottle_1(self) -> bool { + match self.kind() { + BlockKind::BrewingStand => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `has_bottle_2` property."] + pub fn has_has_bottle_2(self) -> bool { + match self.kind() { + BlockKind::BrewingStand => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `has_record` property."] + pub fn has_has_record(self) -> bool { + match self.kind() { + BlockKind::Jukebox => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `hatch` property."] + pub fn has_hatch(self) -> bool { + match self.kind() { + BlockKind::TurtleEgg => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `hinge` property."] + pub fn has_hinge(self) -> bool { + match self.kind() { + BlockKind::OakDoor + | BlockKind::IronDoor + | BlockKind::SpruceDoor + | BlockKind::BirchDoor + | BlockKind::JungleDoor + | BlockKind::AcaciaDoor + | BlockKind::DarkOakDoor + | BlockKind::CrimsonDoor + | BlockKind::WarpedDoor => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `honey_level` property."] + pub fn has_honey_level(self) -> bool { + match self.kind() { + BlockKind::BeeNest | BlockKind::Beehive => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `in_wall` property."] + pub fn has_in_wall(self) -> bool { + match self.kind() { + BlockKind::OakFenceGate + | BlockKind::SpruceFenceGate + | BlockKind::BirchFenceGate + | BlockKind::JungleFenceGate + | BlockKind::AcaciaFenceGate + | BlockKind::DarkOakFenceGate + | BlockKind::CrimsonFenceGate + | BlockKind::WarpedFenceGate => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `instrument` property."] + pub fn has_instrument(self) -> bool { + match self.kind() { + BlockKind::NoteBlock => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `inverted` property."] + pub fn has_inverted(self) -> bool { + match self.kind() { + BlockKind::DaylightDetector => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `layers` property."] + pub fn has_layers(self) -> bool { + match self.kind() { + BlockKind::Snow => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `leaves` property."] + pub fn has_leaves(self) -> bool { + match self.kind() { + BlockKind::Bamboo => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `level_0_8` property."] + pub fn has_level_0_8(self) -> bool { + match self.kind() { + BlockKind::Composter => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `lit` property."] + pub fn has_lit(self) -> bool { + match self.kind() { + BlockKind::Furnace + | BlockKind::RedstoneOre + | BlockKind::RedstoneTorch + | BlockKind::RedstoneWallTorch + | BlockKind::RedstoneLamp + | BlockKind::Smoker + | BlockKind::BlastFurnace + | BlockKind::Campfire + | BlockKind::SoulCampfire => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `locked` property."] + pub fn has_locked(self) -> bool { + match self.kind() { + BlockKind::Repeater => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `moisture` property."] + pub fn has_moisture(self) -> bool { + match self.kind() { + BlockKind::Farmland => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `north_connected` property."] + pub fn has_north_connected(self) -> bool { + match self.kind() { + BlockKind::Fire + | BlockKind::OakFence + | BlockKind::BrownMushroomBlock + | BlockKind::RedMushroomBlock + | BlockKind::MushroomStem + | BlockKind::IronBars + | BlockKind::GlassPane + | BlockKind::Vine + | BlockKind::NetherBrickFence + | BlockKind::Tripwire + | BlockKind::WhiteStainedGlassPane + | BlockKind::OrangeStainedGlassPane + | BlockKind::MagentaStainedGlassPane + | BlockKind::LightBlueStainedGlassPane + | BlockKind::YellowStainedGlassPane + | BlockKind::LimeStainedGlassPane + | BlockKind::PinkStainedGlassPane + | BlockKind::GrayStainedGlassPane + | BlockKind::LightGrayStainedGlassPane + | BlockKind::CyanStainedGlassPane + | BlockKind::PurpleStainedGlassPane + | BlockKind::BlueStainedGlassPane + | BlockKind::BrownStainedGlassPane + | BlockKind::GreenStainedGlassPane + | BlockKind::RedStainedGlassPane + | BlockKind::BlackStainedGlassPane + | BlockKind::SpruceFence + | BlockKind::BirchFence + | BlockKind::JungleFence + | BlockKind::AcaciaFence + | BlockKind::DarkOakFence + | BlockKind::ChorusPlant + | BlockKind::CrimsonFence + | BlockKind::WarpedFence => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `north_nlt` property."] + pub fn has_north_nlt(self) -> bool { + match self.kind() { + BlockKind::CobblestoneWall + | BlockKind::MossyCobblestoneWall + | BlockKind::BrickWall + | BlockKind::PrismarineWall + | BlockKind::RedSandstoneWall + | BlockKind::MossyStoneBrickWall + | BlockKind::GraniteWall + | BlockKind::StoneBrickWall + | BlockKind::NetherBrickWall + | BlockKind::AndesiteWall + | BlockKind::RedNetherBrickWall + | BlockKind::SandstoneWall + | BlockKind::EndStoneBrickWall + | BlockKind::DioriteWall + | BlockKind::BlackstoneWall + | BlockKind::PolishedBlackstoneBrickWall + | BlockKind::PolishedBlackstoneWall => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `north_wire` property."] + pub fn has_north_wire(self) -> bool { + match self.kind() { + BlockKind::RedstoneWire => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `note` property."] + pub fn has_note(self) -> bool { + match self.kind() { + BlockKind::NoteBlock => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `occupied` property."] + pub fn has_occupied(self) -> bool { + match self.kind() { + BlockKind::WhiteBed + | BlockKind::OrangeBed + | BlockKind::MagentaBed + | BlockKind::LightBlueBed + | BlockKind::YellowBed + | BlockKind::LimeBed + | BlockKind::PinkBed + | BlockKind::GrayBed + | BlockKind::LightGrayBed + | BlockKind::CyanBed + | BlockKind::PurpleBed + | BlockKind::BlueBed + | BlockKind::BrownBed + | BlockKind::GreenBed + | BlockKind::RedBed + | BlockKind::BlackBed => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `open` property."] + pub fn has_open(self) -> bool { + match self.kind() { + BlockKind::OakDoor + | BlockKind::IronDoor + | BlockKind::OakTrapdoor + | BlockKind::SpruceTrapdoor + | BlockKind::BirchTrapdoor + | BlockKind::JungleTrapdoor + | BlockKind::AcaciaTrapdoor + | BlockKind::DarkOakTrapdoor + | BlockKind::OakFenceGate + | BlockKind::IronTrapdoor + | BlockKind::SpruceFenceGate + | BlockKind::BirchFenceGate + | BlockKind::JungleFenceGate + | BlockKind::AcaciaFenceGate + | BlockKind::DarkOakFenceGate + | BlockKind::SpruceDoor + | BlockKind::BirchDoor + | BlockKind::JungleDoor + | BlockKind::AcaciaDoor + | BlockKind::DarkOakDoor + | BlockKind::Barrel + | BlockKind::CrimsonTrapdoor + | BlockKind::WarpedTrapdoor + | BlockKind::CrimsonFenceGate + | BlockKind::WarpedFenceGate + | BlockKind::CrimsonDoor + | BlockKind::WarpedDoor => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `orientation` property."] + pub fn has_orientation(self) -> bool { + match self.kind() { + BlockKind::Jigsaw => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `part` property."] + pub fn has_part(self) -> bool { + match self.kind() { + BlockKind::WhiteBed + | BlockKind::OrangeBed + | BlockKind::MagentaBed + | BlockKind::LightBlueBed + | BlockKind::YellowBed + | BlockKind::LimeBed + | BlockKind::PinkBed + | BlockKind::GrayBed + | BlockKind::LightGrayBed + | BlockKind::CyanBed + | BlockKind::PurpleBed + | BlockKind::BlueBed + | BlockKind::BrownBed + | BlockKind::GreenBed + | BlockKind::RedBed + | BlockKind::BlackBed => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `persistent` property."] + pub fn has_persistent(self) -> bool { + match self.kind() { + BlockKind::OakLeaves + | BlockKind::SpruceLeaves + | BlockKind::BirchLeaves + | BlockKind::JungleLeaves + | BlockKind::AcaciaLeaves + | BlockKind::DarkOakLeaves => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `pickles` property."] + pub fn has_pickles(self) -> bool { + match self.kind() { + BlockKind::SeaPickle => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `piston_kind` property."] + pub fn has_piston_kind(self) -> bool { + match self.kind() { + BlockKind::PistonHead | BlockKind::MovingPiston => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `power` property."] + pub fn has_power(self) -> bool { + match self.kind() { + BlockKind::RedstoneWire + | BlockKind::LightWeightedPressurePlate + | BlockKind::HeavyWeightedPressurePlate + | BlockKind::DaylightDetector + | BlockKind::Target => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `powered` property."] + pub fn has_powered(self) -> bool { + match self.kind() { + BlockKind::NoteBlock + | BlockKind::PoweredRail + | BlockKind::DetectorRail + | BlockKind::OakDoor + | BlockKind::Lever + | BlockKind::StonePressurePlate + | BlockKind::IronDoor + | BlockKind::OakPressurePlate + | BlockKind::SprucePressurePlate + | BlockKind::BirchPressurePlate + | BlockKind::JunglePressurePlate + | BlockKind::AcaciaPressurePlate + | BlockKind::DarkOakPressurePlate + | BlockKind::StoneButton + | BlockKind::Repeater + | BlockKind::OakTrapdoor + | BlockKind::SpruceTrapdoor + | BlockKind::BirchTrapdoor + | BlockKind::JungleTrapdoor + | BlockKind::AcaciaTrapdoor + | BlockKind::DarkOakTrapdoor + | BlockKind::OakFenceGate + | BlockKind::TripwireHook + | BlockKind::Tripwire + | BlockKind::OakButton + | BlockKind::SpruceButton + | BlockKind::BirchButton + | BlockKind::JungleButton + | BlockKind::AcaciaButton + | BlockKind::DarkOakButton + | BlockKind::Comparator + | BlockKind::ActivatorRail + | BlockKind::IronTrapdoor + | BlockKind::SpruceFenceGate + | BlockKind::BirchFenceGate + | BlockKind::JungleFenceGate + | BlockKind::AcaciaFenceGate + | BlockKind::DarkOakFenceGate + | BlockKind::SpruceDoor + | BlockKind::BirchDoor + | BlockKind::JungleDoor + | BlockKind::AcaciaDoor + | BlockKind::DarkOakDoor + | BlockKind::Observer + | BlockKind::Lectern + | BlockKind::Bell + | BlockKind::CrimsonPressurePlate + | BlockKind::WarpedPressurePlate + | BlockKind::CrimsonTrapdoor + | BlockKind::WarpedTrapdoor + | BlockKind::CrimsonFenceGate + | BlockKind::WarpedFenceGate + | BlockKind::CrimsonButton + | BlockKind::WarpedButton + | BlockKind::CrimsonDoor + | BlockKind::WarpedDoor + | BlockKind::PolishedBlackstonePressurePlate + | BlockKind::PolishedBlackstoneButton => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `powered_rail_shape` property."] + pub fn has_powered_rail_shape(self) -> bool { + match self.kind() { + BlockKind::PoweredRail | BlockKind::DetectorRail | BlockKind::ActivatorRail => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `rail_shape` property."] + pub fn has_rail_shape(self) -> bool { + match self.kind() { + BlockKind::Rail => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `rotation` property."] + pub fn has_rotation(self) -> bool { + match self.kind() { + BlockKind::OakSign + | BlockKind::SpruceSign + | BlockKind::BirchSign + | BlockKind::AcaciaSign + | BlockKind::JungleSign + | BlockKind::DarkOakSign + | BlockKind::SkeletonSkull + | BlockKind::WitherSkeletonSkull + | BlockKind::ZombieHead + | BlockKind::PlayerHead + | BlockKind::CreeperHead + | BlockKind::DragonHead + | BlockKind::WhiteBanner + | BlockKind::OrangeBanner + | BlockKind::MagentaBanner + | BlockKind::LightBlueBanner + | BlockKind::YellowBanner + | BlockKind::LimeBanner + | BlockKind::PinkBanner + | BlockKind::GrayBanner + | BlockKind::LightGrayBanner + | BlockKind::CyanBanner + | BlockKind::PurpleBanner + | BlockKind::BlueBanner + | BlockKind::BrownBanner + | BlockKind::GreenBanner + | BlockKind::RedBanner + | BlockKind::BlackBanner + | BlockKind::CrimsonSign + | BlockKind::WarpedSign => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `short` property."] + pub fn has_short(self) -> bool { + match self.kind() { + BlockKind::PistonHead => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `signal_fire` property."] + pub fn has_signal_fire(self) -> bool { + match self.kind() { + BlockKind::Campfire | BlockKind::SoulCampfire => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `slab_kind` property."] + pub fn has_slab_kind(self) -> bool { + match self.kind() { + BlockKind::PrismarineSlab + | BlockKind::PrismarineBrickSlab + | BlockKind::DarkPrismarineSlab + | BlockKind::OakSlab + | BlockKind::SpruceSlab + | BlockKind::BirchSlab + | BlockKind::JungleSlab + | BlockKind::AcaciaSlab + | BlockKind::DarkOakSlab + | BlockKind::StoneSlab + | BlockKind::SmoothStoneSlab + | BlockKind::SandstoneSlab + | BlockKind::CutSandstoneSlab + | BlockKind::PetrifiedOakSlab + | BlockKind::CobblestoneSlab + | BlockKind::BrickSlab + | BlockKind::StoneBrickSlab + | BlockKind::NetherBrickSlab + | BlockKind::QuartzSlab + | BlockKind::RedSandstoneSlab + | BlockKind::CutRedSandstoneSlab + | BlockKind::PurpurSlab + | BlockKind::PolishedGraniteSlab + | BlockKind::SmoothRedSandstoneSlab + | BlockKind::MossyStoneBrickSlab + | BlockKind::PolishedDioriteSlab + | BlockKind::MossyCobblestoneSlab + | BlockKind::EndStoneBrickSlab + | BlockKind::SmoothSandstoneSlab + | BlockKind::SmoothQuartzSlab + | BlockKind::GraniteSlab + | BlockKind::AndesiteSlab + | BlockKind::RedNetherBrickSlab + | BlockKind::PolishedAndesiteSlab + | BlockKind::DioriteSlab + | BlockKind::CrimsonSlab + | BlockKind::WarpedSlab + | BlockKind::BlackstoneSlab + | BlockKind::PolishedBlackstoneBrickSlab + | BlockKind::PolishedBlackstoneSlab => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `snowy` property."] + pub fn has_snowy(self) -> bool { + match self.kind() { + BlockKind::GrassBlock | BlockKind::Podzol | BlockKind::Mycelium => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `south_connected` property."] + pub fn has_south_connected(self) -> bool { + match self.kind() { + BlockKind::Fire + | BlockKind::OakFence + | BlockKind::BrownMushroomBlock + | BlockKind::RedMushroomBlock + | BlockKind::MushroomStem + | BlockKind::IronBars + | BlockKind::GlassPane + | BlockKind::Vine + | BlockKind::NetherBrickFence + | BlockKind::Tripwire + | BlockKind::WhiteStainedGlassPane + | BlockKind::OrangeStainedGlassPane + | BlockKind::MagentaStainedGlassPane + | BlockKind::LightBlueStainedGlassPane + | BlockKind::YellowStainedGlassPane + | BlockKind::LimeStainedGlassPane + | BlockKind::PinkStainedGlassPane + | BlockKind::GrayStainedGlassPane + | BlockKind::LightGrayStainedGlassPane + | BlockKind::CyanStainedGlassPane + | BlockKind::PurpleStainedGlassPane + | BlockKind::BlueStainedGlassPane + | BlockKind::BrownStainedGlassPane + | BlockKind::GreenStainedGlassPane + | BlockKind::RedStainedGlassPane + | BlockKind::BlackStainedGlassPane + | BlockKind::SpruceFence + | BlockKind::BirchFence + | BlockKind::JungleFence + | BlockKind::AcaciaFence + | BlockKind::DarkOakFence + | BlockKind::ChorusPlant + | BlockKind::CrimsonFence + | BlockKind::WarpedFence => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `south_nlt` property."] + pub fn has_south_nlt(self) -> bool { + match self.kind() { + BlockKind::CobblestoneWall + | BlockKind::MossyCobblestoneWall + | BlockKind::BrickWall + | BlockKind::PrismarineWall + | BlockKind::RedSandstoneWall + | BlockKind::MossyStoneBrickWall + | BlockKind::GraniteWall + | BlockKind::StoneBrickWall + | BlockKind::NetherBrickWall + | BlockKind::AndesiteWall + | BlockKind::RedNetherBrickWall + | BlockKind::SandstoneWall + | BlockKind::EndStoneBrickWall + | BlockKind::DioriteWall + | BlockKind::BlackstoneWall + | BlockKind::PolishedBlackstoneBrickWall + | BlockKind::PolishedBlackstoneWall => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `south_wire` property."] + pub fn has_south_wire(self) -> bool { + match self.kind() { + BlockKind::RedstoneWire => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `stage` property."] + pub fn has_stage(self) -> bool { + match self.kind() { + BlockKind::OakSapling + | BlockKind::SpruceSapling + | BlockKind::BirchSapling + | BlockKind::JungleSapling + | BlockKind::AcaciaSapling + | BlockKind::DarkOakSapling + | BlockKind::Bamboo => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `stairs_shape` property."] + pub fn has_stairs_shape(self) -> bool { + match self.kind() { + BlockKind::OakStairs + | BlockKind::CobblestoneStairs + | BlockKind::BrickStairs + | BlockKind::StoneBrickStairs + | BlockKind::NetherBrickStairs + | BlockKind::SandstoneStairs + | BlockKind::SpruceStairs + | BlockKind::BirchStairs + | BlockKind::JungleStairs + | BlockKind::QuartzStairs + | BlockKind::AcaciaStairs + | BlockKind::DarkOakStairs + | BlockKind::PrismarineStairs + | BlockKind::PrismarineBrickStairs + | BlockKind::DarkPrismarineStairs + | BlockKind::RedSandstoneStairs + | BlockKind::PurpurStairs + | BlockKind::PolishedGraniteStairs + | BlockKind::SmoothRedSandstoneStairs + | BlockKind::MossyStoneBrickStairs + | BlockKind::PolishedDioriteStairs + | BlockKind::MossyCobblestoneStairs + | BlockKind::EndStoneBrickStairs + | BlockKind::StoneStairs + | BlockKind::SmoothSandstoneStairs + | BlockKind::SmoothQuartzStairs + | BlockKind::GraniteStairs + | BlockKind::AndesiteStairs + | BlockKind::RedNetherBrickStairs + | BlockKind::PolishedAndesiteStairs + | BlockKind::DioriteStairs + | BlockKind::CrimsonStairs + | BlockKind::WarpedStairs + | BlockKind::BlackstoneStairs + | BlockKind::PolishedBlackstoneBrickStairs + | BlockKind::PolishedBlackstoneStairs => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `structure_block_mode` property."] + pub fn has_structure_block_mode(self) -> bool { + match self.kind() { + BlockKind::StructureBlock => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `triggered` property."] + pub fn has_triggered(self) -> bool { + match self.kind() { + BlockKind::Dispenser | BlockKind::Dropper => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `unstable` property."] + pub fn has_unstable(self) -> bool { + match self.kind() { + BlockKind::Tnt => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `up` property."] + pub fn has_up(self) -> bool { + match self.kind() { + BlockKind::Fire + | BlockKind::BrownMushroomBlock + | BlockKind::RedMushroomBlock + | BlockKind::MushroomStem + | BlockKind::Vine + | BlockKind::CobblestoneWall + | BlockKind::MossyCobblestoneWall + | BlockKind::ChorusPlant + | BlockKind::BrickWall + | BlockKind::PrismarineWall + | BlockKind::RedSandstoneWall + | BlockKind::MossyStoneBrickWall + | BlockKind::GraniteWall + | BlockKind::StoneBrickWall + | BlockKind::NetherBrickWall + | BlockKind::AndesiteWall + | BlockKind::RedNetherBrickWall + | BlockKind::SandstoneWall + | BlockKind::EndStoneBrickWall + | BlockKind::DioriteWall + | BlockKind::BlackstoneWall + | BlockKind::PolishedBlackstoneBrickWall + | BlockKind::PolishedBlackstoneWall => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `water_level` property."] + pub fn has_water_level(self) -> bool { + match self.kind() { + BlockKind::Water | BlockKind::Lava => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `waterlogged` property."] + pub fn has_waterlogged(self) -> bool { + match self.kind() { + BlockKind::OakStairs + | BlockKind::Chest + | BlockKind::OakSign + | BlockKind::SpruceSign + | BlockKind::BirchSign + | BlockKind::AcaciaSign + | BlockKind::JungleSign + | BlockKind::DarkOakSign + | BlockKind::Ladder + | BlockKind::CobblestoneStairs + | BlockKind::OakWallSign + | BlockKind::SpruceWallSign + | BlockKind::BirchWallSign + | BlockKind::AcaciaWallSign + | BlockKind::JungleWallSign + | BlockKind::DarkOakWallSign + | BlockKind::OakFence + | BlockKind::OakTrapdoor + | BlockKind::SpruceTrapdoor + | BlockKind::BirchTrapdoor + | BlockKind::JungleTrapdoor + | BlockKind::AcaciaTrapdoor + | BlockKind::DarkOakTrapdoor + | BlockKind::IronBars + | BlockKind::Chain + | BlockKind::GlassPane + | BlockKind::BrickStairs + | BlockKind::StoneBrickStairs + | BlockKind::NetherBrickFence + | BlockKind::NetherBrickStairs + | BlockKind::SandstoneStairs + | BlockKind::EnderChest + | BlockKind::SpruceStairs + | BlockKind::BirchStairs + | BlockKind::JungleStairs + | BlockKind::CobblestoneWall + | BlockKind::MossyCobblestoneWall + | BlockKind::TrappedChest + | BlockKind::QuartzStairs + | BlockKind::WhiteStainedGlassPane + | BlockKind::OrangeStainedGlassPane + | BlockKind::MagentaStainedGlassPane + | BlockKind::LightBlueStainedGlassPane + | BlockKind::YellowStainedGlassPane + | BlockKind::LimeStainedGlassPane + | BlockKind::PinkStainedGlassPane + | BlockKind::GrayStainedGlassPane + | BlockKind::LightGrayStainedGlassPane + | BlockKind::CyanStainedGlassPane + | BlockKind::PurpleStainedGlassPane + | BlockKind::BlueStainedGlassPane + | BlockKind::BrownStainedGlassPane + | BlockKind::GreenStainedGlassPane + | BlockKind::RedStainedGlassPane + | BlockKind::BlackStainedGlassPane + | BlockKind::AcaciaStairs + | BlockKind::DarkOakStairs + | BlockKind::IronTrapdoor + | BlockKind::PrismarineStairs + | BlockKind::PrismarineBrickStairs + | BlockKind::DarkPrismarineStairs + | BlockKind::PrismarineSlab + | BlockKind::PrismarineBrickSlab + | BlockKind::DarkPrismarineSlab + | BlockKind::RedSandstoneStairs + | BlockKind::OakSlab + | BlockKind::SpruceSlab + | BlockKind::BirchSlab + | BlockKind::JungleSlab + | BlockKind::AcaciaSlab + | BlockKind::DarkOakSlab + | BlockKind::StoneSlab + | BlockKind::SmoothStoneSlab + | BlockKind::SandstoneSlab + | BlockKind::CutSandstoneSlab + | BlockKind::PetrifiedOakSlab + | BlockKind::CobblestoneSlab + | BlockKind::BrickSlab + | BlockKind::StoneBrickSlab + | BlockKind::NetherBrickSlab + | BlockKind::QuartzSlab + | BlockKind::RedSandstoneSlab + | BlockKind::CutRedSandstoneSlab + | BlockKind::PurpurSlab + | BlockKind::SpruceFence + | BlockKind::BirchFence + | BlockKind::JungleFence + | BlockKind::AcaciaFence + | BlockKind::DarkOakFence + | BlockKind::PurpurStairs + | BlockKind::DeadTubeCoral + | BlockKind::DeadBrainCoral + | BlockKind::DeadBubbleCoral + | BlockKind::DeadFireCoral + | BlockKind::DeadHornCoral + | BlockKind::TubeCoral + | BlockKind::BrainCoral + | BlockKind::BubbleCoral + | BlockKind::FireCoral + | BlockKind::HornCoral + | BlockKind::DeadTubeCoralFan + | BlockKind::DeadBrainCoralFan + | BlockKind::DeadBubbleCoralFan + | BlockKind::DeadFireCoralFan + | BlockKind::DeadHornCoralFan + | BlockKind::TubeCoralFan + | BlockKind::BrainCoralFan + | BlockKind::BubbleCoralFan + | BlockKind::FireCoralFan + | BlockKind::HornCoralFan + | BlockKind::DeadTubeCoralWallFan + | BlockKind::DeadBrainCoralWallFan + | BlockKind::DeadBubbleCoralWallFan + | BlockKind::DeadFireCoralWallFan + | BlockKind::DeadHornCoralWallFan + | BlockKind::TubeCoralWallFan + | BlockKind::BrainCoralWallFan + | BlockKind::BubbleCoralWallFan + | BlockKind::FireCoralWallFan + | BlockKind::HornCoralWallFan + | BlockKind::SeaPickle + | BlockKind::Conduit + | BlockKind::PolishedGraniteStairs + | BlockKind::SmoothRedSandstoneStairs + | BlockKind::MossyStoneBrickStairs + | BlockKind::PolishedDioriteStairs + | BlockKind::MossyCobblestoneStairs + | BlockKind::EndStoneBrickStairs + | BlockKind::StoneStairs + | BlockKind::SmoothSandstoneStairs + | BlockKind::SmoothQuartzStairs + | BlockKind::GraniteStairs + | BlockKind::AndesiteStairs + | BlockKind::RedNetherBrickStairs + | BlockKind::PolishedAndesiteStairs + | BlockKind::DioriteStairs + | BlockKind::PolishedGraniteSlab + | BlockKind::SmoothRedSandstoneSlab + | BlockKind::MossyStoneBrickSlab + | BlockKind::PolishedDioriteSlab + | BlockKind::MossyCobblestoneSlab + | BlockKind::EndStoneBrickSlab + | BlockKind::SmoothSandstoneSlab + | BlockKind::SmoothQuartzSlab + | BlockKind::GraniteSlab + | BlockKind::AndesiteSlab + | BlockKind::RedNetherBrickSlab + | BlockKind::PolishedAndesiteSlab + | BlockKind::DioriteSlab + | BlockKind::BrickWall + | BlockKind::PrismarineWall + | BlockKind::RedSandstoneWall + | BlockKind::MossyStoneBrickWall + | BlockKind::GraniteWall + | BlockKind::StoneBrickWall + | BlockKind::NetherBrickWall + | BlockKind::AndesiteWall + | BlockKind::RedNetherBrickWall + | BlockKind::SandstoneWall + | BlockKind::EndStoneBrickWall + | BlockKind::DioriteWall + | BlockKind::Scaffolding + | BlockKind::Lantern + | BlockKind::SoulLantern + | BlockKind::Campfire + | BlockKind::SoulCampfire + | BlockKind::CrimsonSlab + | BlockKind::WarpedSlab + | BlockKind::CrimsonFence + | BlockKind::WarpedFence + | BlockKind::CrimsonTrapdoor + | BlockKind::WarpedTrapdoor + | BlockKind::CrimsonStairs + | BlockKind::WarpedStairs + | BlockKind::CrimsonSign + | BlockKind::WarpedSign + | BlockKind::CrimsonWallSign + | BlockKind::WarpedWallSign + | BlockKind::BlackstoneStairs + | BlockKind::BlackstoneWall + | BlockKind::BlackstoneSlab + | BlockKind::PolishedBlackstoneBrickSlab + | BlockKind::PolishedBlackstoneBrickStairs + | BlockKind::PolishedBlackstoneBrickWall + | BlockKind::PolishedBlackstoneStairs + | BlockKind::PolishedBlackstoneSlab + | BlockKind::PolishedBlackstoneWall => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `west_connected` property."] + pub fn has_west_connected(self) -> bool { + match self.kind() { + BlockKind::Fire + | BlockKind::OakFence + | BlockKind::BrownMushroomBlock + | BlockKind::RedMushroomBlock + | BlockKind::MushroomStem + | BlockKind::IronBars + | BlockKind::GlassPane + | BlockKind::Vine + | BlockKind::NetherBrickFence + | BlockKind::Tripwire + | BlockKind::WhiteStainedGlassPane + | BlockKind::OrangeStainedGlassPane + | BlockKind::MagentaStainedGlassPane + | BlockKind::LightBlueStainedGlassPane + | BlockKind::YellowStainedGlassPane + | BlockKind::LimeStainedGlassPane + | BlockKind::PinkStainedGlassPane + | BlockKind::GrayStainedGlassPane + | BlockKind::LightGrayStainedGlassPane + | BlockKind::CyanStainedGlassPane + | BlockKind::PurpleStainedGlassPane + | BlockKind::BlueStainedGlassPane + | BlockKind::BrownStainedGlassPane + | BlockKind::GreenStainedGlassPane + | BlockKind::RedStainedGlassPane + | BlockKind::BlackStainedGlassPane + | BlockKind::SpruceFence + | BlockKind::BirchFence + | BlockKind::JungleFence + | BlockKind::AcaciaFence + | BlockKind::DarkOakFence + | BlockKind::ChorusPlant + | BlockKind::CrimsonFence + | BlockKind::WarpedFence => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `west_nlt` property."] + pub fn has_west_nlt(self) -> bool { + match self.kind() { + BlockKind::CobblestoneWall + | BlockKind::MossyCobblestoneWall + | BlockKind::BrickWall + | BlockKind::PrismarineWall + | BlockKind::RedSandstoneWall + | BlockKind::MossyStoneBrickWall + | BlockKind::GraniteWall + | BlockKind::StoneBrickWall + | BlockKind::NetherBrickWall + | BlockKind::AndesiteWall + | BlockKind::RedNetherBrickWall + | BlockKind::SandstoneWall + | BlockKind::EndStoneBrickWall + | BlockKind::DioriteWall + | BlockKind::BlackstoneWall + | BlockKind::PolishedBlackstoneBrickWall + | BlockKind::PolishedBlackstoneWall => true, + _ => false, + } + } + #[doc = "Determines whether or not a block has the `west_wire` property."] + pub fn has_west_wire(self) -> bool { + match self.kind() { + BlockKind::RedstoneWire => true, + _ => false, + } + } +} diff --git a/feather/blocks/src/generated/table.dat b/feather/blocks/src/generated/table.dat new file mode 100644 index 000000000..9033f810e Binary files /dev/null and b/feather/blocks/src/generated/table.dat differ diff --git a/feather/blocks/src/generated/table.rs b/feather/blocks/src/generated/table.rs new file mode 100644 index 000000000..ea078a60b --- /dev/null +++ b/feather/blocks/src/generated/table.rs @@ -0,0 +1,3180 @@ +use crate::BlockKind; +use serde::Deserialize; +use std::convert::TryFrom; +use std::str::FromStr; +#[derive(Debug, Deserialize)] +pub struct BlockTable { + age_0_1: Vec<(u16, u16)>, + age_0_15: Vec<(u16, u16)>, + age_0_2: Vec<(u16, u16)>, + age_0_25: Vec<(u16, u16)>, + age_0_3: Vec<(u16, u16)>, + age_0_5: Vec<(u16, u16)>, + age_0_7: Vec<(u16, u16)>, + attached: Vec<(u16, u16)>, + attachment: Vec<(u16, u16)>, + axis_xyz: Vec<(u16, u16)>, + axis_xz: Vec<(u16, u16)>, + bites: Vec<(u16, u16)>, + bottom: Vec<(u16, u16)>, + cauldron_level: Vec<(u16, u16)>, + charges: Vec<(u16, u16)>, + chest_kind: Vec<(u16, u16)>, + comparator_mode: Vec<(u16, u16)>, + conditional: Vec<(u16, u16)>, + delay: Vec<(u16, u16)>, + disarmed: Vec<(u16, u16)>, + distance_0_7: Vec<(u16, u16)>, + distance_1_7: Vec<(u16, u16)>, + down: Vec<(u16, u16)>, + drag: Vec<(u16, u16)>, + east_connected: Vec<(u16, u16)>, + east_nlt: Vec<(u16, u16)>, + east_wire: Vec<(u16, u16)>, + eggs: Vec<(u16, u16)>, + enabled: Vec<(u16, u16)>, + extended: Vec<(u16, u16)>, + eye: Vec<(u16, u16)>, + face: Vec<(u16, u16)>, + facing_cardinal: Vec<(u16, u16)>, + facing_cardinal_and_down: Vec<(u16, u16)>, + facing_cubic: Vec<(u16, u16)>, + half_top_bottom: Vec<(u16, u16)>, + half_upper_lower: Vec<(u16, u16)>, + hanging: Vec<(u16, u16)>, + has_book: Vec<(u16, u16)>, + has_bottle_0: Vec<(u16, u16)>, + has_bottle_1: Vec<(u16, u16)>, + has_bottle_2: Vec<(u16, u16)>, + has_record: Vec<(u16, u16)>, + hatch: Vec<(u16, u16)>, + hinge: Vec<(u16, u16)>, + honey_level: Vec<(u16, u16)>, + in_wall: Vec<(u16, u16)>, + instrument: Vec<(u16, u16)>, + inverted: Vec<(u16, u16)>, + layers: Vec<(u16, u16)>, + leaves: Vec<(u16, u16)>, + level_0_8: Vec<(u16, u16)>, + lit: Vec<(u16, u16)>, + locked: Vec<(u16, u16)>, + moisture: Vec<(u16, u16)>, + north_connected: Vec<(u16, u16)>, + north_nlt: Vec<(u16, u16)>, + north_wire: Vec<(u16, u16)>, + note: Vec<(u16, u16)>, + occupied: Vec<(u16, u16)>, + open: Vec<(u16, u16)>, + orientation: Vec<(u16, u16)>, + part: Vec<(u16, u16)>, + persistent: Vec<(u16, u16)>, + pickles: Vec<(u16, u16)>, + piston_kind: Vec<(u16, u16)>, + power: Vec<(u16, u16)>, + powered: Vec<(u16, u16)>, + powered_rail_shape: Vec<(u16, u16)>, + rail_shape: Vec<(u16, u16)>, + rotation: Vec<(u16, u16)>, + short: Vec<(u16, u16)>, + signal_fire: Vec<(u16, u16)>, + slab_kind: Vec<(u16, u16)>, + snowy: Vec<(u16, u16)>, + south_connected: Vec<(u16, u16)>, + south_nlt: Vec<(u16, u16)>, + south_wire: Vec<(u16, u16)>, + stage: Vec<(u16, u16)>, + stairs_shape: Vec<(u16, u16)>, + structure_block_mode: Vec<(u16, u16)>, + triggered: Vec<(u16, u16)>, + unstable: Vec<(u16, u16)>, + up: Vec<(u16, u16)>, + water_level: Vec<(u16, u16)>, + waterlogged: Vec<(u16, u16)>, + west_connected: Vec<(u16, u16)>, + west_nlt: Vec<(u16, u16)>, + west_wire: Vec<(u16, u16)>, +} +impl BlockTable { + #[doc = "Retrieves the `age_0_1` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn age_0_1(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.age_0_1[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `age_0_1` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_age_0_1(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.age_0_1[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `age_0_15` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn age_0_15(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.age_0_15[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `age_0_15` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_age_0_15(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.age_0_15[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `age_0_2` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn age_0_2(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.age_0_2[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `age_0_2` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_age_0_2(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.age_0_2[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `age_0_25` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn age_0_25(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.age_0_25[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `age_0_25` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_age_0_25(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.age_0_25[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `age_0_3` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn age_0_3(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.age_0_3[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `age_0_3` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_age_0_3(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.age_0_3[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `age_0_5` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn age_0_5(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.age_0_5[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `age_0_5` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_age_0_5(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.age_0_5[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `age_0_7` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn age_0_7(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.age_0_7[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `age_0_7` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_age_0_7(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.age_0_7[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `attached` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn attached(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.attached[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `attached` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_attached(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.attached[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `attachment` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn attachment(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.attachment[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(Attachment::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `attachment` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_attachment(&self, kind: BlockKind, state: u16, value: Attachment) -> Option { + let (offset_coefficient, stride) = self.attachment[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `axis_xyz` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn axis_xyz(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.axis_xyz[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(AxisXyz::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `axis_xyz` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_axis_xyz(&self, kind: BlockKind, state: u16, value: AxisXyz) -> Option { + let (offset_coefficient, stride) = self.axis_xyz[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `axis_xz` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn axis_xz(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.axis_xz[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(AxisXz::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `axis_xz` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_axis_xz(&self, kind: BlockKind, state: u16, value: AxisXz) -> Option { + let (offset_coefficient, stride) = self.axis_xz[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `bites` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn bites(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.bites[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `bites` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_bites(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.bites[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `bottom` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn bottom(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.bottom[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `bottom` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_bottom(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.bottom[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `cauldron_level` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn cauldron_level(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.cauldron_level[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `cauldron_level` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_cauldron_level(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.cauldron_level[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `charges` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn charges(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.charges[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `charges` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_charges(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.charges[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `chest_kind` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn chest_kind(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.chest_kind[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(ChestKind::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `chest_kind` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_chest_kind(&self, kind: BlockKind, state: u16, value: ChestKind) -> Option { + let (offset_coefficient, stride) = self.chest_kind[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `comparator_mode` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn comparator_mode(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.comparator_mode[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(ComparatorMode::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `comparator_mode` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_comparator_mode( + &self, + kind: BlockKind, + state: u16, + value: ComparatorMode, + ) -> Option { + let (offset_coefficient, stride) = self.comparator_mode[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `conditional` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn conditional(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.conditional[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `conditional` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_conditional(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.conditional[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `delay` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn delay(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.delay[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 1i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `delay` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_delay(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.delay[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 1u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `disarmed` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn disarmed(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.disarmed[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `disarmed` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_disarmed(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.disarmed[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `distance_0_7` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn distance_0_7(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.distance_0_7[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `distance_0_7` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_distance_0_7(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.distance_0_7[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `distance_1_7` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn distance_1_7(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.distance_1_7[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 1i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `distance_1_7` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_distance_1_7(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.distance_1_7[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 1u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `down` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn down(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.down[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `down` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_down(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.down[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `drag` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn drag(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.drag[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `drag` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_drag(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.drag[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `east_connected` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn east_connected(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.east_connected[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `east_connected` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_east_connected(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.east_connected[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `east_nlt` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn east_nlt(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.east_nlt[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(EastNlt::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `east_nlt` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_east_nlt(&self, kind: BlockKind, state: u16, value: EastNlt) -> Option { + let (offset_coefficient, stride) = self.east_nlt[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `east_wire` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn east_wire(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.east_wire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(EastWire::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `east_wire` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_east_wire(&self, kind: BlockKind, state: u16, value: EastWire) -> Option { + let (offset_coefficient, stride) = self.east_wire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `eggs` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn eggs(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.eggs[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 1i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `eggs` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_eggs(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.eggs[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 1u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `enabled` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn enabled(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.enabled[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `enabled` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_enabled(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.enabled[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `extended` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn extended(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.extended[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `extended` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_extended(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.extended[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `eye` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn eye(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.eye[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `eye` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_eye(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.eye[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `face` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn face(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.face[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(Face::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `face` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_face(&self, kind: BlockKind, state: u16, value: Face) -> Option { + let (offset_coefficient, stride) = self.face[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `facing_cardinal` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn facing_cardinal(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.facing_cardinal[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(FacingCardinal::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `facing_cardinal` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_facing_cardinal( + &self, + kind: BlockKind, + state: u16, + value: FacingCardinal, + ) -> Option { + let (offset_coefficient, stride) = self.facing_cardinal[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `facing_cardinal_and_down` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn facing_cardinal_and_down( + &self, + kind: BlockKind, + state: u16, + ) -> Option { + let (offset_coefficient, stride) = self.facing_cardinal_and_down[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(FacingCardinalAndDown::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `facing_cardinal_and_down` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_facing_cardinal_and_down( + &self, + kind: BlockKind, + state: u16, + value: FacingCardinalAndDown, + ) -> Option { + let (offset_coefficient, stride) = self.facing_cardinal_and_down[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `facing_cubic` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn facing_cubic(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.facing_cubic[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(FacingCubic::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `facing_cubic` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_facing_cubic(&self, kind: BlockKind, state: u16, value: FacingCubic) -> Option { + let (offset_coefficient, stride) = self.facing_cubic[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `half_top_bottom` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn half_top_bottom(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.half_top_bottom[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(HalfTopBottom::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `half_top_bottom` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_half_top_bottom( + &self, + kind: BlockKind, + state: u16, + value: HalfTopBottom, + ) -> Option { + let (offset_coefficient, stride) = self.half_top_bottom[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `half_upper_lower` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn half_upper_lower(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.half_upper_lower[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(HalfUpperLower::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `half_upper_lower` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_half_upper_lower( + &self, + kind: BlockKind, + state: u16, + value: HalfUpperLower, + ) -> Option { + let (offset_coefficient, stride) = self.half_upper_lower[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `hanging` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn hanging(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.hanging[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `hanging` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_hanging(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.hanging[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `has_book` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn has_book(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.has_book[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `has_book` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_has_book(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.has_book[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `has_bottle_0` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn has_bottle_0(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.has_bottle_0[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `has_bottle_0` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_has_bottle_0(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.has_bottle_0[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `has_bottle_1` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn has_bottle_1(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.has_bottle_1[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `has_bottle_1` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_has_bottle_1(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.has_bottle_1[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `has_bottle_2` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn has_bottle_2(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.has_bottle_2[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `has_bottle_2` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_has_bottle_2(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.has_bottle_2[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `has_record` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn has_record(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.has_record[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `has_record` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_has_record(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.has_record[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `hatch` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn hatch(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.hatch[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `hatch` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_hatch(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.hatch[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `hinge` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn hinge(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.hinge[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(Hinge::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `hinge` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_hinge(&self, kind: BlockKind, state: u16, value: Hinge) -> Option { + let (offset_coefficient, stride) = self.hinge[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `honey_level` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn honey_level(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.honey_level[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `honey_level` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_honey_level(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.honey_level[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `in_wall` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn in_wall(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.in_wall[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `in_wall` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_in_wall(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.in_wall[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `instrument` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn instrument(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.instrument[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(Instrument::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `instrument` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_instrument(&self, kind: BlockKind, state: u16, value: Instrument) -> Option { + let (offset_coefficient, stride) = self.instrument[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `inverted` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn inverted(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.inverted[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `inverted` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_inverted(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.inverted[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `layers` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn layers(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.layers[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 1i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `layers` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_layers(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.layers[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 1u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `leaves` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn leaves(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.leaves[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(Leaves::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `leaves` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_leaves(&self, kind: BlockKind, state: u16, value: Leaves) -> Option { + let (offset_coefficient, stride) = self.leaves[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `level_0_8` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn level_0_8(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.level_0_8[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `level_0_8` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_level_0_8(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.level_0_8[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `lit` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn lit(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.lit[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `lit` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_lit(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.lit[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `locked` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn locked(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.locked[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `locked` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_locked(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.locked[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `moisture` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn moisture(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.moisture[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `moisture` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_moisture(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.moisture[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `north_connected` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn north_connected(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.north_connected[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `north_connected` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_north_connected(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.north_connected[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `north_nlt` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn north_nlt(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.north_nlt[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(NorthNlt::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `north_nlt` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_north_nlt(&self, kind: BlockKind, state: u16, value: NorthNlt) -> Option { + let (offset_coefficient, stride) = self.north_nlt[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `north_wire` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn north_wire(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.north_wire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(NorthWire::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `north_wire` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_north_wire(&self, kind: BlockKind, state: u16, value: NorthWire) -> Option { + let (offset_coefficient, stride) = self.north_wire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `note` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn note(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.note[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `note` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_note(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.note[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `occupied` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn occupied(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.occupied[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `occupied` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_occupied(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.occupied[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `open` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn open(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.open[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `open` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_open(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.open[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `orientation` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn orientation(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.orientation[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(Orientation::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `orientation` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_orientation(&self, kind: BlockKind, state: u16, value: Orientation) -> Option { + let (offset_coefficient, stride) = self.orientation[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `part` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn part(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.part[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(Part::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `part` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_part(&self, kind: BlockKind, state: u16, value: Part) -> Option { + let (offset_coefficient, stride) = self.part[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `persistent` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn persistent(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.persistent[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `persistent` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_persistent(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.persistent[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `pickles` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn pickles(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.pickles[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 1i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `pickles` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_pickles(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.pickles[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 1u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `piston_kind` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn piston_kind(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.piston_kind[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(PistonKind::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `piston_kind` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_piston_kind(&self, kind: BlockKind, state: u16, value: PistonKind) -> Option { + let (offset_coefficient, stride) = self.piston_kind[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `power` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn power(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.power[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `power` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_power(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.power[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `powered` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn powered(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.powered[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `powered` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_powered(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.powered[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `powered_rail_shape` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn powered_rail_shape(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.powered_rail_shape[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(PoweredRailShape::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `powered_rail_shape` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_powered_rail_shape( + &self, + kind: BlockKind, + state: u16, + value: PoweredRailShape, + ) -> Option { + let (offset_coefficient, stride) = self.powered_rail_shape[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `rail_shape` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn rail_shape(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.rail_shape[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(RailShape::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `rail_shape` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_rail_shape(&self, kind: BlockKind, state: u16, value: RailShape) -> Option { + let (offset_coefficient, stride) = self.rail_shape[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `rotation` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn rotation(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.rotation[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `rotation` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_rotation(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.rotation[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `short` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn short(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.short[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `short` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_short(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.short[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `signal_fire` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn signal_fire(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.signal_fire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `signal_fire` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_signal_fire(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.signal_fire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `slab_kind` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn slab_kind(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.slab_kind[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(SlabKind::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `slab_kind` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_slab_kind(&self, kind: BlockKind, state: u16, value: SlabKind) -> Option { + let (offset_coefficient, stride) = self.slab_kind[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `snowy` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn snowy(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.snowy[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `snowy` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_snowy(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.snowy[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `south_connected` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn south_connected(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.south_connected[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `south_connected` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_south_connected(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.south_connected[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `south_nlt` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn south_nlt(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.south_nlt[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(SouthNlt::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `south_nlt` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_south_nlt(&self, kind: BlockKind, state: u16, value: SouthNlt) -> Option { + let (offset_coefficient, stride) = self.south_nlt[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `south_wire` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn south_wire(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.south_wire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(SouthWire::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `south_wire` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_south_wire(&self, kind: BlockKind, state: u16, value: SouthWire) -> Option { + let (offset_coefficient, stride) = self.south_wire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `stage` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn stage(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.stage[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `stage` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_stage(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.stage[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `stairs_shape` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn stairs_shape(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.stairs_shape[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(StairsShape::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `stairs_shape` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_stairs_shape(&self, kind: BlockKind, state: u16, value: StairsShape) -> Option { + let (offset_coefficient, stride) = self.stairs_shape[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `structure_block_mode` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn structure_block_mode(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.structure_block_mode[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(StructureBlockMode::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `structure_block_mode` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_structure_block_mode( + &self, + kind: BlockKind, + state: u16, + value: StructureBlockMode, + ) -> Option { + let (offset_coefficient, stride) = self.structure_block_mode[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `triggered` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn triggered(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.triggered[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `triggered` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_triggered(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.triggered[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `unstable` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn unstable(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.unstable[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `unstable` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_unstable(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.unstable[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `up` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn up(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.up[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `up` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_up(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.up[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `water_level` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn water_level(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.water_level[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some({ x as i32 + 0i32 }) + } + #[doc = "Updates the state value for the given block kind such that its `water_level` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_water_level(&self, kind: BlockKind, state: u16, value: i32) -> Option { + let (offset_coefficient, stride) = self.water_level[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 - 0u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `waterlogged` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn waterlogged(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.waterlogged[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `waterlogged` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_waterlogged(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.waterlogged[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `west_connected` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn west_connected(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.west_connected[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(if x == 0 { false } else { true }) + } + #[doc = "Updates the state value for the given block kind such that its `west_connected` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_west_connected(&self, kind: BlockKind, state: u16, value: bool) -> Option { + let (offset_coefficient, stride) = self.west_connected[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `west_nlt` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn west_nlt(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.west_nlt[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(WestNlt::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `west_nlt` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_west_nlt(&self, kind: BlockKind, state: u16, value: WestNlt) -> Option { + let (offset_coefficient, stride) = self.west_nlt[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } + #[doc = "Retrieves the `west_wire` value for the given block kind with the given state value.\n Returns the value of the property, or `None` if it does not exist."] + pub fn west_wire(&self, kind: BlockKind, state: u16) -> Option { + let (offset_coefficient, stride) = self.west_wire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let x = crate::n_dimensional_index(state, offset_coefficient, stride); + Some(WestWire::try_from(x).expect("invalid block state")) + } + #[doc = "Updates the state value for the given block kind such that its `west_wire` value is updated. Returns the new state,\n or `None` if the block does not have this property."] + pub fn set_west_wire(&self, kind: BlockKind, state: u16, value: WestWire) -> Option { + let (offset_coefficient, stride) = self.west_wire[kind as u16 as usize]; + if offset_coefficient == 0 { + return None; + } + let old = crate::n_dimensional_index(state, offset_coefficient, stride) as i32; + let new = ({ value as u16 } as i32 - old) * stride as i32 + state as i32; + Some(new as u16) + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum Attachment { + Floor, + Ceiling, + SingleWall, + DoubleWall, +} +impl TryFrom for Attachment { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(Attachment::Floor), + 1u16 => Ok(Attachment::Ceiling), + 2u16 => Ok(Attachment::SingleWall), + 3u16 => Ok(Attachment::DoubleWall), + x => Err(anyhow::anyhow!("invalid value {} for Attachment", x)), + } + } +} +impl FromStr for Attachment { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "floor" => Ok(Attachment::Floor), + "ceiling" => Ok(Attachment::Ceiling), + "single_wall" => Ok(Attachment::SingleWall), + "double_wall" => Ok(Attachment::DoubleWall), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(Attachment) + )), + } + } +} +impl Attachment { + pub fn as_str(self) -> &'static str { + match self { + Attachment::Floor => "floor", + Attachment::Ceiling => "ceiling", + Attachment::SingleWall => "single_wall", + Attachment::DoubleWall => "double_wall", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum AxisXyz { + X, + Y, + Z, +} +impl TryFrom for AxisXyz { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(AxisXyz::X), + 1u16 => Ok(AxisXyz::Y), + 2u16 => Ok(AxisXyz::Z), + x => Err(anyhow::anyhow!("invalid value {} for AxisXyz", x)), + } + } +} +impl FromStr for AxisXyz { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "x" => Ok(AxisXyz::X), + "y" => Ok(AxisXyz::Y), + "z" => Ok(AxisXyz::Z), + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(AxisXyz))), + } + } +} +impl AxisXyz { + pub fn as_str(self) -> &'static str { + match self { + AxisXyz::X => "x", + AxisXyz::Y => "y", + AxisXyz::Z => "z", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum AxisXz { + X, + Z, +} +impl TryFrom for AxisXz { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(AxisXz::X), + 1u16 => Ok(AxisXz::Z), + x => Err(anyhow::anyhow!("invalid value {} for AxisXz", x)), + } + } +} +impl FromStr for AxisXz { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "x" => Ok(AxisXz::X), + "z" => Ok(AxisXz::Z), + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(AxisXz))), + } + } +} +impl AxisXz { + pub fn as_str(self) -> &'static str { + match self { + AxisXz::X => "x", + AxisXz::Z => "z", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum ChestKind { + Single, + Left, + Right, +} +impl TryFrom for ChestKind { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(ChestKind::Single), + 1u16 => Ok(ChestKind::Left), + 2u16 => Ok(ChestKind::Right), + x => Err(anyhow::anyhow!("invalid value {} for ChestKind", x)), + } + } +} +impl FromStr for ChestKind { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "single" => Ok(ChestKind::Single), + "left" => Ok(ChestKind::Left), + "right" => Ok(ChestKind::Right), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(ChestKind) + )), + } + } +} +impl ChestKind { + pub fn as_str(self) -> &'static str { + match self { + ChestKind::Single => "single", + ChestKind::Left => "left", + ChestKind::Right => "right", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum ComparatorMode { + Compare, + Subtract, +} +impl TryFrom for ComparatorMode { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(ComparatorMode::Compare), + 1u16 => Ok(ComparatorMode::Subtract), + x => Err(anyhow::anyhow!("invalid value {} for ComparatorMode", x)), + } + } +} +impl FromStr for ComparatorMode { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "compare" => Ok(ComparatorMode::Compare), + "subtract" => Ok(ComparatorMode::Subtract), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(ComparatorMode) + )), + } + } +} +impl ComparatorMode { + pub fn as_str(self) -> &'static str { + match self { + ComparatorMode::Compare => "compare", + ComparatorMode::Subtract => "subtract", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum EastNlt { + None, + Low, + Tall, +} +impl TryFrom for EastNlt { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(EastNlt::None), + 1u16 => Ok(EastNlt::Low), + 2u16 => Ok(EastNlt::Tall), + x => Err(anyhow::anyhow!("invalid value {} for EastNlt", x)), + } + } +} +impl FromStr for EastNlt { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "none" => Ok(EastNlt::None), + "low" => Ok(EastNlt::Low), + "tall" => Ok(EastNlt::Tall), + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(EastNlt))), + } + } +} +impl EastNlt { + pub fn as_str(self) -> &'static str { + match self { + EastNlt::None => "none", + EastNlt::Low => "low", + EastNlt::Tall => "tall", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum EastWire { + Up, + Side, + None, +} +impl TryFrom for EastWire { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(EastWire::Up), + 1u16 => Ok(EastWire::Side), + 2u16 => Ok(EastWire::None), + x => Err(anyhow::anyhow!("invalid value {} for EastWire", x)), + } + } +} +impl FromStr for EastWire { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "up" => Ok(EastWire::Up), + "side" => Ok(EastWire::Side), + "none" => Ok(EastWire::None), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(EastWire) + )), + } + } +} +impl EastWire { + pub fn as_str(self) -> &'static str { + match self { + EastWire::Up => "up", + EastWire::Side => "side", + EastWire::None => "none", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum Face { + Floor, + Wall, + Ceiling, +} +impl TryFrom for Face { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(Face::Floor), + 1u16 => Ok(Face::Wall), + 2u16 => Ok(Face::Ceiling), + x => Err(anyhow::anyhow!("invalid value {} for Face", x)), + } + } +} +impl FromStr for Face { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "floor" => Ok(Face::Floor), + "wall" => Ok(Face::Wall), + "ceiling" => Ok(Face::Ceiling), + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(Face))), + } + } +} +impl Face { + pub fn as_str(self) -> &'static str { + match self { + Face::Floor => "floor", + Face::Wall => "wall", + Face::Ceiling => "ceiling", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum FacingCardinal { + North, + South, + West, + East, +} +impl TryFrom for FacingCardinal { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(FacingCardinal::North), + 1u16 => Ok(FacingCardinal::South), + 2u16 => Ok(FacingCardinal::West), + 3u16 => Ok(FacingCardinal::East), + x => Err(anyhow::anyhow!("invalid value {} for FacingCardinal", x)), + } + } +} +impl FromStr for FacingCardinal { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "north" => Ok(FacingCardinal::North), + "south" => Ok(FacingCardinal::South), + "west" => Ok(FacingCardinal::West), + "east" => Ok(FacingCardinal::East), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(FacingCardinal) + )), + } + } +} +impl FacingCardinal { + pub fn as_str(self) -> &'static str { + match self { + FacingCardinal::North => "north", + FacingCardinal::South => "south", + FacingCardinal::West => "west", + FacingCardinal::East => "east", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum FacingCardinalAndDown { + Down, + North, + South, + West, + East, +} +impl TryFrom for FacingCardinalAndDown { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(FacingCardinalAndDown::Down), + 1u16 => Ok(FacingCardinalAndDown::North), + 2u16 => Ok(FacingCardinalAndDown::South), + 3u16 => Ok(FacingCardinalAndDown::West), + 4u16 => Ok(FacingCardinalAndDown::East), + x => Err(anyhow::anyhow!( + "invalid value {} for FacingCardinalAndDown", + x + )), + } + } +} +impl FromStr for FacingCardinalAndDown { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "down" => Ok(FacingCardinalAndDown::Down), + "north" => Ok(FacingCardinalAndDown::North), + "south" => Ok(FacingCardinalAndDown::South), + "west" => Ok(FacingCardinalAndDown::West), + "east" => Ok(FacingCardinalAndDown::East), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(FacingCardinalAndDown) + )), + } + } +} +impl FacingCardinalAndDown { + pub fn as_str(self) -> &'static str { + match self { + FacingCardinalAndDown::Down => "down", + FacingCardinalAndDown::North => "north", + FacingCardinalAndDown::South => "south", + FacingCardinalAndDown::West => "west", + FacingCardinalAndDown::East => "east", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum FacingCubic { + North, + East, + South, + West, + Up, + Down, +} +impl TryFrom for FacingCubic { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(FacingCubic::North), + 1u16 => Ok(FacingCubic::East), + 2u16 => Ok(FacingCubic::South), + 3u16 => Ok(FacingCubic::West), + 4u16 => Ok(FacingCubic::Up), + 5u16 => Ok(FacingCubic::Down), + x => Err(anyhow::anyhow!("invalid value {} for FacingCubic", x)), + } + } +} +impl FromStr for FacingCubic { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "north" => Ok(FacingCubic::North), + "east" => Ok(FacingCubic::East), + "south" => Ok(FacingCubic::South), + "west" => Ok(FacingCubic::West), + "up" => Ok(FacingCubic::Up), + "down" => Ok(FacingCubic::Down), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(FacingCubic) + )), + } + } +} +impl FacingCubic { + pub fn as_str(self) -> &'static str { + match self { + FacingCubic::North => "north", + FacingCubic::East => "east", + FacingCubic::South => "south", + FacingCubic::West => "west", + FacingCubic::Up => "up", + FacingCubic::Down => "down", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum HalfTopBottom { + Top, + Bottom, +} +impl TryFrom for HalfTopBottom { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(HalfTopBottom::Top), + 1u16 => Ok(HalfTopBottom::Bottom), + x => Err(anyhow::anyhow!("invalid value {} for HalfTopBottom", x)), + } + } +} +impl FromStr for HalfTopBottom { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "top" => Ok(HalfTopBottom::Top), + "bottom" => Ok(HalfTopBottom::Bottom), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(HalfTopBottom) + )), + } + } +} +impl HalfTopBottom { + pub fn as_str(self) -> &'static str { + match self { + HalfTopBottom::Top => "top", + HalfTopBottom::Bottom => "bottom", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum HalfUpperLower { + Upper, + Lower, +} +impl TryFrom for HalfUpperLower { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(HalfUpperLower::Upper), + 1u16 => Ok(HalfUpperLower::Lower), + x => Err(anyhow::anyhow!("invalid value {} for HalfUpperLower", x)), + } + } +} +impl FromStr for HalfUpperLower { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "upper" => Ok(HalfUpperLower::Upper), + "lower" => Ok(HalfUpperLower::Lower), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(HalfUpperLower) + )), + } + } +} +impl HalfUpperLower { + pub fn as_str(self) -> &'static str { + match self { + HalfUpperLower::Upper => "upper", + HalfUpperLower::Lower => "lower", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum Hinge { + Left, + Right, +} +impl TryFrom for Hinge { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(Hinge::Left), + 1u16 => Ok(Hinge::Right), + x => Err(anyhow::anyhow!("invalid value {} for Hinge", x)), + } + } +} +impl FromStr for Hinge { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "left" => Ok(Hinge::Left), + "right" => Ok(Hinge::Right), + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(Hinge))), + } + } +} +impl Hinge { + pub fn as_str(self) -> &'static str { + match self { + Hinge::Left => "left", + Hinge::Right => "right", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum Instrument { + Harp, + Basedrum, + Snare, + Hat, + Bass, + Flute, + Bell, + Guitar, + Chime, + Xylophone, + IronXylophone, + CowBell, + Didgeridoo, + Bit, + Banjo, + Pling, +} +impl TryFrom for Instrument { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(Instrument::Harp), + 1u16 => Ok(Instrument::Basedrum), + 2u16 => Ok(Instrument::Snare), + 3u16 => Ok(Instrument::Hat), + 4u16 => Ok(Instrument::Bass), + 5u16 => Ok(Instrument::Flute), + 6u16 => Ok(Instrument::Bell), + 7u16 => Ok(Instrument::Guitar), + 8u16 => Ok(Instrument::Chime), + 9u16 => Ok(Instrument::Xylophone), + 10u16 => Ok(Instrument::IronXylophone), + 11u16 => Ok(Instrument::CowBell), + 12u16 => Ok(Instrument::Didgeridoo), + 13u16 => Ok(Instrument::Bit), + 14u16 => Ok(Instrument::Banjo), + 15u16 => Ok(Instrument::Pling), + x => Err(anyhow::anyhow!("invalid value {} for Instrument", x)), + } + } +} +impl FromStr for Instrument { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "harp" => Ok(Instrument::Harp), + "basedrum" => Ok(Instrument::Basedrum), + "snare" => Ok(Instrument::Snare), + "hat" => Ok(Instrument::Hat), + "bass" => Ok(Instrument::Bass), + "flute" => Ok(Instrument::Flute), + "bell" => Ok(Instrument::Bell), + "guitar" => Ok(Instrument::Guitar), + "chime" => Ok(Instrument::Chime), + "xylophone" => Ok(Instrument::Xylophone), + "iron_xylophone" => Ok(Instrument::IronXylophone), + "cow_bell" => Ok(Instrument::CowBell), + "didgeridoo" => Ok(Instrument::Didgeridoo), + "bit" => Ok(Instrument::Bit), + "banjo" => Ok(Instrument::Banjo), + "pling" => Ok(Instrument::Pling), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(Instrument) + )), + } + } +} +impl Instrument { + pub fn as_str(self) -> &'static str { + match self { + Instrument::Harp => "harp", + Instrument::Basedrum => "basedrum", + Instrument::Snare => "snare", + Instrument::Hat => "hat", + Instrument::Bass => "bass", + Instrument::Flute => "flute", + Instrument::Bell => "bell", + Instrument::Guitar => "guitar", + Instrument::Chime => "chime", + Instrument::Xylophone => "xylophone", + Instrument::IronXylophone => "iron_xylophone", + Instrument::CowBell => "cow_bell", + Instrument::Didgeridoo => "didgeridoo", + Instrument::Bit => "bit", + Instrument::Banjo => "banjo", + Instrument::Pling => "pling", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum Leaves { + None, + Small, + Large, +} +impl TryFrom for Leaves { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(Leaves::None), + 1u16 => Ok(Leaves::Small), + 2u16 => Ok(Leaves::Large), + x => Err(anyhow::anyhow!("invalid value {} for Leaves", x)), + } + } +} +impl FromStr for Leaves { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "none" => Ok(Leaves::None), + "small" => Ok(Leaves::Small), + "large" => Ok(Leaves::Large), + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(Leaves))), + } + } +} +impl Leaves { + pub fn as_str(self) -> &'static str { + match self { + Leaves::None => "none", + Leaves::Small => "small", + Leaves::Large => "large", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum NorthNlt { + None, + Low, + Tall, +} +impl TryFrom for NorthNlt { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(NorthNlt::None), + 1u16 => Ok(NorthNlt::Low), + 2u16 => Ok(NorthNlt::Tall), + x => Err(anyhow::anyhow!("invalid value {} for NorthNlt", x)), + } + } +} +impl FromStr for NorthNlt { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "none" => Ok(NorthNlt::None), + "low" => Ok(NorthNlt::Low), + "tall" => Ok(NorthNlt::Tall), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(NorthNlt) + )), + } + } +} +impl NorthNlt { + pub fn as_str(self) -> &'static str { + match self { + NorthNlt::None => "none", + NorthNlt::Low => "low", + NorthNlt::Tall => "tall", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum NorthWire { + Up, + Side, + None, +} +impl TryFrom for NorthWire { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(NorthWire::Up), + 1u16 => Ok(NorthWire::Side), + 2u16 => Ok(NorthWire::None), + x => Err(anyhow::anyhow!("invalid value {} for NorthWire", x)), + } + } +} +impl FromStr for NorthWire { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "up" => Ok(NorthWire::Up), + "side" => Ok(NorthWire::Side), + "none" => Ok(NorthWire::None), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(NorthWire) + )), + } + } +} +impl NorthWire { + pub fn as_str(self) -> &'static str { + match self { + NorthWire::Up => "up", + NorthWire::Side => "side", + NorthWire::None => "none", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum Orientation { + DownEast, + DownNorth, + DownSouth, + DownWest, + UpEast, + UpNorth, + UpSouth, + UpWest, + WestUp, + EastUp, + NorthUp, + SouthUp, +} +impl TryFrom for Orientation { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(Orientation::DownEast), + 1u16 => Ok(Orientation::DownNorth), + 2u16 => Ok(Orientation::DownSouth), + 3u16 => Ok(Orientation::DownWest), + 4u16 => Ok(Orientation::UpEast), + 5u16 => Ok(Orientation::UpNorth), + 6u16 => Ok(Orientation::UpSouth), + 7u16 => Ok(Orientation::UpWest), + 8u16 => Ok(Orientation::WestUp), + 9u16 => Ok(Orientation::EastUp), + 10u16 => Ok(Orientation::NorthUp), + 11u16 => Ok(Orientation::SouthUp), + x => Err(anyhow::anyhow!("invalid value {} for Orientation", x)), + } + } +} +impl FromStr for Orientation { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "down_east" => Ok(Orientation::DownEast), + "down_north" => Ok(Orientation::DownNorth), + "down_south" => Ok(Orientation::DownSouth), + "down_west" => Ok(Orientation::DownWest), + "up_east" => Ok(Orientation::UpEast), + "up_north" => Ok(Orientation::UpNorth), + "up_south" => Ok(Orientation::UpSouth), + "up_west" => Ok(Orientation::UpWest), + "west_up" => Ok(Orientation::WestUp), + "east_up" => Ok(Orientation::EastUp), + "north_up" => Ok(Orientation::NorthUp), + "south_up" => Ok(Orientation::SouthUp), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(Orientation) + )), + } + } +} +impl Orientation { + pub fn as_str(self) -> &'static str { + match self { + Orientation::DownEast => "down_east", + Orientation::DownNorth => "down_north", + Orientation::DownSouth => "down_south", + Orientation::DownWest => "down_west", + Orientation::UpEast => "up_east", + Orientation::UpNorth => "up_north", + Orientation::UpSouth => "up_south", + Orientation::UpWest => "up_west", + Orientation::WestUp => "west_up", + Orientation::EastUp => "east_up", + Orientation::NorthUp => "north_up", + Orientation::SouthUp => "south_up", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum Part { + Head, + Foot, +} +impl TryFrom for Part { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(Part::Head), + 1u16 => Ok(Part::Foot), + x => Err(anyhow::anyhow!("invalid value {} for Part", x)), + } + } +} +impl FromStr for Part { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "head" => Ok(Part::Head), + "foot" => Ok(Part::Foot), + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(Part))), + } + } +} +impl Part { + pub fn as_str(self) -> &'static str { + match self { + Part::Head => "head", + Part::Foot => "foot", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum PistonKind { + Normal, + Sticky, +} +impl TryFrom for PistonKind { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(PistonKind::Normal), + 1u16 => Ok(PistonKind::Sticky), + x => Err(anyhow::anyhow!("invalid value {} for PistonKind", x)), + } + } +} +impl FromStr for PistonKind { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "normal" => Ok(PistonKind::Normal), + "sticky" => Ok(PistonKind::Sticky), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(PistonKind) + )), + } + } +} +impl PistonKind { + pub fn as_str(self) -> &'static str { + match self { + PistonKind::Normal => "normal", + PistonKind::Sticky => "sticky", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum PoweredRailShape { + NorthSouth, + EastWest, + AscendingEast, + AscendingWest, + AscendingNorth, + AscendingSouth, +} +impl TryFrom for PoweredRailShape { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(PoweredRailShape::NorthSouth), + 1u16 => Ok(PoweredRailShape::EastWest), + 2u16 => Ok(PoweredRailShape::AscendingEast), + 3u16 => Ok(PoweredRailShape::AscendingWest), + 4u16 => Ok(PoweredRailShape::AscendingNorth), + 5u16 => Ok(PoweredRailShape::AscendingSouth), + x => Err(anyhow::anyhow!("invalid value {} for PoweredRailShape", x)), + } + } +} +impl FromStr for PoweredRailShape { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "north_south" => Ok(PoweredRailShape::NorthSouth), + "east_west" => Ok(PoweredRailShape::EastWest), + "ascending_east" => Ok(PoweredRailShape::AscendingEast), + "ascending_west" => Ok(PoweredRailShape::AscendingWest), + "ascending_north" => Ok(PoweredRailShape::AscendingNorth), + "ascending_south" => Ok(PoweredRailShape::AscendingSouth), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(PoweredRailShape) + )), + } + } +} +impl PoweredRailShape { + pub fn as_str(self) -> &'static str { + match self { + PoweredRailShape::NorthSouth => "north_south", + PoweredRailShape::EastWest => "east_west", + PoweredRailShape::AscendingEast => "ascending_east", + PoweredRailShape::AscendingWest => "ascending_west", + PoweredRailShape::AscendingNorth => "ascending_north", + PoweredRailShape::AscendingSouth => "ascending_south", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum RailShape { + NorthSouth, + EastWest, + AscendingEast, + AscendingWest, + AscendingNorth, + AscendingSouth, + SouthEast, + SouthWest, + NorthWest, + NorthEast, +} +impl TryFrom for RailShape { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(RailShape::NorthSouth), + 1u16 => Ok(RailShape::EastWest), + 2u16 => Ok(RailShape::AscendingEast), + 3u16 => Ok(RailShape::AscendingWest), + 4u16 => Ok(RailShape::AscendingNorth), + 5u16 => Ok(RailShape::AscendingSouth), + 6u16 => Ok(RailShape::SouthEast), + 7u16 => Ok(RailShape::SouthWest), + 8u16 => Ok(RailShape::NorthWest), + 9u16 => Ok(RailShape::NorthEast), + x => Err(anyhow::anyhow!("invalid value {} for RailShape", x)), + } + } +} +impl FromStr for RailShape { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "north_south" => Ok(RailShape::NorthSouth), + "east_west" => Ok(RailShape::EastWest), + "ascending_east" => Ok(RailShape::AscendingEast), + "ascending_west" => Ok(RailShape::AscendingWest), + "ascending_north" => Ok(RailShape::AscendingNorth), + "ascending_south" => Ok(RailShape::AscendingSouth), + "south_east" => Ok(RailShape::SouthEast), + "south_west" => Ok(RailShape::SouthWest), + "north_west" => Ok(RailShape::NorthWest), + "north_east" => Ok(RailShape::NorthEast), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(RailShape) + )), + } + } +} +impl RailShape { + pub fn as_str(self) -> &'static str { + match self { + RailShape::NorthSouth => "north_south", + RailShape::EastWest => "east_west", + RailShape::AscendingEast => "ascending_east", + RailShape::AscendingWest => "ascending_west", + RailShape::AscendingNorth => "ascending_north", + RailShape::AscendingSouth => "ascending_south", + RailShape::SouthEast => "south_east", + RailShape::SouthWest => "south_west", + RailShape::NorthWest => "north_west", + RailShape::NorthEast => "north_east", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum SlabKind { + Top, + Bottom, + Double, +} +impl TryFrom for SlabKind { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(SlabKind::Top), + 1u16 => Ok(SlabKind::Bottom), + 2u16 => Ok(SlabKind::Double), + x => Err(anyhow::anyhow!("invalid value {} for SlabKind", x)), + } + } +} +impl FromStr for SlabKind { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "top" => Ok(SlabKind::Top), + "bottom" => Ok(SlabKind::Bottom), + "double" => Ok(SlabKind::Double), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(SlabKind) + )), + } + } +} +impl SlabKind { + pub fn as_str(self) -> &'static str { + match self { + SlabKind::Top => "top", + SlabKind::Bottom => "bottom", + SlabKind::Double => "double", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum SouthNlt { + None, + Low, + Tall, +} +impl TryFrom for SouthNlt { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(SouthNlt::None), + 1u16 => Ok(SouthNlt::Low), + 2u16 => Ok(SouthNlt::Tall), + x => Err(anyhow::anyhow!("invalid value {} for SouthNlt", x)), + } + } +} +impl FromStr for SouthNlt { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "none" => Ok(SouthNlt::None), + "low" => Ok(SouthNlt::Low), + "tall" => Ok(SouthNlt::Tall), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(SouthNlt) + )), + } + } +} +impl SouthNlt { + pub fn as_str(self) -> &'static str { + match self { + SouthNlt::None => "none", + SouthNlt::Low => "low", + SouthNlt::Tall => "tall", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum SouthWire { + Up, + Side, + None, +} +impl TryFrom for SouthWire { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(SouthWire::Up), + 1u16 => Ok(SouthWire::Side), + 2u16 => Ok(SouthWire::None), + x => Err(anyhow::anyhow!("invalid value {} for SouthWire", x)), + } + } +} +impl FromStr for SouthWire { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "up" => Ok(SouthWire::Up), + "side" => Ok(SouthWire::Side), + "none" => Ok(SouthWire::None), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(SouthWire) + )), + } + } +} +impl SouthWire { + pub fn as_str(self) -> &'static str { + match self { + SouthWire::Up => "up", + SouthWire::Side => "side", + SouthWire::None => "none", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum StairsShape { + Straight, + InnerLeft, + InnerRight, + OuterLeft, + OuterRight, +} +impl TryFrom for StairsShape { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(StairsShape::Straight), + 1u16 => Ok(StairsShape::InnerLeft), + 2u16 => Ok(StairsShape::InnerRight), + 3u16 => Ok(StairsShape::OuterLeft), + 4u16 => Ok(StairsShape::OuterRight), + x => Err(anyhow::anyhow!("invalid value {} for StairsShape", x)), + } + } +} +impl FromStr for StairsShape { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "straight" => Ok(StairsShape::Straight), + "inner_left" => Ok(StairsShape::InnerLeft), + "inner_right" => Ok(StairsShape::InnerRight), + "outer_left" => Ok(StairsShape::OuterLeft), + "outer_right" => Ok(StairsShape::OuterRight), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(StairsShape) + )), + } + } +} +impl StairsShape { + pub fn as_str(self) -> &'static str { + match self { + StairsShape::Straight => "straight", + StairsShape::InnerLeft => "inner_left", + StairsShape::InnerRight => "inner_right", + StairsShape::OuterLeft => "outer_left", + StairsShape::OuterRight => "outer_right", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum StructureBlockMode { + Save, + Load, + Corner, + Data, +} +impl TryFrom for StructureBlockMode { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(StructureBlockMode::Save), + 1u16 => Ok(StructureBlockMode::Load), + 2u16 => Ok(StructureBlockMode::Corner), + 3u16 => Ok(StructureBlockMode::Data), + x => Err(anyhow::anyhow!( + "invalid value {} for StructureBlockMode", + x + )), + } + } +} +impl FromStr for StructureBlockMode { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "save" => Ok(StructureBlockMode::Save), + "load" => Ok(StructureBlockMode::Load), + "corner" => Ok(StructureBlockMode::Corner), + "data" => Ok(StructureBlockMode::Data), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(StructureBlockMode) + )), + } + } +} +impl StructureBlockMode { + pub fn as_str(self) -> &'static str { + match self { + StructureBlockMode::Save => "save", + StructureBlockMode::Load => "load", + StructureBlockMode::Corner => "corner", + StructureBlockMode::Data => "data", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum WestNlt { + None, + Low, + Tall, +} +impl TryFrom for WestNlt { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(WestNlt::None), + 1u16 => Ok(WestNlt::Low), + 2u16 => Ok(WestNlt::Tall), + x => Err(anyhow::anyhow!("invalid value {} for WestNlt", x)), + } + } +} +impl FromStr for WestNlt { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "none" => Ok(WestNlt::None), + "low" => Ok(WestNlt::Low), + "tall" => Ok(WestNlt::Tall), + _ => Err(anyhow::anyhow!("invalid value for {}", stringify!(WestNlt))), + } + } +} +impl WestNlt { + pub fn as_str(self) -> &'static str { + match self { + WestNlt::None => "none", + WestNlt::Low => "low", + WestNlt::Tall => "tall", + } + } +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(u16)] +pub enum WestWire { + Up, + Side, + None, +} +impl TryFrom for WestWire { + type Error = anyhow::Error; + fn try_from(value: u16) -> anyhow::Result { + match value { + 0u16 => Ok(WestWire::Up), + 1u16 => Ok(WestWire::Side), + 2u16 => Ok(WestWire::None), + x => Err(anyhow::anyhow!("invalid value {} for WestWire", x)), + } + } +} +impl FromStr for WestWire { + type Err = anyhow::Error; + fn from_str(s: &str) -> anyhow::Result { + match s { + "up" => Ok(WestWire::Up), + "side" => Ok(WestWire::Side), + "none" => Ok(WestWire::None), + _ => Err(anyhow::anyhow!( + "invalid value for {}", + stringify!(WestWire) + )), + } + } +} +impl WestWire { + pub fn as_str(self) -> &'static str { + match self { + WestWire::Up => "up", + WestWire::Side => "side", + WestWire::None => "none", + } + } +} diff --git a/feather/blocks/src/generated/vanilla_ids.dat b/feather/blocks/src/generated/vanilla_ids.dat new file mode 100644 index 000000000..fd1c60abd Binary files /dev/null and b/feather/blocks/src/generated/vanilla_ids.dat differ diff --git a/feather/blocks/src/lib.rs b/feather/blocks/src/lib.rs new file mode 100644 index 000000000..f8cf91187 --- /dev/null +++ b/feather/blocks/src/lib.rs @@ -0,0 +1,229 @@ +pub use libcraft_blocks::{BlockKind, SimplifiedBlockKind}; +use num_traits::FromPrimitive; +use std::convert::TryFrom; +use thiserror::Error; + +pub mod categories; +mod directions; +#[allow(warnings)] +#[allow(clippy::all)] +mod generated; +mod wall_blocks; + +static BLOCK_TABLE: Lazy = Lazy::new(|| { + let bytes = include_bytes!("generated/table.dat"); + bincode::deserialize(bytes).expect("failed to deserialize generated block table (bincode)") +}); + +static VANILLA_ID_TABLE: Lazy>> = Lazy::new(|| { + let bytes = include_bytes!("generated/vanilla_ids.dat"); + bincode::deserialize(bytes).expect("failed to deserialize generated vanilla ID table (bincode)") +}); + +pub const HIGHEST_ID: u16 = 17111; + +static FROM_VANILLA_ID_TABLE: Lazy> = Lazy::new(|| { + let mut res = vec![BlockId::default(); u16::max_value() as usize]; + + for (kind_id, ids) in VANILLA_ID_TABLE.iter().enumerate() { + let kind = BlockKind::from_u16(kind_id as u16).expect("invalid block kind ID"); + + for (state, id) in ids.iter().enumerate() { + res[*id as usize] = BlockId { + state: state as u16, + kind, + }; + } + } + + debug_assert!((1..=HIGHEST_ID).all(|id| res[id as usize] != BlockId::default())); + // Verify distinction + if cfg!(debug_assertions) { + let mut known_blocks = HashSet::with_capacity(HIGHEST_ID as usize); + assert!((1..=HIGHEST_ID).all(|id| known_blocks.insert(res[id as usize]))); + } + + res +}); + +/// Can be called at startup to pre-initialize the global block table. +pub fn init() { + Lazy::force(&FROM_VANILLA_ID_TABLE); + Lazy::force(&BLOCK_TABLE); +} + +use once_cell::sync::Lazy; + +pub use crate::generated::table::*; + +use std::collections::HashSet; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct BlockId { + kind: BlockKind, + state: u16, +} + +impl Default for BlockId { + fn default() -> Self { + BlockId { + kind: BlockKind::Air, + state: 0, + } + } +} + +impl BlockId { + /// Returns the kind of this block. + pub fn kind(self) -> BlockKind { + self.kind + } + + /// Returns the simplified kind of this block. + /// This is an arbitrary manual mapping that aims to condense the different + /// vanilla block kinds which have only minor differences (e.g. different colored beds) + /// and is mainly intended to make `match`ing on the block type easier. + /// This mapping in no way stable right now. + pub fn simplified_kind(self) -> SimplifiedBlockKind { + self.kind.simplified_kind() + } + + /// Returns the vanilla state ID for this block. + pub fn vanilla_id(self) -> u16 { + VANILLA_ID_TABLE[self.kind as u16 as usize][self.state as usize] + } + + /* + /// Returns the vanilla fluid ID for this block in case it is a fluid. + /// The fluid ID is used in the Tags packet. + pub fn vanilla_fluid_id(self) -> Option { + if self.is_fluid() { + match (self.kind(), self.water_level().unwrap()) { + // could be swapped? + (BlockKind::Water, 0) => Some(2), // stationary water + (BlockKind::Water, _) => Some(1), // flowing water + // tested those + (BlockKind::Lava, 0) => Some(4), // stationary lava + (BlockKind::Lava, _) => Some(3), // flowing lava + _ => unreachable!(), + } + } else { + None + } + } + */ + + /// Returns the block corresponding to the given vanilla ID. + /// + /// (Invalid IDs currently return `BlockId::air()`). + pub fn from_vanilla_id(id: u16) -> Self { + FROM_VANILLA_ID_TABLE[id as usize] + } +} + +impl From for u32 { + fn from(id: BlockId) -> Self { + ((id.kind as u32) << 16) | id.state as u32 + } +} + +#[derive(Debug, Error)] +pub enum BlockIdFromU32Error { + #[error("invalid block kind ID {0}")] + InvalidKind(u16), + #[error("invalid block state ID {0} for kind {1:?}")] + InvalidState(u16, BlockKind), +} + +impl TryFrom for BlockId { + type Error = BlockIdFromU32Error; + + fn try_from(value: u32) -> Result { + let kind_id = (value >> 16) as u16; + let kind = BlockKind::from_u16(kind_id).ok_or(BlockIdFromU32Error::InvalidKind(kind_id))?; + + let state = (value | ((1 << 16) - 1)) as u16; + + // TODO: verify state + Ok(BlockId { kind, state }) + } +} + +// This is where the magic happens. +pub(crate) fn n_dimensional_index(state: u16, offset_coefficient: u16, stride: u16) -> u16 { + (state % offset_coefficient) / stride +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn instrument() { + let mut block = BlockId { + kind: BlockKind::NoteBlock, + state: 0, + }; + assert!(block.instrument().is_some()); + + block.set_instrument(Instrument::Basedrum); + assert_eq!(block.instrument(), Some(Instrument::Basedrum)); + } + + #[test] + fn highest_id() { + assert_eq!( + HIGHEST_ID, + *VANILLA_ID_TABLE.last().unwrap().last().unwrap() + ) + } + + #[test] + fn vanilla_ids() { + let block = BlockId::rose_bush().with_half_upper_lower(HalfUpperLower::Lower); + + assert_eq!(block.vanilla_id(), 7894); // will have to be changed whenever we update to a newer MC version + assert_eq!(BlockId::from_vanilla_id(block.vanilla_id()), block); + + let block = + BlockId::structure_block().with_structure_block_mode(StructureBlockMode::Corner); + + assert_eq!(block.vanilla_id(), 15745); + assert_eq!(BlockId::from_vanilla_id(block.vanilla_id()), block); + + let mut block = BlockId::redstone_wire(); + block.set_power(2); + block.set_south_wire(SouthWire::Side); + block.set_west_wire(WestWire::Side); + block.set_east_wire(EastWire::Side); + block.set_north_wire(NorthWire::Up); + + assert_eq!(block.power(), Some(2)); + assert_eq!(block.south_wire(), Some(SouthWire::Side)); + assert_eq!(block.west_wire(), Some(WestWire::Side)); + assert_eq!(block.east_wire(), Some(EastWire::Side)); + assert_eq!(block.north_wire(), Some(NorthWire::Up)); + + assert_eq!(block.vanilla_id(), 2512); + assert_eq!(BlockId::from_vanilla_id(block.vanilla_id()), block); + } + + #[test] + fn vanilla_ids_roundtrip() { + for id in 0..8598 { + assert_eq!(BlockId::from_vanilla_id(id).vanilla_id(), id); + + if id != 0 { + assert_ne!(BlockId::from_vanilla_id(id), BlockId::air()); + } + } + } + + #[test] + fn property_starting_at_1() { + let block = BlockId::snow().with_layers(1); + + assert_eq!(block.layers(), Some(1)); + assert_eq!(block.to_properties_map()["layers"], "1"); + } +} diff --git a/feather/blocks/src/wall_blocks.rs b/feather/blocks/src/wall_blocks.rs new file mode 100644 index 000000000..268f31781 --- /dev/null +++ b/feather/blocks/src/wall_blocks.rs @@ -0,0 +1,41 @@ +use crate::{BlockId, BlockKind}; + +impl BlockId { + pub fn to_wall_block(self) -> Option { + match self.kind() { + BlockKind::Torch => Some(BlockId::wall_torch()), + BlockKind::RedstoneTorch => Some(BlockId::redstone_wall_torch()), + BlockKind::OakSign => Some(BlockId::oak_wall_sign()), + BlockKind::SpruceSign => Some(BlockId::spruce_wall_sign()), + BlockKind::AcaciaSign => Some(BlockId::acacia_wall_sign()), + BlockKind::BirchSign => Some(BlockId::birch_wall_sign()), + BlockKind::CrimsonSign => Some(BlockId::crimson_wall_sign()), + BlockKind::DarkOakSign => Some(BlockId::dark_oak_wall_sign()), + BlockKind::JungleSign => Some(BlockId::jungle_wall_sign()), + BlockKind::WarpedSign => Some(BlockId::warped_wall_sign()), + BlockKind::SkeletonSkull => Some(BlockId::skeleton_wall_skull()), + BlockKind::WitherSkeletonSkull => Some(BlockId::wither_skeleton_wall_skull()), + BlockKind::ZombieHead => Some(BlockId::zombie_wall_head()), + BlockKind::CreeperHead => Some(BlockId::creeper_wall_head()), + BlockKind::PlayerHead => Some(BlockId::player_wall_head()), + BlockKind::DragonHead => Some(BlockId::dragon_wall_head()), + BlockKind::WhiteBanner => Some(BlockId::white_wall_banner()), + BlockKind::OrangeBanner => Some(BlockId::orange_wall_banner()), + BlockKind::MagentaBanner => Some(BlockId::magenta_wall_banner()), + BlockKind::LightBlueBanner => Some(BlockId::light_blue_wall_banner()), + BlockKind::YellowBanner => Some(BlockId::yellow_wall_banner()), + BlockKind::LimeBanner => Some(BlockId::lime_wall_banner()), + BlockKind::PinkBanner => Some(BlockId::pink_wall_banner()), + BlockKind::GrayBanner => Some(BlockId::gray_wall_banner()), + BlockKind::LightGrayBanner => Some(BlockId::light_gray_wall_banner()), + BlockKind::CyanBanner => Some(BlockId::cyan_wall_banner()), + BlockKind::PurpleBanner => Some(BlockId::purple_wall_banner()), + BlockKind::BlueBanner => Some(BlockId::blue_wall_banner()), + BlockKind::BrownBanner => Some(BlockId::brown_wall_banner()), + BlockKind::GreenBanner => Some(BlockId::green_wall_banner()), + BlockKind::RedBanner => Some(BlockId::red_wall_banner()), + BlockKind::BlackBanner => Some(BlockId::black_wall_banner()), + _ => None, + } + } +} diff --git a/feather/common/Cargo.toml b/feather/common/Cargo.toml new file mode 100644 index 000000000..a371549d5 --- /dev/null +++ b/feather/common/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "feather-common" +version = "0.1.0" +authors = [ "caelunshun " ] +edition = "2018" + +[dependencies] +ahash = "0.7" +anyhow = "1" +base = { path = "../base", package = "feather-base" } +blocks = { path = "../blocks", package = "feather-blocks" } +ecs = { path = "../ecs", package = "feather-ecs" } +flume = "0.10" +itertools = "0.10" +log = "0.4" +parking_lot = "0.11" +quill-common = { path = "../../quill/common" } +smartstring = "0.2" +utils = { path = "../utils", package = "feather-utils" } +uuid = { version = "0.8", features = [ "v4" ] } +libcraft-core = { path = "../../libcraft/core" } +libcraft-inventory = { path = "../../libcraft/inventory" } +libcraft-items = { path = "../../libcraft/items" } +rayon = "1.5" +worldgen = { path = "../worldgen", package = "feather-worldgen" } +rand = "0.8" \ No newline at end of file diff --git a/feather/common/src/chat.rs b/feather/common/src/chat.rs new file mode 100644 index 000000000..287860495 --- /dev/null +++ b/feather/common/src/chat.rs @@ -0,0 +1,118 @@ +use base::{Text, Title}; + +/// An entity's "mailbox" for receiving chat messages. +/// +/// Internally stores a list of [`ChatMessage`]s. +/// It is up to the user to flush the mailbox. +/// (`feather-server` flushes mailboxes by sending chat packets.) +#[derive(Debug)] +pub struct ChatBox { + messages: Vec, + titles: Vec, + preference: ChatPreference, +} + +impl ChatBox { + pub fn new(preference: ChatPreference) -> Self { + Self { + messages: Vec::new(), + titles: Vec::new(), + preference, + } + } + + pub fn set_preference(&mut self, preference: ChatPreference) { + self.preference = preference; + } + + pub fn send(&mut self, message: ChatMessage) { + self.messages.push(message); + } + + pub fn send_chat(&mut self, message: impl Into<Text>) { + self.send(ChatMessage::new(ChatKind::PlayerChat, message.into())); + } + + pub fn send_system(&mut self, message: impl Into<Text>) { + self.send(ChatMessage::new(ChatKind::System, message.into())); + } + + pub fn send_above_hotbar(&mut self, message: impl Into<Text>) { + self.send(ChatMessage::new(ChatKind::AboveHotbar, message.into())); + } + + /// Adds the [`Title`] to the title queue. + pub fn send_title(&mut self, title: Title) { + self.titles.push(title); + } + + /// Drains titles in the mailbox + pub fn drain_titles(&mut self) -> impl Iterator<Item = Title> + '_ { + self.titles.drain(..) + } + + /// Drains messages in the mailbox. + pub fn drain(&mut self) -> impl Iterator<Item = ChatMessage> + '_ { + let preference = self.preference; + self.messages + .drain(..) + .filter(move |msg| msg.kind.should_send(preference)) + } +} + +/// Represents a chat message. +#[derive(Debug, Clone)] +pub struct ChatMessage { + kind: ChatKind, + message: Text, +} + +impl ChatMessage { + pub fn new(kind: ChatKind, message: Text) -> Self { + Self { kind, message } + } + + pub fn kind(&self) -> ChatKind { + self.kind + } + + pub fn text(&self) -> &Text { + &self.message + } +} + +/// Kind of chat message. The client determines whether +/// to display a message based on this kind. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum ChatKind { + /// A player chat message or similar. + PlayerChat, + /// The output of a command or other messages + /// not originating from players. + System, + /// A message displayed above the hotbar. + AboveHotbar, +} + +impl ChatKind { + pub fn should_send(self, preference: ChatPreference) -> bool { + match self { + ChatKind::PlayerChat => preference == ChatPreference::All, + ChatKind::System => preference >= ChatPreference::System, + ChatKind::AboveHotbar => true, + } + } +} + +/// A player's chat preference. +/// Determines which [`ChatKind`]s will +/// be sent to this player. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ChatPreference { + /// Receive only game info messages. + GameInfoOnly, + /// Receive only messages from commands and game info messages. + System, + /// Receive all messages. + All, +} diff --git a/feather/common/src/chunk/cache.rs b/feather/common/src/chunk/cache.rs new file mode 100644 index 000000000..c07908968 --- /dev/null +++ b/feather/common/src/chunk/cache.rs @@ -0,0 +1,152 @@ +use std::{ + collections::VecDeque, + sync::Arc, + time::{Duration, Instant}, +}; + +use ahash::AHashMap; +use base::{ChunkHandle, ChunkPosition}; + +#[cfg(not(test))] +const CACHE_TIME: Duration = Duration::from_secs(30); +#[cfg(test)] +const CACHE_TIME: Duration = Duration::from_millis(500); + +/// This struct contains chunks that were unloaded but remain in memory in case they are needed. +#[derive(Default)] +pub struct ChunkCache { + map: AHashMap<ChunkPosition, (Instant, ChunkHandle)>, // expire time + handle + unload_queue: VecDeque<ChunkPosition>, +} +impl ChunkCache { + pub fn new() -> Self { + Self { + map: AHashMap::new(), + unload_queue: VecDeque::new(), + } + } + /// Purges all unused chunk handles. Handles that exist elswhere in the memory are not removed. + pub fn purge_unused(&mut self) { + let mut to_remove: Vec<ChunkPosition> = vec![]; + for (pos, (_, arc)) in self.map.iter() { + if Arc::strong_count(arc) == 1 { + to_remove.push(*pos) + } + } + for i in to_remove { + self.map.remove(&i); + } + } + /// Purges all chunk handles in the cache, including those that exist elswhere. + pub fn purge_all(&mut self) { + self.map.clear(); + self.unload_queue.clear(); + } + fn ref_count(&self, pos: &ChunkPosition) -> Option<usize> { + self.map.get(pos).map(|(_, arc)| Arc::strong_count(arc)) + } + /// Purges all chunks that have been in unused the cache for longer than `CACHE_TIME`. Refreshes this timer for chunks that are in use at the moment. + pub fn purge_old_unused(&mut self) { + while let Some(&pos) = self.unload_queue.get(0) { + if !self.contains(&pos) { + // Might be caused by a manual purge + self.unload_queue.pop_front(); + continue; + } + if self.map.get(&pos).unwrap().0 > Instant::now() { + // Subsequent entries are 'scheduled' for later + break; + } + self.unload_queue.pop_front(); + if self.ref_count(&pos).unwrap() > 1 { + // Another copy of this handle already exists + self.unload_queue.push_back(pos); + self.map.entry(pos).and_modify(|(time, _)| { + *time = Instant::now() + CACHE_TIME; + }); + } else { + self.map.remove_entry(&pos); + } + } + } + /// Returns whether the chunk at the position is cached. + pub fn contains(&self, pos: &ChunkPosition) -> bool { + self.map.contains_key(pos) + } + /// Inserts a chunk handle into the cache, returning the previous handle if there was one. + pub fn insert(&mut self, pos: ChunkPosition, handle: ChunkHandle) -> Option<ChunkHandle> { + self.unload_queue.push_back(pos); + self.map + .insert(pos, (Instant::now() + CACHE_TIME, handle)) + .map(|(_, handle)| handle) + } + /// Inserts a chunk handle into the cache. Reads the chunk's position by locking it. Blocks. + pub fn insert_read_pos(&mut self, handle: ChunkHandle) -> Option<ChunkHandle> { + let pos = handle.read().position(); + self.insert(pos, handle) + } + /// Removes the chunk handle at the given position, returning the handle if it was cached. + pub fn remove(&mut self, pos: ChunkPosition) -> Option<ChunkHandle> { + self.map.remove(&pos).map(|(_, handle)| handle) + } + /// Returns the chunk handle at the given position, if there was one. + pub fn get(&mut self, pos: ChunkPosition) -> Option<ChunkHandle> { + self.map.get(&pos).map(|(_, handle)| handle.clone()) + } + pub fn len(&self) -> usize { + self.map.len() + } + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } +} + +#[cfg(test)] +mod tests { + use std::{sync::Arc, thread::sleep}; + + use base::{Chunk, ChunkHandle, ChunkLock, ChunkPosition}; + + use super::{ChunkCache, CACHE_TIME}; + + #[test] + fn purge_unused() { + let mut cache = ChunkCache::new(); + let mut stored_handles: Vec<ChunkHandle> = vec![]; + let mut used_count = 0; + for i in 0..100 { + let handle = Arc::new(ChunkLock::new(Chunk::new(ChunkPosition::new(i, 0)), false)); + if rand::random::<bool>() { + // clone this handle and pretend it is used + used_count += 1; + stored_handles.push(handle.clone()); + } + assert!(cache.insert_read_pos(handle).is_none()); + } + assert_eq!(cache.len(), 100); + cache.purge_unused(); + assert_eq!(cache.len(), used_count); + } + #[test] + fn purge_old_unused() { + let mut cache = ChunkCache::new(); + let mut stored_handles: Vec<ChunkHandle> = vec![]; + let mut used_count = 0; + for i in 0..100 { + let handle = Arc::new(ChunkLock::new(Chunk::new(ChunkPosition::new(i, 0)), false)); + if rand::random::<bool>() { + // clone this handle and pretend it is used + used_count += 1; + stored_handles.push(handle.clone()); + } + assert!(cache.insert_read_pos(handle).is_none()); + } + cache.purge_old_unused(); + assert_eq!(cache.len(), 100); + sleep(CACHE_TIME); + sleep(CACHE_TIME); + assert_eq!(cache.len(), 100); + cache.purge_old_unused(); + assert_eq!(cache.len(), used_count); + } +} diff --git a/feather/common/src/chunk/entities.rs b/feather/common/src/chunk/entities.rs new file mode 100644 index 000000000..02a2b0db4 --- /dev/null +++ b/feather/common/src/chunk/entities.rs @@ -0,0 +1,98 @@ +use ahash::AHashMap; +use base::{ChunkPosition, Position}; +use ecs::{Entity, SysResult, SystemExecutor}; +use quill_common::events::{EntityCreateEvent, EntityRemoveEvent}; +use utils::vec_remove_item; + +use crate::{events::ChunkCrossEvent, Game}; + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems.add_system(update_chunk_entities); +} + +/// A spatial index to look up entities within a given chunk. +#[derive(Default)] +pub struct ChunkEntities { + entities: AHashMap<ChunkPosition, Vec<Entity>>, +} + +impl ChunkEntities { + /// Returns the entities in the given chunk. + pub fn entities_in_chunk(&self, chunk: ChunkPosition) -> &[Entity] { + self.entities + .get(&chunk) + .map(Vec::as_slice) + .unwrap_or_default() + } + + fn update( + &mut self, + entity: Entity, + old_chunk: Option<ChunkPosition>, + new_chunk: ChunkPosition, + ) { + if let Some(old_chunk) = old_chunk { + if let Some(vec) = self.entities.get_mut(&old_chunk) { + vec_remove_item(vec, &entity); + } + } + + self.entities.entry(new_chunk).or_default().push(entity); + } + + fn remove_entity(&mut self, entity: Entity, chunk: ChunkPosition) { + if let Some(vec) = self.entities.get_mut(&chunk) { + vec_remove_item(vec, &entity); + } + } +} + +fn update_chunk_entities(game: &mut Game) -> SysResult { + // Entities that have crossed chunks + let mut events = Vec::new(); + for (entity, (old_chunk, &position)) in + game.ecs.query::<(&mut ChunkPosition, &Position)>().iter() + { + let new_chunk = position.chunk(); + if position.chunk() != *old_chunk { + game.chunk_entities + .update(entity, Some(*old_chunk), new_chunk); + events.push(( + entity, + ChunkCrossEvent { + old_chunk: *old_chunk, + new_chunk, + }, + )); + + *old_chunk = new_chunk; + } + } + for (entity, event) in events { + game.ecs.insert_entity_event(entity, event)?; + } + + // Entities that have been created + let mut insertions = Vec::new(); + for (entity, (_event, &position)) in game.ecs.query::<(&EntityCreateEvent, &Position)>().iter() + { + let chunk = position.chunk(); + game.chunk_entities.update(entity, None, chunk); + insertions.push((entity, chunk)); + } + // Add ChunkPosition component to new entities + for (entity, chunk) in insertions { + game.ecs.insert(entity, chunk)?; + } + + // Entities that have been destroyed + for (entity, (_event, &chunk)) in game + .ecs + .query::<(&EntityRemoveEvent, &ChunkPosition)>() + .iter() + { + game.chunk_entities.remove_entity(entity, chunk); + } + + Ok(()) +} diff --git a/feather/common/src/chunk/loading.rs b/feather/common/src/chunk/loading.rs new file mode 100644 index 000000000..7e52d37fa --- /dev/null +++ b/feather/common/src/chunk/loading.rs @@ -0,0 +1,175 @@ +//! Chunk loading and unloading based on player `View`s. + +use std::{ + collections::VecDeque, + mem, + time::{Duration, Instant}, +}; + +use ahash::AHashMap; +use base::ChunkPosition; +use ecs::{Entity, SysResult, SystemExecutor}; +use quill_common::events::EntityRemoveEvent; +use utils::vec_remove_item; + +use crate::{chunk::worker::LoadRequest, events::ViewUpdateEvent, Game}; + +pub fn register(game: &mut Game, systems: &mut SystemExecutor<Game>) { + game.insert_resource(ChunkLoadState::default()); + systems + .group::<ChunkLoadState>() + .add_system(remove_dead_entities) + .add_system(update_tickets_for_players) + .add_system(unload_chunks) + .add_system(load_chunks); +} + +/// Amount of time to wait after a chunk has +/// no tickets until it is unloaded. +const UNLOAD_DELAY: Duration = Duration::from_secs(10); + +#[derive(Default)] +struct ChunkLoadState { + /// Chunks that have been queued for unloading. + chunk_unload_queue: VecDeque<QueuedChunkUnload>, + + chunk_tickets: ChunkTickets, +} + +impl ChunkLoadState { + pub fn remove_ticket(&mut self, chunk: ChunkPosition, ticket: Ticket) { + self.chunk_tickets.remove_ticket(chunk, ticket); + + // If this was the last ticket, then queue the chunk to be + // unloaded. + if self.chunk_tickets.num_tickets(chunk) == 0 { + self.chunk_tickets.remove_chunk(chunk); + self.chunk_unload_queue + .push_back(QueuedChunkUnload::new(chunk)); + } + } +} + +#[derive(Copy, Clone, Debug)] +struct QueuedChunkUnload { + pos: ChunkPosition, + /// Time after which the chunk should be unloaded. + unload_at_time: Instant, +} + +impl QueuedChunkUnload { + pub fn new(pos: ChunkPosition) -> Self { + Self { + pos, + unload_at_time: Instant::now() + UNLOAD_DELAY, + } + } +} + +/// Maintains a list of "tickets" for each loaded chunk. +/// A chunk is queued for unloading when it has no more tickets. +#[derive(Default)] +struct ChunkTickets { + tickets: AHashMap<ChunkPosition, Vec<Ticket>>, + by_entity: AHashMap<Ticket, Vec<ChunkPosition>>, +} + +impl ChunkTickets { + pub fn insert_ticket(&mut self, chunk: ChunkPosition, ticket: Ticket) { + self.tickets.entry(chunk).or_default().push(ticket); + self.by_entity.entry(ticket).or_default().push(chunk); + } + + pub fn remove_ticket(&mut self, chunk: ChunkPosition, ticket: Ticket) { + if let Some(vec) = self.tickets.get_mut(&chunk) { + vec_remove_item(vec, &ticket); + } + vec_remove_item(self.by_entity.get_mut(&ticket).unwrap(), &chunk); + } + + pub fn num_tickets(&self, chunk: ChunkPosition) -> usize { + match self.tickets.get(&chunk) { + Some(vec) => vec.len(), + None => 0, + } + } + + pub fn take_entity_tickets(&mut self, ticket: Ticket) -> Vec<ChunkPosition> { + self.by_entity + .get_mut(&ticket) + .map(mem::take) + .unwrap_or_default() + } + + pub fn remove_chunk(&mut self, pos: ChunkPosition) { + self.tickets.remove(&pos); + } +} + +/// ID of a chunk ticket that keeps a chunk loaded. +/// +/// Currently just represents an entity, the player +/// that is keeping this chunk loaded. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +struct Ticket(Entity); + +/// System to populate chunk tickets based on players' views. +fn update_tickets_for_players(game: &mut Game, state: &mut ChunkLoadState) -> SysResult { + for (player, event) in game.ecs.query::<&ViewUpdateEvent>().iter() { + let player_ticket = Ticket(player); + + // Remove old tickets + for &old_chunk in &event.old_chunks { + state.remove_ticket(old_chunk, player_ticket); + } + + // Create new tickets + for &new_chunk in &event.new_chunks { + state.chunk_tickets.insert_ticket(new_chunk, player_ticket); + + // Load if needed + if !game.world.is_chunk_loaded(new_chunk) && !game.world.is_chunk_loading(new_chunk) { + game.world.queue_chunk_load(LoadRequest { pos: new_chunk }); + } + } + } + Ok(()) +} + +/// System to unload chunks from the `ChunkUnloadQueue`. +fn unload_chunks(game: &mut Game, state: &mut ChunkLoadState) -> SysResult { + while let Some(&unload) = state.chunk_unload_queue.get(0) { + if unload.unload_at_time > Instant::now() { + // None of the remaining chunks in the queue are + // ready for unloading, because the queue is ordered + // by time. + break; + } + + state.chunk_unload_queue.pop_front(); + + // If the chunk has acquired new tickets, then abort unloading it. + if state.chunk_tickets.num_tickets(unload.pos) > 0 { + continue; + } + + game.world.unload_chunk(unload.pos)?; + } + game.world.cache.purge_unused(); + Ok(()) +} + +fn remove_dead_entities(game: &mut Game, state: &mut ChunkLoadState) -> SysResult { + for (entity, _event) in game.ecs.query::<&EntityRemoveEvent>().iter() { + let entity_ticket = Ticket(entity); + for chunk in state.chunk_tickets.take_entity_tickets(entity_ticket) { + state.remove_ticket(chunk, entity_ticket); + } + } + Ok(()) +} + +/// System to call `World::load_chunks` each tick +fn load_chunks(game: &mut Game, _state: &mut ChunkLoadState) -> SysResult { + game.world.load_chunks(&mut game.ecs) +} diff --git a/feather/common/src/chunk/mod.rs b/feather/common/src/chunk/mod.rs new file mode 100644 index 000000000..e1c180383 --- /dev/null +++ b/feather/common/src/chunk/mod.rs @@ -0,0 +1,4 @@ +pub mod cache; +pub mod entities; +pub mod loading; +pub mod worker; diff --git a/feather/common/src/chunk/worker.rs b/feather/common/src/chunk/worker.rs new file mode 100644 index 000000000..85f4d7229 --- /dev/null +++ b/feather/common/src/chunk/worker.rs @@ -0,0 +1,115 @@ +use std::{path::PathBuf, sync::Arc}; + +use anyhow::bail; +use base::{ + anvil::{block_entity::BlockEntityData, entity::EntityData}, + Chunk, ChunkHandle, ChunkPosition, +}; +use flume::{Receiver, Sender}; +use worldgen::WorldGenerator; + +use crate::region_worker::RegionWorker; + +#[derive(Debug)] +pub struct LoadRequest { + pub pos: ChunkPosition, +} +#[derive(Debug)] +pub struct LoadedChunk { + pub pos: ChunkPosition, + pub chunk: Chunk, +} + +#[derive(Debug)] +#[allow(clippy::large_enum_variant)] +pub enum ChunkLoadResult { + /// The chunk does not exist in this source. + Missing(ChunkPosition), + /// An error occurred while loading the chunk. + Error(anyhow::Error), + /// Successfully loaded the chunk. + Loaded(LoadedChunk), +} + +#[derive(Debug)] +pub struct SaveRequest { + pub pos: ChunkPosition, + pub chunk: ChunkHandle, + pub entities: Vec<EntityData>, + pub block_entities: Vec<BlockEntityData>, +} + +#[derive(Debug)] +#[allow(clippy::large_enum_variant)] +pub enum WorkerRequest { + Load(LoadRequest), + Save(SaveRequest), +} +pub struct ChunkWorker { + generator: Arc<dyn WorldGenerator>, + send_req: Sender<WorkerRequest>, + send_gen: Sender<LoadedChunk>, + recv_gen: Receiver<LoadedChunk>, // Chunk generation should be infallible. + recv_load: Receiver<ChunkLoadResult>, +} + +impl ChunkWorker { + pub fn new(world_dir: impl Into<PathBuf>, generator: Arc<dyn WorldGenerator>) -> Self { + let (send_req, recv_req) = flume::unbounded(); + let (send_gen, recv_gen) = flume::unbounded(); + let (region_worker, recv_load) = RegionWorker::new(world_dir.into(), recv_req); + region_worker.start(); + Self { + generator, + send_req, + send_gen, + recv_gen, + recv_load, + } + } + pub fn queue_load(&mut self, request: LoadRequest) { + self.send_req.send(WorkerRequest::Load(request)).unwrap() + } + + /// Helper function for poll_loaded_chunk. Attemts to receive a freshly generated chunk. + /// Function signature identical to that of poll_loaded_chunk for ease of use. + fn try_recv_gen(&mut self) -> Result<Option<LoadedChunk>, anyhow::Error> { + match self.recv_gen.try_recv() { + Ok(l) => Ok(Some(l)), + Err(e) => match e { + flume::TryRecvError::Empty => Ok(None), + flume::TryRecvError::Disconnected => bail!("chunkgen channel died"), + }, + } + } + pub fn poll_loaded_chunk(&mut self) -> Result<Option<LoadedChunk>, anyhow::Error> { + match self.recv_load.try_recv() { + Ok(answer) => { + match answer { + // RegionWorker answered + ChunkLoadResult::Missing(pos) => { + // chunk does not exist, queue it for generation + let send_gen = self.send_gen.clone(); + let gen = self.generator.clone(); + rayon::spawn(move || { + // spawn task to generate chunk + let chunk = gen.generate_chunk(pos); + send_gen.send(LoadedChunk { pos, chunk }).unwrap() + }); + self.try_recv_gen() // check for generated chunks + } + ChunkLoadResult::Error(e) => Err(e), + ChunkLoadResult::Loaded(l) => Ok(Some(l)), + } + } + Err(e) => match e { + flume::TryRecvError::Empty => self.try_recv_gen(), // check for generated chunks + flume::TryRecvError::Disconnected => bail!("RegionWorker died"), + }, + } + } + + pub fn queue_chunk_save(&mut self, req: SaveRequest) { + self.send_req.send(WorkerRequest::Save(req)).unwrap() + } +} diff --git a/feather/common/src/entities.rs b/feather/common/src/entities.rs new file mode 100644 index 000000000..3fa7663fd --- /dev/null +++ b/feather/common/src/entities.rs @@ -0,0 +1,236 @@ +//! Entity implementations. +//! +//! Each entity should be implemented in a submodule of this module. +//! It should export a `build_default(&mut EntityBuilder)` function to +//! add default components for that entity. + +use ecs::EntityBuilder; +use quill_common::{components::OnGround, entity_init::EntityInit}; +use uuid::Uuid; + +/// Adds default components shared between all entities. +fn build_default(builder: &mut EntityBuilder) { + builder.add(Uuid::new_v4()).add(OnGround(true)); +} + +pub mod area_effect_cloud; +pub mod armor_stand; +pub mod arrow; +pub mod bat; +pub mod bee; +pub mod blaze; +pub mod boat; +pub mod cat; +pub mod cave_spider; +pub mod chest_minecart; +pub mod chicken; +pub mod cod; +pub mod command_block_minecart; +pub mod cow; +pub mod creeper; +pub mod dolphin; +pub mod donkey; +pub mod dragon_fireball; +pub mod drowned; +pub mod egg; +pub mod elder_guardian; +pub mod end_crystal; +pub mod ender_dragon; +pub mod ender_pearl; +pub mod enderman; +pub mod endermite; +pub mod evoker; +pub mod evoker_fangs; +pub mod experience_bottle; +pub mod experience_orb; +pub mod eye_of_ender; +pub mod falling_block; +pub mod fireball; +pub mod firework_rocket; +pub mod fishing_bobber; +pub mod fox; +pub mod furnace_minecart; +pub mod ghast; +pub mod giant; +pub mod guardian; +pub mod hoglin; +pub mod hopper_minecart; +pub mod horse; +pub mod husk; +pub mod illusioner; +pub mod iron_golem; +pub mod item; +pub mod item_frame; +pub mod leash_knot; +pub mod lightning_bolt; +pub mod llama; +pub mod llama_spit; +pub mod magma_cube; +pub mod minecart; +pub mod mooshroom; +pub mod mule; +pub mod ocelot; +pub mod painting; +pub mod panda; +pub mod parrot; +pub mod phantom; +pub mod pig; +pub mod piglin; +pub mod piglin_brute; +pub mod pillager; +pub mod player; +pub mod polar_bear; +pub mod potion; +pub mod pufferfish; +pub mod rabbit; +pub mod ravager; +pub mod salmon; +pub mod sheep; +pub mod shulker; +pub mod shulker_bullet; +pub mod silverfish; +pub mod skeleton; +pub mod skeleton_horse; +pub mod slime; +pub mod small_fireball; +pub mod snow_golem; +pub mod snowball; +pub mod spawner_minecart; +pub mod spectral_arrow; +pub mod spider; +pub mod squid; +pub mod stray; +pub mod strider; +pub mod tnt; +pub mod tnt_minecart; +pub mod trader_llama; +pub mod trident; +pub mod tropical_fish; +pub mod turtle; +pub mod vex; +pub mod villager; +pub mod vindicator; +pub mod wandering_trader; +pub mod witch; +pub mod wither; +pub mod wither_skeleton; +pub mod wither_skull; +pub mod wolf; +pub mod zoglin; +pub mod zombie; +pub mod zombie_horse; +pub mod zombie_villager; +pub mod zombified_piglin; + +pub fn add_entity_components(builder: &mut EntityBuilder, init: &EntityInit) { + match init { + EntityInit::AreaEffectCloud => area_effect_cloud::build_default(builder), + EntityInit::ArmorStand => armor_stand::build_default(builder), + EntityInit::Arrow => arrow::build_default(builder), + EntityInit::Bat => bat::build_default(builder), + EntityInit::Bee => bee::build_default(builder), + EntityInit::Blaze => blaze::build_default(builder), + EntityInit::Boat => boat::build_default(builder), + EntityInit::Cat => cat::build_default(builder), + EntityInit::CaveSpider => cave_spider::build_default(builder), + EntityInit::Chicken => chicken::build_default(builder), + EntityInit::Cod => cod::build_default(builder), + EntityInit::Cow => cow::build_default(builder), + EntityInit::Creeper => creeper::build_default(builder), + EntityInit::Dolphin => dolphin::build_default(builder), + EntityInit::Donkey => donkey::build_default(builder), + EntityInit::DragonFireball => dragon_fireball::build_default(builder), + EntityInit::Drowned => drowned::build_default(builder), + EntityInit::ElderGuardian => elder_guardian::build_default(builder), + EntityInit::EndCrystal => end_crystal::build_default(builder), + EntityInit::EnderDragon => ender_dragon::build_default(builder), + EntityInit::Enderman => enderman::build_default(builder), + EntityInit::Endermite => endermite::build_default(builder), + EntityInit::Evoker => evoker::build_default(builder), + EntityInit::EvokerFangs => evoker_fangs::build_default(builder), + EntityInit::ExperienceOrb => experience_orb::build_default(builder), + EntityInit::EyeOfEnder => eye_of_ender::build_default(builder), + EntityInit::FallingBlock => falling_block::build_default(builder), + EntityInit::FireworkRocket => firework_rocket::build_default(builder), + EntityInit::Fox => fox::build_default(builder), + EntityInit::Ghast => ghast::build_default(builder), + EntityInit::Giant => giant::build_default(builder), + EntityInit::Guardian => guardian::build_default(builder), + EntityInit::Hoglin => hoglin::build_default(builder), + EntityInit::Horse => horse::build_default(builder), + EntityInit::Husk => husk::build_default(builder), + EntityInit::Illusioner => illusioner::build_default(builder), + EntityInit::IronGolem => iron_golem::build_default(builder), + EntityInit::Item => item::build_default(builder), + EntityInit::ItemFrame => item_frame::build_default(builder), + EntityInit::Fireball => fireball::build_default(builder), + EntityInit::LeashKnot => leash_knot::build_default(builder), + EntityInit::LightningBolt => lightning_bolt::build_default(builder), + EntityInit::Llama => llama::build_default(builder), + EntityInit::LlamaSpit => llama_spit::build_default(builder), + EntityInit::MagmaCube => magma_cube::build_default(builder), + EntityInit::Minecart => minecart::build_default(builder), + EntityInit::ChestMinecart => chest_minecart::build_default(builder), + EntityInit::CommandBlockMinecart => command_block_minecart::build_default(builder), + EntityInit::FurnaceMinecart => furnace_minecart::build_default(builder), + EntityInit::HopperMinecart => hopper_minecart::build_default(builder), + EntityInit::SpawnerMinecart => spawner_minecart::build_default(builder), + EntityInit::TntMinecart => tnt_minecart::build_default(builder), + EntityInit::Mule => mule::build_default(builder), + EntityInit::Mooshroom => mooshroom::build_default(builder), + EntityInit::Ocelot => ocelot::build_default(builder), + EntityInit::Painting => painting::build_default(builder), + EntityInit::Panda => panda::build_default(builder), + EntityInit::Parrot => parrot::build_default(builder), + EntityInit::Phantom => phantom::build_default(builder), + EntityInit::Pig => pig::build_default(builder), + EntityInit::Piglin => piglin::build_default(builder), + EntityInit::PiglinBrute => piglin_brute::build_default(builder), + EntityInit::Pillager => pillager::build_default(builder), + EntityInit::PolarBear => polar_bear::build_default(builder), + EntityInit::Tnt => tnt::build_default(builder), + EntityInit::Pufferfish => pufferfish::build_default(builder), + EntityInit::Rabbit => rabbit::build_default(builder), + EntityInit::Ravager => ravager::build_default(builder), + EntityInit::Salmon => salmon::build_default(builder), + EntityInit::Sheep => sheep::build_default(builder), + EntityInit::Shulker => shulker::build_default(builder), + EntityInit::ShulkerBullet => shulker_bullet::build_default(builder), + EntityInit::Silverfish => silverfish::build_default(builder), + EntityInit::Skeleton => skeleton::build_default(builder), + EntityInit::SkeletonHorse => skeleton_horse::build_default(builder), + EntityInit::Slime => slime::build_default(builder), + EntityInit::SmallFireball => small_fireball::build_default(builder), + EntityInit::SnowGolem => snow_golem::build_default(builder), + EntityInit::Snowball => snowball::build_default(builder), + EntityInit::SpectralArrow => spectral_arrow::build_default(builder), + EntityInit::Spider => spider::build_default(builder), + EntityInit::Squid => squid::build_default(builder), + EntityInit::Stray => stray::build_default(builder), + EntityInit::Strider => strider::build_default(builder), + EntityInit::Egg => egg::build_default(builder), + EntityInit::EnderPearl => ender_pearl::build_default(builder), + EntityInit::ExperienceBottle => experience_bottle::build_default(builder), + EntityInit::Potion => potion::build_default(builder), + EntityInit::Trident => trident::build_default(builder), + EntityInit::TraderLlama => trader_llama::build_default(builder), + EntityInit::TropicalFish => tropical_fish::build_default(builder), + EntityInit::Turtle => turtle::build_default(builder), + EntityInit::Vex => vex::build_default(builder), + EntityInit::Villager => villager::build_default(builder), + EntityInit::Vindicator => vindicator::build_default(builder), + EntityInit::WanderingTrader => wandering_trader::build_default(builder), + EntityInit::Witch => witch::build_default(builder), + EntityInit::Wither => wither::build_default(builder), + EntityInit::WitherSkeleton => wither_skeleton::build_default(builder), + EntityInit::WitherSkull => wither_skull::build_default(builder), + EntityInit::Wolf => wolf::build_default(builder), + EntityInit::Zoglin => zoglin::build_default(builder), + EntityInit::Zombie => zombie::build_default(builder), + EntityInit::ZombieHorse => zombie_horse::build_default(builder), + EntityInit::ZombieVillager => zombie_villager::build_default(builder), + EntityInit::ZombifiedPiglin => zombified_piglin::build_default(builder), + EntityInit::Player => player::build_default(builder), + EntityInit::FishingBobber => fishing_bobber::build_default(builder), + } +} diff --git a/feather/common/src/entities/area_effect_cloud.rs b/feather/common/src/entities/area_effect_cloud.rs new file mode 100644 index 000000000..974b31a69 --- /dev/null +++ b/feather/common/src/entities/area_effect_cloud.rs @@ -0,0 +1,10 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::AreaEffectCloud; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder + .add(AreaEffectCloud) + .add(EntityKind::AreaEffectCloud); +} diff --git a/feather/common/src/entities/armor_stand.rs b/feather/common/src/entities/armor_stand.rs new file mode 100644 index 000000000..95cdee704 --- /dev/null +++ b/feather/common/src/entities/armor_stand.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ArmorStand; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(ArmorStand).add(EntityKind::ArmorStand); +} diff --git a/feather/common/src/entities/arrow.rs b/feather/common/src/entities/arrow.rs new file mode 100644 index 000000000..9c15209e5 --- /dev/null +++ b/feather/common/src/entities/arrow.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Arrow; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Arrow).add(EntityKind::Arrow); +} diff --git a/feather/common/src/entities/bat.rs b/feather/common/src/entities/bat.rs new file mode 100644 index 000000000..f222c3e21 --- /dev/null +++ b/feather/common/src/entities/bat.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Bat; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Bat).add(EntityKind::Bat); +} diff --git a/feather/common/src/entities/bee.rs b/feather/common/src/entities/bee.rs new file mode 100644 index 000000000..d72385897 --- /dev/null +++ b/feather/common/src/entities/bee.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Bee; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Bee).add(EntityKind::Bee); +} diff --git a/feather/common/src/entities/blaze.rs b/feather/common/src/entities/blaze.rs new file mode 100644 index 000000000..8345ca50b --- /dev/null +++ b/feather/common/src/entities/blaze.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Blaze; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Blaze).add(EntityKind::Blaze); +} diff --git a/feather/common/src/entities/boat.rs b/feather/common/src/entities/boat.rs new file mode 100644 index 000000000..74798544b --- /dev/null +++ b/feather/common/src/entities/boat.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Boat; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Boat).add(EntityKind::Boat); +} diff --git a/feather/common/src/entities/cat.rs b/feather/common/src/entities/cat.rs new file mode 100644 index 000000000..0d046eb71 --- /dev/null +++ b/feather/common/src/entities/cat.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Cat; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Cat).add(EntityKind::Cat); +} diff --git a/feather/common/src/entities/cave_spider.rs b/feather/common/src/entities/cave_spider.rs new file mode 100644 index 000000000..ef2f5079e --- /dev/null +++ b/feather/common/src/entities/cave_spider.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::CaveSpider; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(CaveSpider).add(EntityKind::CaveSpider); +} diff --git a/feather/common/src/entities/chest_minecart.rs b/feather/common/src/entities/chest_minecart.rs new file mode 100644 index 000000000..814cc3a15 --- /dev/null +++ b/feather/common/src/entities/chest_minecart.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ChestMinecart; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(ChestMinecart).add(EntityKind::ChestMinecart); +} diff --git a/feather/common/src/entities/chicken.rs b/feather/common/src/entities/chicken.rs new file mode 100644 index 000000000..acad9f090 --- /dev/null +++ b/feather/common/src/entities/chicken.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Chicken; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Chicken).add(EntityKind::Chicken); +} diff --git a/feather/common/src/entities/cod.rs b/feather/common/src/entities/cod.rs new file mode 100644 index 000000000..f00ab6ced --- /dev/null +++ b/feather/common/src/entities/cod.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Cod; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Cod).add(EntityKind::Cod); +} diff --git a/feather/common/src/entities/command_block_minecart.rs b/feather/common/src/entities/command_block_minecart.rs new file mode 100644 index 000000000..7ee4cf12d --- /dev/null +++ b/feather/common/src/entities/command_block_minecart.rs @@ -0,0 +1,10 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::CommandBlockMinecart; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder + .add(CommandBlockMinecart) + .add(EntityKind::CommandBlockMinecart); +} diff --git a/feather/common/src/entities/cow.rs b/feather/common/src/entities/cow.rs new file mode 100644 index 000000000..0819836c1 --- /dev/null +++ b/feather/common/src/entities/cow.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Cow; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Cow).add(EntityKind::Cow); +} diff --git a/feather/common/src/entities/creeper.rs b/feather/common/src/entities/creeper.rs new file mode 100644 index 000000000..31c416ef2 --- /dev/null +++ b/feather/common/src/entities/creeper.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Creeper; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Creeper).add(EntityKind::Creeper); +} diff --git a/feather/common/src/entities/dolphin.rs b/feather/common/src/entities/dolphin.rs new file mode 100644 index 000000000..ace8dc2d0 --- /dev/null +++ b/feather/common/src/entities/dolphin.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Dolphin; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Dolphin).add(EntityKind::Dolphin); +} diff --git a/feather/common/src/entities/donkey.rs b/feather/common/src/entities/donkey.rs new file mode 100644 index 000000000..e58b5cd26 --- /dev/null +++ b/feather/common/src/entities/donkey.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Donkey; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Donkey).add(EntityKind::Donkey); +} diff --git a/feather/common/src/entities/dragon_fireball.rs b/feather/common/src/entities/dragon_fireball.rs new file mode 100644 index 000000000..63c4121c7 --- /dev/null +++ b/feather/common/src/entities/dragon_fireball.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::DragonFireball; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(DragonFireball).add(EntityKind::DragonFireball); +} diff --git a/feather/common/src/entities/drowned.rs b/feather/common/src/entities/drowned.rs new file mode 100644 index 000000000..c91618ce1 --- /dev/null +++ b/feather/common/src/entities/drowned.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Drowned; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Drowned).add(EntityKind::Drowned); +} diff --git a/feather/common/src/entities/egg.rs b/feather/common/src/entities/egg.rs new file mode 100644 index 000000000..f5ae44457 --- /dev/null +++ b/feather/common/src/entities/egg.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Egg; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Egg).add(EntityKind::Egg); +} diff --git a/feather/common/src/entities/elder_guardian.rs b/feather/common/src/entities/elder_guardian.rs new file mode 100644 index 000000000..b5a642bc9 --- /dev/null +++ b/feather/common/src/entities/elder_guardian.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ElderGuardian; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(ElderGuardian).add(EntityKind::ElderGuardian); +} diff --git a/feather/common/src/entities/end_crystal.rs b/feather/common/src/entities/end_crystal.rs new file mode 100644 index 000000000..84849f55b --- /dev/null +++ b/feather/common/src/entities/end_crystal.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::EndCrystal; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(EndCrystal).add(EntityKind::EndCrystal); +} diff --git a/feather/common/src/entities/ender_dragon.rs b/feather/common/src/entities/ender_dragon.rs new file mode 100644 index 000000000..ef6680a7c --- /dev/null +++ b/feather/common/src/entities/ender_dragon.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::EnderDragon; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(EnderDragon).add(EntityKind::EnderDragon); +} diff --git a/feather/common/src/entities/ender_pearl.rs b/feather/common/src/entities/ender_pearl.rs new file mode 100644 index 000000000..ab1a2e7d2 --- /dev/null +++ b/feather/common/src/entities/ender_pearl.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::EnderPearl; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(EnderPearl).add(EntityKind::EnderPearl); +} diff --git a/feather/common/src/entities/enderman.rs b/feather/common/src/entities/enderman.rs new file mode 100644 index 000000000..833c752b9 --- /dev/null +++ b/feather/common/src/entities/enderman.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Enderman; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Enderman).add(EntityKind::Enderman); +} diff --git a/feather/common/src/entities/endermite.rs b/feather/common/src/entities/endermite.rs new file mode 100644 index 000000000..1676d2014 --- /dev/null +++ b/feather/common/src/entities/endermite.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Endermite; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Endermite).add(EntityKind::Endermite); +} diff --git a/feather/common/src/entities/evoker.rs b/feather/common/src/entities/evoker.rs new file mode 100644 index 000000000..ee2f9d38f --- /dev/null +++ b/feather/common/src/entities/evoker.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Evoker; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Evoker).add(EntityKind::Evoker); +} diff --git a/feather/common/src/entities/evoker_fangs.rs b/feather/common/src/entities/evoker_fangs.rs new file mode 100644 index 000000000..52a94c63b --- /dev/null +++ b/feather/common/src/entities/evoker_fangs.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::EvokerFangs; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(EvokerFangs).add(EntityKind::EvokerFangs); +} diff --git a/feather/common/src/entities/experience_bottle.rs b/feather/common/src/entities/experience_bottle.rs new file mode 100644 index 000000000..eb984d54f --- /dev/null +++ b/feather/common/src/entities/experience_bottle.rs @@ -0,0 +1,10 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ExperienceBottle; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder + .add(ExperienceBottle) + .add(EntityKind::ExperienceBottle); +} diff --git a/feather/common/src/entities/experience_orb.rs b/feather/common/src/entities/experience_orb.rs new file mode 100644 index 000000000..0c696cfb6 --- /dev/null +++ b/feather/common/src/entities/experience_orb.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ExperienceOrb; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(ExperienceOrb).add(EntityKind::ExperienceOrb); +} diff --git a/feather/common/src/entities/eye_of_ender.rs b/feather/common/src/entities/eye_of_ender.rs new file mode 100644 index 000000000..6d6a9eb99 --- /dev/null +++ b/feather/common/src/entities/eye_of_ender.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::EyeOfEnder; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(EyeOfEnder).add(EntityKind::EyeOfEnder); +} diff --git a/feather/common/src/entities/falling_block.rs b/feather/common/src/entities/falling_block.rs new file mode 100644 index 000000000..64eba2aa9 --- /dev/null +++ b/feather/common/src/entities/falling_block.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::FallingBlock; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(FallingBlock).add(EntityKind::FallingBlock); +} diff --git a/feather/common/src/entities/fireball.rs b/feather/common/src/entities/fireball.rs new file mode 100644 index 000000000..232684802 --- /dev/null +++ b/feather/common/src/entities/fireball.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Fireball; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Fireball).add(EntityKind::Fireball); +} diff --git a/feather/common/src/entities/firework_rocket.rs b/feather/common/src/entities/firework_rocket.rs new file mode 100644 index 000000000..c3992dce8 --- /dev/null +++ b/feather/common/src/entities/firework_rocket.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::FireworkRocket; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(FireworkRocket).add(EntityKind::FireworkRocket); +} diff --git a/feather/common/src/entities/fishing_bobber.rs b/feather/common/src/entities/fishing_bobber.rs new file mode 100644 index 000000000..036d7afcc --- /dev/null +++ b/feather/common/src/entities/fishing_bobber.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::FishingBobber; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(FishingBobber).add(EntityKind::FishingBobber); +} diff --git a/feather/common/src/entities/fox.rs b/feather/common/src/entities/fox.rs new file mode 100644 index 000000000..2267ab1e2 --- /dev/null +++ b/feather/common/src/entities/fox.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Fox; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Fox).add(EntityKind::Fox); +} diff --git a/feather/common/src/entities/furnace_minecart.rs b/feather/common/src/entities/furnace_minecart.rs new file mode 100644 index 000000000..d56fa0efc --- /dev/null +++ b/feather/common/src/entities/furnace_minecart.rs @@ -0,0 +1,10 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::FurnaceMinecart; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder + .add(FurnaceMinecart) + .add(EntityKind::FurnaceMinecart); +} diff --git a/feather/common/src/entities/ghast.rs b/feather/common/src/entities/ghast.rs new file mode 100644 index 000000000..687175afa --- /dev/null +++ b/feather/common/src/entities/ghast.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Ghast; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Ghast).add(EntityKind::Ghast); +} diff --git a/feather/common/src/entities/giant.rs b/feather/common/src/entities/giant.rs new file mode 100644 index 000000000..11290d1d1 --- /dev/null +++ b/feather/common/src/entities/giant.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Giant; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Giant).add(EntityKind::Giant); +} diff --git a/feather/common/src/entities/guardian.rs b/feather/common/src/entities/guardian.rs new file mode 100644 index 000000000..04289c4bb --- /dev/null +++ b/feather/common/src/entities/guardian.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Guardian; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Guardian).add(EntityKind::Guardian); +} diff --git a/feather/common/src/entities/hoglin.rs b/feather/common/src/entities/hoglin.rs new file mode 100644 index 000000000..1be5d1dad --- /dev/null +++ b/feather/common/src/entities/hoglin.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Hoglin; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Hoglin).add(EntityKind::Hoglin); +} diff --git a/feather/common/src/entities/hopper_minecart.rs b/feather/common/src/entities/hopper_minecart.rs new file mode 100644 index 000000000..8cf8455fc --- /dev/null +++ b/feather/common/src/entities/hopper_minecart.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::HopperMinecart; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(HopperMinecart).add(EntityKind::HopperMinecart); +} diff --git a/feather/common/src/entities/horse.rs b/feather/common/src/entities/horse.rs new file mode 100644 index 000000000..25dc48d44 --- /dev/null +++ b/feather/common/src/entities/horse.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Horse; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Horse).add(EntityKind::Horse); +} diff --git a/feather/common/src/entities/husk.rs b/feather/common/src/entities/husk.rs new file mode 100644 index 000000000..dc276d868 --- /dev/null +++ b/feather/common/src/entities/husk.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Husk; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Husk).add(EntityKind::Husk); +} diff --git a/feather/common/src/entities/illusioner.rs b/feather/common/src/entities/illusioner.rs new file mode 100644 index 000000000..f188f09fb --- /dev/null +++ b/feather/common/src/entities/illusioner.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Illusioner; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Illusioner).add(EntityKind::Illusioner); +} diff --git a/feather/common/src/entities/iron_golem.rs b/feather/common/src/entities/iron_golem.rs new file mode 100644 index 000000000..ca0c91c9b --- /dev/null +++ b/feather/common/src/entities/iron_golem.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::IronGolem; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(IronGolem).add(EntityKind::IronGolem); +} diff --git a/feather/common/src/entities/item.rs b/feather/common/src/entities/item.rs new file mode 100644 index 000000000..7fe8f4b44 --- /dev/null +++ b/feather/common/src/entities/item.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Item; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Item).add(EntityKind::Item); +} diff --git a/feather/common/src/entities/item_frame.rs b/feather/common/src/entities/item_frame.rs new file mode 100644 index 000000000..cbcac743f --- /dev/null +++ b/feather/common/src/entities/item_frame.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ItemFrame; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(ItemFrame).add(EntityKind::ItemFrame); +} diff --git a/feather/common/src/entities/leash_knot.rs b/feather/common/src/entities/leash_knot.rs new file mode 100644 index 000000000..554df1092 --- /dev/null +++ b/feather/common/src/entities/leash_knot.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::LeashKnot; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(LeashKnot).add(EntityKind::LeashKnot); +} diff --git a/feather/common/src/entities/lightning_bolt.rs b/feather/common/src/entities/lightning_bolt.rs new file mode 100644 index 000000000..6127c561d --- /dev/null +++ b/feather/common/src/entities/lightning_bolt.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::LightningBolt; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(LightningBolt).add(EntityKind::LightningBolt); +} diff --git a/feather/common/src/entities/llama.rs b/feather/common/src/entities/llama.rs new file mode 100644 index 000000000..5929eed9d --- /dev/null +++ b/feather/common/src/entities/llama.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Llama; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Llama).add(EntityKind::Llama); +} diff --git a/feather/common/src/entities/llama_spit.rs b/feather/common/src/entities/llama_spit.rs new file mode 100644 index 000000000..562a3a8be --- /dev/null +++ b/feather/common/src/entities/llama_spit.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::LlamaSpit; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(LlamaSpit).add(EntityKind::LlamaSpit); +} diff --git a/feather/common/src/entities/magma_cube.rs b/feather/common/src/entities/magma_cube.rs new file mode 100644 index 000000000..61831dab9 --- /dev/null +++ b/feather/common/src/entities/magma_cube.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::MagmaCube; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(MagmaCube).add(EntityKind::MagmaCube); +} diff --git a/feather/common/src/entities/minecart.rs b/feather/common/src/entities/minecart.rs new file mode 100644 index 000000000..f28ed8687 --- /dev/null +++ b/feather/common/src/entities/minecart.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Minecart; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Minecart).add(EntityKind::Minecart); +} diff --git a/feather/common/src/entities/mooshroom.rs b/feather/common/src/entities/mooshroom.rs new file mode 100644 index 000000000..984f2c913 --- /dev/null +++ b/feather/common/src/entities/mooshroom.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Mooshroom; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Mooshroom).add(EntityKind::Mooshroom); +} diff --git a/feather/common/src/entities/mule.rs b/feather/common/src/entities/mule.rs new file mode 100644 index 000000000..342387ebc --- /dev/null +++ b/feather/common/src/entities/mule.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Mule; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Mule).add(EntityKind::Mule); +} diff --git a/feather/common/src/entities/ocelot.rs b/feather/common/src/entities/ocelot.rs new file mode 100644 index 000000000..0e1d4c528 --- /dev/null +++ b/feather/common/src/entities/ocelot.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Ocelot; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Ocelot).add(EntityKind::Ocelot); +} diff --git a/feather/common/src/entities/painting.rs b/feather/common/src/entities/painting.rs new file mode 100644 index 000000000..1eaaf6117 --- /dev/null +++ b/feather/common/src/entities/painting.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Painting; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Painting).add(EntityKind::Painting); +} diff --git a/feather/common/src/entities/panda.rs b/feather/common/src/entities/panda.rs new file mode 100644 index 000000000..c63b7e116 --- /dev/null +++ b/feather/common/src/entities/panda.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Panda; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Panda).add(EntityKind::Panda); +} diff --git a/feather/common/src/entities/parrot.rs b/feather/common/src/entities/parrot.rs new file mode 100644 index 000000000..919865d45 --- /dev/null +++ b/feather/common/src/entities/parrot.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Parrot; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Parrot).add(EntityKind::Parrot); +} diff --git a/feather/common/src/entities/phantom.rs b/feather/common/src/entities/phantom.rs new file mode 100644 index 000000000..4339412d7 --- /dev/null +++ b/feather/common/src/entities/phantom.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Phantom; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Phantom).add(EntityKind::Phantom); +} diff --git a/feather/common/src/entities/pig.rs b/feather/common/src/entities/pig.rs new file mode 100644 index 000000000..210cf2c0a --- /dev/null +++ b/feather/common/src/entities/pig.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Pig; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Pig).add(EntityKind::Pig); +} diff --git a/feather/common/src/entities/piglin.rs b/feather/common/src/entities/piglin.rs new file mode 100644 index 000000000..3c759c2e5 --- /dev/null +++ b/feather/common/src/entities/piglin.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Piglin; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Piglin).add(EntityKind::Piglin); +} diff --git a/feather/common/src/entities/piglin_brute.rs b/feather/common/src/entities/piglin_brute.rs new file mode 100644 index 000000000..b9d371464 --- /dev/null +++ b/feather/common/src/entities/piglin_brute.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::PiglinBrute; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(PiglinBrute).add(EntityKind::PiglinBrute); +} diff --git a/feather/common/src/entities/pillager.rs b/feather/common/src/entities/pillager.rs new file mode 100644 index 000000000..3e76f800b --- /dev/null +++ b/feather/common/src/entities/pillager.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Pillager; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Pillager).add(EntityKind::Pillager); +} diff --git a/feather/common/src/entities/player.rs b/feather/common/src/entities/player.rs new file mode 100644 index 000000000..a8cc7443a --- /dev/null +++ b/feather/common/src/entities/player.rs @@ -0,0 +1,40 @@ +use anyhow::bail; +use base::EntityKind; +use ecs::{EntityBuilder, SysResult}; +use quill_common::{ + components::{CreativeFlying, Sneaking, Sprinting}, + entities::Player, +}; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder + .add(Player) + .add(CreativeFlying(false)) + .add(Sneaking(false)) + .add(Sprinting(false)) + .add(EntityKind::Player); +} + +/// The hotbar slot a player's cursor is currently on +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub struct HotbarSlot(usize); + +impl HotbarSlot { + pub fn new(id: usize) -> Self { + Self(id) + } + + pub fn get(&self) -> usize { + self.0 + } + + pub fn set(&mut self, id: usize) -> SysResult { + if id > 8 { + bail!("invalid hotbar slot id"); + } + + self.0 = id; + Ok(()) + } +} diff --git a/feather/common/src/entities/polar_bear.rs b/feather/common/src/entities/polar_bear.rs new file mode 100644 index 000000000..532bf6791 --- /dev/null +++ b/feather/common/src/entities/polar_bear.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::PolarBear; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(PolarBear).add(EntityKind::PolarBear); +} diff --git a/feather/common/src/entities/potion.rs b/feather/common/src/entities/potion.rs new file mode 100644 index 000000000..cccf07566 --- /dev/null +++ b/feather/common/src/entities/potion.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Potion; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Potion).add(EntityKind::Potion); +} diff --git a/feather/common/src/entities/pufferfish.rs b/feather/common/src/entities/pufferfish.rs new file mode 100644 index 000000000..65c67a85a --- /dev/null +++ b/feather/common/src/entities/pufferfish.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Pufferfish; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Pufferfish).add(EntityKind::Pufferfish); +} diff --git a/feather/common/src/entities/rabbit.rs b/feather/common/src/entities/rabbit.rs new file mode 100644 index 000000000..4b2582fb0 --- /dev/null +++ b/feather/common/src/entities/rabbit.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Rabbit; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Rabbit).add(EntityKind::Rabbit); +} diff --git a/feather/common/src/entities/ravager.rs b/feather/common/src/entities/ravager.rs new file mode 100644 index 000000000..e0d574c73 --- /dev/null +++ b/feather/common/src/entities/ravager.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Ravager; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Ravager).add(EntityKind::Ravager); +} diff --git a/feather/common/src/entities/salmon.rs b/feather/common/src/entities/salmon.rs new file mode 100644 index 000000000..178ef9d21 --- /dev/null +++ b/feather/common/src/entities/salmon.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Salmon; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Salmon).add(EntityKind::Salmon); +} diff --git a/feather/common/src/entities/sheep.rs b/feather/common/src/entities/sheep.rs new file mode 100644 index 000000000..d0ca5449d --- /dev/null +++ b/feather/common/src/entities/sheep.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Sheep; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Sheep).add(EntityKind::Sheep); +} diff --git a/feather/common/src/entities/shulker.rs b/feather/common/src/entities/shulker.rs new file mode 100644 index 000000000..9643d8e29 --- /dev/null +++ b/feather/common/src/entities/shulker.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Shulker; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Shulker).add(EntityKind::Shulker); +} diff --git a/feather/common/src/entities/shulker_bullet.rs b/feather/common/src/entities/shulker_bullet.rs new file mode 100644 index 000000000..796b272b2 --- /dev/null +++ b/feather/common/src/entities/shulker_bullet.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ShulkerBullet; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(ShulkerBullet).add(EntityKind::ShulkerBullet); +} diff --git a/feather/common/src/entities/silverfish.rs b/feather/common/src/entities/silverfish.rs new file mode 100644 index 000000000..ab6e939ab --- /dev/null +++ b/feather/common/src/entities/silverfish.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Silverfish; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Silverfish).add(EntityKind::Silverfish); +} diff --git a/feather/common/src/entities/skeleton.rs b/feather/common/src/entities/skeleton.rs new file mode 100644 index 000000000..6f72c12b3 --- /dev/null +++ b/feather/common/src/entities/skeleton.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Skeleton; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Skeleton).add(EntityKind::Skeleton); +} diff --git a/feather/common/src/entities/skeleton_horse.rs b/feather/common/src/entities/skeleton_horse.rs new file mode 100644 index 000000000..cf8a2c96e --- /dev/null +++ b/feather/common/src/entities/skeleton_horse.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::SkeletonHorse; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(SkeletonHorse).add(EntityKind::SkeletonHorse); +} diff --git a/feather/common/src/entities/slime.rs b/feather/common/src/entities/slime.rs new file mode 100644 index 000000000..809221504 --- /dev/null +++ b/feather/common/src/entities/slime.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Slime; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Slime).add(EntityKind::Slime); +} diff --git a/feather/common/src/entities/small_fireball.rs b/feather/common/src/entities/small_fireball.rs new file mode 100644 index 000000000..f3eac8f9a --- /dev/null +++ b/feather/common/src/entities/small_fireball.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::SmallFireball; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(SmallFireball).add(EntityKind::SmallFireball); +} diff --git a/feather/common/src/entities/snow_golem.rs b/feather/common/src/entities/snow_golem.rs new file mode 100644 index 000000000..01193a73e --- /dev/null +++ b/feather/common/src/entities/snow_golem.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::SnowGolem; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(SnowGolem).add(EntityKind::SnowGolem); +} diff --git a/feather/common/src/entities/snowball.rs b/feather/common/src/entities/snowball.rs new file mode 100644 index 000000000..f5bafff66 --- /dev/null +++ b/feather/common/src/entities/snowball.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Snowball; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Snowball).add(EntityKind::Snowball); +} diff --git a/feather/common/src/entities/spawner_minecart.rs b/feather/common/src/entities/spawner_minecart.rs new file mode 100644 index 000000000..550ccde67 --- /dev/null +++ b/feather/common/src/entities/spawner_minecart.rs @@ -0,0 +1,10 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::SpawnerMinecart; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder + .add(SpawnerMinecart) + .add(EntityKind::SpawnerMinecart); +} diff --git a/feather/common/src/entities/spectral_arrow.rs b/feather/common/src/entities/spectral_arrow.rs new file mode 100644 index 000000000..adc604636 --- /dev/null +++ b/feather/common/src/entities/spectral_arrow.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::SpectralArrow; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(SpectralArrow).add(EntityKind::SpectralArrow); +} diff --git a/feather/common/src/entities/spider.rs b/feather/common/src/entities/spider.rs new file mode 100644 index 000000000..9f1a6c688 --- /dev/null +++ b/feather/common/src/entities/spider.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Spider; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Spider).add(EntityKind::Spider); +} diff --git a/feather/common/src/entities/squid.rs b/feather/common/src/entities/squid.rs new file mode 100644 index 000000000..8743b62a1 --- /dev/null +++ b/feather/common/src/entities/squid.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Squid; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Squid).add(EntityKind::Squid); +} diff --git a/feather/common/src/entities/stray.rs b/feather/common/src/entities/stray.rs new file mode 100644 index 000000000..dd38847aa --- /dev/null +++ b/feather/common/src/entities/stray.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Stray; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Stray).add(EntityKind::Stray); +} diff --git a/feather/common/src/entities/strider.rs b/feather/common/src/entities/strider.rs new file mode 100644 index 000000000..b94f79706 --- /dev/null +++ b/feather/common/src/entities/strider.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Strider; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Strider).add(EntityKind::Strider); +} diff --git a/feather/common/src/entities/tnt.rs b/feather/common/src/entities/tnt.rs new file mode 100644 index 000000000..8adefb369 --- /dev/null +++ b/feather/common/src/entities/tnt.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Tnt; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Tnt).add(EntityKind::Tnt); +} diff --git a/feather/common/src/entities/tnt_minecart.rs b/feather/common/src/entities/tnt_minecart.rs new file mode 100644 index 000000000..77b2bca36 --- /dev/null +++ b/feather/common/src/entities/tnt_minecart.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::TntMinecart; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(TntMinecart).add(EntityKind::TntMinecart); +} diff --git a/feather/common/src/entities/trader_llama.rs b/feather/common/src/entities/trader_llama.rs new file mode 100644 index 000000000..58e0310a4 --- /dev/null +++ b/feather/common/src/entities/trader_llama.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::TraderLlama; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(TraderLlama).add(EntityKind::TraderLlama); +} diff --git a/feather/common/src/entities/trident.rs b/feather/common/src/entities/trident.rs new file mode 100644 index 000000000..b5a9a2bfa --- /dev/null +++ b/feather/common/src/entities/trident.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Trident; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Trident).add(EntityKind::Trident); +} diff --git a/feather/common/src/entities/tropical_fish.rs b/feather/common/src/entities/tropical_fish.rs new file mode 100644 index 000000000..381e50aa0 --- /dev/null +++ b/feather/common/src/entities/tropical_fish.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::TropicalFish; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(TropicalFish).add(EntityKind::TropicalFish); +} diff --git a/feather/common/src/entities/turtle.rs b/feather/common/src/entities/turtle.rs new file mode 100644 index 000000000..16c776443 --- /dev/null +++ b/feather/common/src/entities/turtle.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Turtle; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Turtle).add(EntityKind::Turtle); +} diff --git a/feather/common/src/entities/vex.rs b/feather/common/src/entities/vex.rs new file mode 100644 index 000000000..3a92f1cdf --- /dev/null +++ b/feather/common/src/entities/vex.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Vex; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Vex).add(EntityKind::Vex); +} diff --git a/feather/common/src/entities/villager.rs b/feather/common/src/entities/villager.rs new file mode 100644 index 000000000..5db272b24 --- /dev/null +++ b/feather/common/src/entities/villager.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Villager; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Villager).add(EntityKind::Villager); +} diff --git a/feather/common/src/entities/vindicator.rs b/feather/common/src/entities/vindicator.rs new file mode 100644 index 000000000..fff0ea097 --- /dev/null +++ b/feather/common/src/entities/vindicator.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Vindicator; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Vindicator).add(EntityKind::Vindicator); +} diff --git a/feather/common/src/entities/wandering_trader.rs b/feather/common/src/entities/wandering_trader.rs new file mode 100644 index 000000000..db57b88c1 --- /dev/null +++ b/feather/common/src/entities/wandering_trader.rs @@ -0,0 +1,10 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::WanderingTrader; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder + .add(WanderingTrader) + .add(EntityKind::WanderingTrader); +} diff --git a/feather/common/src/entities/witch.rs b/feather/common/src/entities/witch.rs new file mode 100644 index 000000000..a3161895a --- /dev/null +++ b/feather/common/src/entities/witch.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Witch; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Witch).add(EntityKind::Witch); +} diff --git a/feather/common/src/entities/wither.rs b/feather/common/src/entities/wither.rs new file mode 100644 index 000000000..02fa1fe78 --- /dev/null +++ b/feather/common/src/entities/wither.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Wither; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Wither).add(EntityKind::Wither); +} diff --git a/feather/common/src/entities/wither_skeleton.rs b/feather/common/src/entities/wither_skeleton.rs new file mode 100644 index 000000000..085b9e280 --- /dev/null +++ b/feather/common/src/entities/wither_skeleton.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::WitherSkeleton; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(WitherSkeleton).add(EntityKind::WitherSkeleton); +} diff --git a/feather/common/src/entities/wither_skull.rs b/feather/common/src/entities/wither_skull.rs new file mode 100644 index 000000000..59b871555 --- /dev/null +++ b/feather/common/src/entities/wither_skull.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::WitherSkull; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(WitherSkull).add(EntityKind::WitherSkull); +} diff --git a/feather/common/src/entities/wolf.rs b/feather/common/src/entities/wolf.rs new file mode 100644 index 000000000..cc07cb7db --- /dev/null +++ b/feather/common/src/entities/wolf.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Wolf; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Wolf).add(EntityKind::Wolf); +} diff --git a/feather/common/src/entities/zoglin.rs b/feather/common/src/entities/zoglin.rs new file mode 100644 index 000000000..79d6ab4e5 --- /dev/null +++ b/feather/common/src/entities/zoglin.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Zoglin; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Zoglin).add(EntityKind::Zoglin); +} diff --git a/feather/common/src/entities/zombie.rs b/feather/common/src/entities/zombie.rs new file mode 100644 index 000000000..eeb456878 --- /dev/null +++ b/feather/common/src/entities/zombie.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::Zombie; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(Zombie).add(EntityKind::Zombie); +} diff --git a/feather/common/src/entities/zombie_horse.rs b/feather/common/src/entities/zombie_horse.rs new file mode 100644 index 000000000..44a7e0919 --- /dev/null +++ b/feather/common/src/entities/zombie_horse.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ZombieHorse; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(ZombieHorse).add(EntityKind::ZombieHorse); +} diff --git a/feather/common/src/entities/zombie_villager.rs b/feather/common/src/entities/zombie_villager.rs new file mode 100644 index 000000000..29ae9d02c --- /dev/null +++ b/feather/common/src/entities/zombie_villager.rs @@ -0,0 +1,8 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ZombieVillager; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder.add(ZombieVillager).add(EntityKind::ZombieVillager); +} diff --git a/feather/common/src/entities/zombified_piglin.rs b/feather/common/src/entities/zombified_piglin.rs new file mode 100644 index 000000000..83b300f7b --- /dev/null +++ b/feather/common/src/entities/zombified_piglin.rs @@ -0,0 +1,10 @@ +use base::EntityKind; +use ecs::EntityBuilder; +use quill_common::entities::ZombifiedPiglin; + +pub fn build_default(builder: &mut EntityBuilder) { + super::build_default(builder); + builder + .add(ZombifiedPiglin) + .add(EntityKind::ZombifiedPiglin); +} diff --git a/feather/common/src/entity/player.rs b/feather/common/src/entity/player.rs new file mode 100644 index 000000000..605fa6769 --- /dev/null +++ b/feather/common/src/entity/player.rs @@ -0,0 +1,10 @@ +use base::EntityKind; +use ecs::EntityBuilder; + +/// Marker component. Indicates that an entity is a player. +pub struct Player; + +/// Fills an `EntityBuilder` with components for a player. +pub fn build(builder: &mut EntityBuilder) -> &mut EntityBuilder { + builder.add(Player).add(EntityKind::Player) +} diff --git a/feather/common/src/events.rs b/feather/common/src/events.rs new file mode 100644 index 000000000..114540089 --- /dev/null +++ b/feather/common/src/events.rs @@ -0,0 +1,60 @@ +use base::{ChunkHandle, ChunkPosition}; + +use crate::view::View; + +mod block_change; +mod plugin_message; + +pub use block_change::BlockChangeEvent; +pub use plugin_message::PluginMessageEvent; + +/// Event triggered when a player changes their `View`, +/// meaning they crossed into a new chunk. +#[derive(Debug)] +pub struct ViewUpdateEvent { + pub old_view: View, + pub new_view: View, + + /// Chunks that are in `new_view` but not `old_view` + pub new_chunks: Vec<ChunkPosition>, + /// Chunks that are in `old_view` but not in `new_view` + pub old_chunks: Vec<ChunkPosition>, +} + +impl ViewUpdateEvent { + pub fn new(old_view: View, new_view: View) -> Self { + let mut this = Self { + old_view, + new_view, + new_chunks: new_view.difference(old_view).collect(), + old_chunks: old_view.difference(new_view).collect(), + }; + this.new_chunks + .sort_unstable_by_key(|chunk| chunk.distance_squared_to(new_view.center())); + this.old_chunks + .sort_unstable_by_key(|chunk| chunk.distance_squared_to(old_view.center())); + this + } +} + +/// Event triggered when an entity crosses into a new chunk. +/// +/// Unlike [`ViewUpdateEvent`], this event triggers for all entities, +/// not just players. +pub struct ChunkCrossEvent { + pub old_chunk: ChunkPosition, + pub new_chunk: ChunkPosition, +} + +/// Triggered when a chunk is loaded. +#[derive(Debug)] +pub struct ChunkLoadEvent { + pub position: ChunkPosition, + pub chunk: ChunkHandle, +} + +/// Triggered when an error occurs while loading a chunk. +#[derive(Debug)] +pub struct ChunkLoadFailEvent { + pub position: ChunkPosition, +} diff --git a/feather/common/src/events/block_change.rs b/feather/common/src/events/block_change.rs new file mode 100644 index 000000000..bb92ba52d --- /dev/null +++ b/feather/common/src/events/block_change.rs @@ -0,0 +1,152 @@ +use std::{convert::TryInto, iter}; + +use base::{ + chunk::{SECTION_HEIGHT, SECTION_VOLUME}, + BlockPosition, ChunkPosition, ValidBlockPosition, +}; +use itertools::Either; + +/// Event triggered when one or more blocks are changed. +/// +/// This event can efficiently store bulk block updates +/// using a variety of different representations. Cloning +/// is cheap as it is, at worst, cloning an `Arc`. +#[derive(Debug, Clone)] +pub struct BlockChangeEvent { + changes: BlockChanges, +} + +impl BlockChangeEvent { + /// Creates an event affecting a single block. + pub fn single(pos: ValidBlockPosition) -> Self { + Self { + changes: BlockChanges::Single { pos }, + } + } + + /// Creates an event corresponding to a block update + /// that fills an entire chunk section with the same block. + pub fn fill_chunk_section(chunk: ChunkPosition, section: u32) -> Self { + Self { + changes: BlockChanges::FillChunkSection { chunk, section }, + } + } + + /// Determines the number of blocks that were + /// changed in this block change event. + pub fn count(&self) -> usize { + match &self.changes { + BlockChanges::Single { .. } => 1, + BlockChanges::FillChunkSection { .. } => SECTION_VOLUME, + } + } + + /// Returns an iterator over block positions affected by this block change. + pub fn iter_changed_blocks(&self) -> impl Iterator<Item = ValidBlockPosition> + '_ { + match &self.changes { + BlockChanges::Single { pos } => Either::Left(iter::once(*pos)), + BlockChanges::FillChunkSection { chunk, section } => { + Either::Right(iter_section_blocks(*chunk, *section)) + } + } + } + + /// Returns an iterator over chunk section positions affected by this block change. + /// + /// The yielded tuple consists of `(chunk, section_y, num_changed_blocks)`, + /// where `num_changed_blocks` is the number of blocks changed within that chunk. + pub fn iter_affected_chunk_sections( + &self, + ) -> impl Iterator<Item = (ChunkPosition, usize, usize)> + '_ { + match &self.changes { + BlockChanges::Single { pos } => { + iter::once((pos.chunk(), pos.y() as usize / SECTION_HEIGHT, 1)) + } + BlockChanges::FillChunkSection { chunk, section } => { + iter::once((*chunk, *section as usize, SECTION_VOLUME)) + } + } + } +} + +fn iter_section_blocks( + chunk: ChunkPosition, + section: u32, +) -> impl Iterator<Item = ValidBlockPosition> { + (0..16) + .flat_map(|x| (0..16).map(move |y| (x, y))) + .flat_map(|(x, y)| (0..16).map(move |z| (x, y, z))) + .map(move |(dx, dy, dz)| { + let x = dx + chunk.x * 16; + let y = dy + section as i32 * 16; + let z = dz + chunk.z * 16; + + // It's safe to unwrap because we are working from a valid source of block positions + BlockPosition::new(x, y, z).try_into().unwrap() + }) +} + +#[derive(Debug, Clone)] +enum BlockChanges { + /// A single block change. + Single { pos: ValidBlockPosition }, + /// A whole chunk section was filled with the same block. + FillChunkSection { chunk: ChunkPosition, section: u32 }, +} + +#[cfg(test)] +mod tests { + use ahash::AHashSet; + use base::chunk::SECTION_VOLUME; + + use super::*; + + #[test] + fn create_single() { + let pos = BlockPosition::new(5, 64, 9).try_into().unwrap(); + let event = BlockChangeEvent::single(pos); + assert_eq!(event.count(), 1); + assert_eq!(event.iter_changed_blocks().collect::<Vec<_>>(), vec![pos]); + assert_eq!( + event.iter_affected_chunk_sections().collect::<Vec<_>>(), + vec![(pos.chunk(), 4, 1)] + ); + } + + #[test] + fn create_chunk_section_fill() { + let chunk = ChunkPosition::new(10, 15); + let section_y = 5; + let event = BlockChangeEvent::fill_chunk_section(chunk, section_y); + assert_eq!(event.count(), SECTION_VOLUME); + assert_eq!(event.iter_changed_blocks().count(), SECTION_VOLUME); + assert_eq!( + event.iter_affected_chunk_sections().collect::<Vec<_>>(), + vec![(chunk, section_y as usize, SECTION_VOLUME)] + ); + } + + #[test] + fn test_iter_section_blocks() { + let blocks: Vec<ValidBlockPosition> = + iter_section_blocks(ChunkPosition::new(-1, -2), 5).collect(); + let unique_blocks: AHashSet<ValidBlockPosition> = blocks.iter().copied().collect(); + + assert_eq!(blocks.len(), unique_blocks.len()); + assert_eq!(blocks.len(), SECTION_VOLUME); + + for x in -16..0 { + for y in 80..96 { + for z in -32..-16 { + assert!( + unique_blocks.contains(&BlockPosition::new(x, y, z).try_into().unwrap()), + "{}, {}, {}", + x, + y, + z + ); + } + } + } + } +} diff --git a/feather/common/src/events/plugin_message.rs b/feather/common/src/events/plugin_message.rs new file mode 100644 index 000000000..b648ae375 --- /dev/null +++ b/feather/common/src/events/plugin_message.rs @@ -0,0 +1,5 @@ +#[derive(Debug)] +pub struct PluginMessageEvent { + pub channel: String, + pub data: Vec<u8>, +} diff --git a/feather/common/src/game.rs b/feather/common/src/game.rs new file mode 100644 index 000000000..64e6bf87d --- /dev/null +++ b/feather/common/src/game.rs @@ -0,0 +1,249 @@ +use std::{cell::RefCell, mem, rc::Rc, sync::Arc}; + +use base::{BlockId, ChunkPosition, Position, Text, Title, ValidBlockPosition}; +use ecs::{ + Ecs, Entity, EntityBuilder, HasEcs, HasResources, NoSuchEntity, Resources, SysResult, + SystemExecutor, +}; +use quill_common::events::{EntityCreateEvent, EntityRemoveEvent, PlayerJoinEvent}; +use quill_common::{entities::Player, entity_init::EntityInit}; + +use crate::{ + chat::{ChatKind, ChatMessage}, + chunk::entities::ChunkEntities, + events::BlockChangeEvent, + ChatBox, World, +}; + +type EntitySpawnCallback = Box<dyn FnMut(&mut EntityBuilder, &EntityInit)>; + +/// Stores the entire state of a Minecraft game. +/// +/// This contains: +/// * A [`World`](crate::World) containing chunks and blocks. +/// * An [`Ecs`](ecs::Ecs) containing entities. +/// * A [`Resources`](ecs::Resources) containing additional, user-defined data. +/// * A [`SystemExecutor`] to run systems. +/// +/// `feather-common` provides `Game` methods for actions such +/// as "drop item" or "kill entity." These high-level methods +/// should be preferred over raw interaction with the ECS. +pub struct Game { + /// Contains chunks and blocks. + /// + /// NB: use methods on `Game` to update + /// blocks, not direct methods on `World`. + /// The `Game` methods will automatically + /// trigger the necessary `BlockChangeEvent`s. + pub world: World, + /// Contains entities, including players. + pub ecs: Ecs, + /// Contains systems. + pub system_executor: Rc<RefCell<SystemExecutor<Game>>>, + + /// User-defined resources. + /// + /// Stored in an `Arc` for borrow-checker purposes. + pub resources: Arc<Resources>, + + /// A spatial index to efficiently find which entities are in a given chunk. + pub chunk_entities: ChunkEntities, + + /// Total ticks elapsed since the server started. + pub tick_count: u64, + + entity_spawn_callbacks: Vec<EntitySpawnCallback>, + + entity_builder: EntityBuilder, +} + +impl Default for Game { + fn default() -> Self { + Self::new() + } +} + +impl Game { + /// Creates a new, empty `Game`. + pub fn new() -> Self { + Self { + world: World::new(), + ecs: Ecs::new(), + system_executor: Rc::new(RefCell::new(SystemExecutor::new())), + resources: Arc::new(Resources::new()), + chunk_entities: ChunkEntities::default(), + tick_count: 0, + entity_spawn_callbacks: Vec::new(), + entity_builder: EntityBuilder::new(), + } + } + + /// Inserts a new resource. + /// + /// An existing resource with type `T` is overriden. + /// + /// # Panics + /// Panics if any resources are currently borrowed. + pub fn insert_resource<T>(&mut self, resource: T) + where + T: 'static, + { + Arc::get_mut(&mut self.resources) + .expect("attempted to insert into resources while resources are borrowed") + .insert(resource); + } + + /// Adds a new entity spawn callback, invoked + /// before an entity is created. + /// + /// This allows you to add components to entities + /// before they are built. + pub fn add_entity_spawn_callback( + &mut self, + callback: impl FnMut(&mut EntityBuilder, &EntityInit) + 'static, + ) { + self.entity_spawn_callbacks.push(Box::new(callback)); + } + + /// Creates an empty entity builder to create entities in + /// the ecs world. + pub fn create_empty_entity_builder(&mut self) -> EntityBuilder { + mem::take(&mut self.entity_builder) + } + + /// Creates an entity builder with the default components + /// for an entity of type `init`. + pub fn create_entity_builder(&mut self, position: Position, init: EntityInit) -> EntityBuilder { + let mut builder = mem::take(&mut self.entity_builder); + builder.add(position); + self.invoke_entity_spawn_callbacks(&mut builder, init); + builder + } + + /// Spawns an entity and returns its [`Entity`](ecs::Entity) handle. + /// + /// Also triggers necessary events, like `EntitySpawnEvent` and `PlayerJoinEvent`. + pub fn spawn_entity(&mut self, mut builder: EntityBuilder) -> Entity { + let entity = self.ecs.spawn(builder.build()); + self.entity_builder = builder; + + self.trigger_entity_spawn_events(entity); + + entity + } + + fn invoke_entity_spawn_callbacks(&mut self, builder: &mut EntityBuilder, init: EntityInit) { + let mut callbacks = mem::take(&mut self.entity_spawn_callbacks); + for callback in &mut callbacks { + callback(builder, &init); + } + self.entity_spawn_callbacks = callbacks; + } + + fn trigger_entity_spawn_events(&mut self, entity: Entity) { + self.ecs + .insert_entity_event(entity, EntityCreateEvent) + .unwrap(); + if self.ecs.get::<Player>(entity).is_ok() { + self.ecs + .insert_entity_event(entity, PlayerJoinEvent) + .unwrap(); + } + } + + /// Causes the given entity to be removed on the next tick. + /// In the meantime, triggers `EntityRemoveEvent`. + pub fn remove_entity(&mut self, entity: Entity) -> Result<(), NoSuchEntity> { + self.ecs.defer_despawn(entity); + self.ecs.insert_entity_event(entity, EntityRemoveEvent) + } + + /// Broadcasts a chat message to all entities with + /// a `ChatBox` component (usually just players). + pub fn broadcast_chat(&self, kind: ChatKind, message: impl Into<Text>) { + let message = message.into(); + for (_, mailbox) in self.ecs.query::<&mut ChatBox>().iter() { + mailbox.send(ChatMessage::new(kind, message.clone())); + } + } + + /// Utility method to send a message to an entity. + pub fn send_message(&mut self, entity: Entity, message: ChatMessage) -> SysResult { + let mut mailbox = self.ecs.get_mut::<ChatBox>(entity)?; + mailbox.send(message); + Ok(()) + } + + /// Utility method to send a title to an entity. + pub fn send_title(&mut self, entity: Entity, title: Title) -> SysResult { + let mut mailbox = self.ecs.get_mut::<ChatBox>(entity)?; + mailbox.send_title(title); + Ok(()) + } + + /// Gets the block at the given position. + pub fn block(&self, pos: ValidBlockPosition) -> Option<BlockId> { + self.world.block_at(pos) + } + + /// Sets the block at the given position. + /// + /// Triggers necessary `BlockChangeEvent`s. + pub fn set_block(&mut self, pos: ValidBlockPosition, block: BlockId) -> bool { + let was_successful = self.world.set_block_at(pos, block); + if was_successful { + self.ecs.insert_event(BlockChangeEvent::single(pos)); + } + was_successful + } + + /// Fills the given chunk section (16x16x16 blocks). + /// + /// All blocks in the chunk section are overwritten with `block`. + pub fn fill_chunk_section( + &mut self, + chunk_pos: ChunkPosition, + section_y: usize, + block: BlockId, + ) -> bool { + let mut chunk = match self.world.chunk_map().chunk_at_mut(chunk_pos) { + Some(chunk) => chunk, + None => return false, + }; + + let was_successful = chunk.fill_section(section_y + 1, block); + + if !was_successful { + return false; + } + + self.ecs.insert_event(BlockChangeEvent::fill_chunk_section( + chunk_pos, + section_y as u32, + )); + + true + } + + /// Breaks the block at the given position, propagating any + /// necessary block updates. + pub fn break_block(&mut self, pos: ValidBlockPosition) -> bool { + self.set_block(pos, BlockId::air()) + } +} + +impl HasResources for Game { + fn resources(&self) -> Arc<Resources> { + Arc::clone(&self.resources) + } +} + +impl HasEcs for Game { + fn ecs(&self) -> &Ecs { + &self.ecs + } + + fn ecs_mut(&mut self) -> &mut Ecs { + &mut self.ecs + } +} diff --git a/feather/common/src/interactable.rs b/feather/common/src/interactable.rs new file mode 100644 index 000000000..59966a2bc --- /dev/null +++ b/feather/common/src/interactable.rs @@ -0,0 +1,62 @@ +use std::collections::HashMap; + +use blocks::BlockKind; + +use crate::Game; + +#[derive(Default)] +pub struct InteractableRegistry { + registry: HashMap<BlockKind, usize>, +} + +impl InteractableRegistry { + /// Creates a new, empty [`InteractableRegistry`] + pub fn new() -> Self { + Self { + registry: HashMap::new(), + } + } + + /// Registers that there is a handler that handles interactions + /// with the [`BlockKind`]. + pub fn register(&mut self, block: BlockKind) { + let value = self.registry.get(&block).copied(); + + match value { + Some(count) => { + self.registry.insert(block, count + 1); + } + None => { + self.registry.insert(block, 1); + } + } + } + + /// Deregisters a handler for a block interaction. + pub fn deregister(&mut self, block: BlockKind) { + let value = self.registry.get(&block).copied(); + + match value { + Some(count) => { + if count == 0 { + panic!( + "Tried to deregister an interaction handler on a block with 0 handlers." + ); + } else { + self.registry.insert(block, count - 1); + } + } + None => { + panic!("Tried to deregister an interaction handler on a block with 0 handlers.") + } + } + } + + pub fn is_registered(&self, block: BlockKind) -> bool { + self.registry.get(&block).is_some() + } +} + +pub fn register(game: &mut Game) { + game.insert_resource(InteractableRegistry::default()); +} diff --git a/feather/common/src/lib.rs b/feather/common/src/lib.rs new file mode 100644 index 000000000..9f9e7348a --- /dev/null +++ b/feather/common/src/lib.rs @@ -0,0 +1,43 @@ +//! Gameplay functionality: entities, components, systems, game logic, ... +//! +//! This crate implements most functionality that is generic between +//! client and server, i.e., which does not involve interaction with the network. + +#![allow(clippy::unnecessary_wraps)] // systems are required to return Results + +mod game; +use ecs::SystemExecutor; +pub use game::Game; + +mod tick_loop; +pub use tick_loop::TickLoop; + +pub mod view; + +pub mod window; +pub use window::Window; + +pub mod events; + +pub mod chunk; +mod region_worker; + +pub mod world; +pub use world::World; + +pub mod chat; +pub use chat::ChatBox; + +pub mod entities; + +pub mod interactable; + +/// Registers gameplay systems with the given `Game` and `SystemExecutor`. +pub fn register(game: &mut Game, systems: &mut SystemExecutor<Game>) { + view::register(game, systems); + chunk::loading::register(game, systems); + chunk::entities::register(systems); + interactable::register(game); + + game.add_entity_spawn_callback(entities::add_entity_components); +} diff --git a/feather/common/src/region_worker.rs b/feather/common/src/region_worker.rs new file mode 100644 index 000000000..dac33c985 --- /dev/null +++ b/feather/common/src/region_worker.rs @@ -0,0 +1,165 @@ +use std::{ + collections::hash_map::Entry, + path::PathBuf, + time::{Duration, Instant}, +}; + +use ahash::AHashMap; +use base::anvil::{ + self, + region::{RegionHandle, RegionPosition}, +}; +use flume::{Receiver, Sender}; + +use crate::chunk::worker::{ChunkLoadResult, LoadRequest, LoadedChunk, SaveRequest, WorkerRequest}; + +/// Duration to keep a region file open when not in use. +const CACHE_TIME: Duration = Duration::from_secs(60); + +struct OpenRegionFile { + handle: RegionHandle, + last_used: Instant, +} + +impl OpenRegionFile { + pub fn new(handle: RegionHandle) -> Self { + Self { + handle, + last_used: Instant::now(), + } + } + + pub fn should_close(&self) -> bool { + self.last_used.elapsed() >= CACHE_TIME + } +} + +pub struct RegionWorker { + request_receiver: Receiver<WorkerRequest>, + result_sender: Sender<ChunkLoadResult>, + world_dir: PathBuf, + region_files: AHashMap<RegionPosition, OpenRegionFile>, + last_cache_update: Instant, +} + +impl RegionWorker { + pub fn new( + world_dir: PathBuf, + request_receiver: Receiver<WorkerRequest>, + ) -> (Self, Receiver<ChunkLoadResult>) { + let (result_sender, result_receiver) = flume::bounded(256); + ( + Self { + request_receiver, + result_sender, + world_dir, + region_files: AHashMap::new(), + last_cache_update: Instant::now(), + }, + result_receiver, + ) + } + + pub fn start(self) { + std::thread::Builder::new() + .name("chunk_worker".to_owned()) + .spawn(move || self.run()) + .expect("failed to create chunk worker thread"); + } + + fn run(mut self) { + log::info!("Chunk worker started"); + loop { + match self.request_receiver.recv_timeout(CACHE_TIME) { + Ok(req) => match req { + WorkerRequest::Load(load) => self.load_chunk(load), + WorkerRequest::Save(save) => self.save_chunk(save).unwrap(), + }, + Err(flume::RecvTimeoutError::Timeout) => (), + Err(flume::RecvTimeoutError::Disconnected) => { + log::info!("Chunk worker shutting down"); + return; + } + } + self.update_cache(); + } + } + + fn save_chunk(&mut self, req: SaveRequest) -> anyhow::Result<()> { + let reg_pos = RegionPosition::from_chunk(req.pos); + let handle = &mut match self.region_file_handle(reg_pos) { + Some(h) => h, + None => { + let new_handle = anvil::region::create_region(&self.world_dir, reg_pos)?; + self.region_files + .insert(reg_pos, OpenRegionFile::new(new_handle)); + self.region_file_handle(reg_pos).unwrap() + } + } + .handle; + handle.save_chunk( + &req.chunk.read(), + &req.entities[..], + &req.block_entities[..], + )?; + Ok(()) + } + + fn load_chunk(&mut self, req: LoadRequest) { + let result = self.get_chunk_load_result(req); + let _ = self.result_sender.send(result); + } + + fn get_chunk_load_result(&mut self, req: LoadRequest) -> ChunkLoadResult { + let pos = req.pos; + let region = RegionPosition::from_chunk(pos); + let file = match self.region_file_handle(region) { + Some(file) => file, + None => return ChunkLoadResult::Missing(pos), + }; + + let chunk = match file.handle.load_chunk(pos) { + Ok((chunk, _, _)) => chunk, + Err(e) => match e { + anvil::region::Error::ChunkNotExist => return ChunkLoadResult::Missing(pos), + err => return ChunkLoadResult::Error(err.into()), + }, + }; + + file.last_used = Instant::now(); + + ChunkLoadResult::Loaded(LoadedChunk { pos, chunk }) + } + + fn region_file_handle(&mut self, region: RegionPosition) -> Option<&mut OpenRegionFile> { + match self.region_files.entry(region) { + Entry::Occupied(e) => Some(e.into_mut()), + Entry::Vacant(e) => { + let handle = base::anvil::region::load_region(&self.world_dir, region); + if let Ok(handle) = handle { + Some(e.insert(OpenRegionFile::new(handle))) + } else { + None + } + } + } + } + + fn update_cache(&mut self) { + if self.last_cache_update.elapsed() >= CACHE_TIME { + let initial_len = self.region_files.len(); + + self.region_files.retain(|_, file| !file.should_close()); + self.last_cache_update = Instant::now(); + + let num_closed = initial_len - self.region_files.len(); + if num_closed != 0 { + log::debug!( + "Closed {} region files ({} still open)", + num_closed, + self.region_files.len() + ); + } + } + } +} diff --git a/feather/common/src/tick_loop.rs b/feather/common/src/tick_loop.rs new file mode 100644 index 000000000..8709087c7 --- /dev/null +++ b/feather/common/src/tick_loop.rs @@ -0,0 +1,38 @@ +use std::time::Instant; + +use base::TICK_DURATION; + +/// Utility to invoke a function in a tick loop, once +/// every 50ms. +pub struct TickLoop { + function: Box<dyn FnMut() -> bool>, +} + +impl TickLoop { + /// Creates a `TickLoop`. The given `function` is called + /// each tick. Returning `true` from `function` causes the + /// tick loop to exit. + pub fn new(function: impl FnMut() -> bool + 'static) -> Self { + Self { + function: Box::new(function), + } + } + + /// Runs the tick loop until the callback returns `true`. + pub fn run(mut self) { + loop { + let start = Instant::now(); + let should_exit = (self.function)(); + if should_exit { + return; + } + + let elapsed = start.elapsed(); + if elapsed > TICK_DURATION { + log::warn!("Tick took too long ({:?})", elapsed); + } else { + std::thread::sleep(TICK_DURATION - elapsed); + } + } + } +} diff --git a/feather/common/src/view.rs b/feather/common/src/view.rs new file mode 100644 index 000000000..52c404f5b --- /dev/null +++ b/feather/common/src/view.rs @@ -0,0 +1,163 @@ +use ahash::AHashSet; +use base::{ChunkPosition, Position}; +use ecs::{SysResult, SystemExecutor}; +use itertools::Either; +use quill_common::components::Name; +use quill_common::events::PlayerJoinEvent; + +use crate::{events::ViewUpdateEvent, Game}; + +/// Registers systems to update the `View` of a player. +pub fn register(_game: &mut Game, systems: &mut SystemExecutor<Game>) { + systems + .add_system(update_player_views) + .add_system(update_view_on_join); +} + +/// Updates players' views when they change chunks. +fn update_player_views(game: &mut Game) -> SysResult { + let mut events = Vec::new(); + for (player, (view, &position, name)) in + game.ecs.query::<(&mut View, &Position, &Name)>().iter() + { + if position.chunk() != view.center() { + let old_view = *view; + let new_view = View::new(position.chunk(), old_view.view_distance); + + let event = ViewUpdateEvent::new(old_view, new_view); + events.push((player, event)); + + *view = new_view; + log::trace!("View of {} has been updated", name); + } + } + + for (player, event) in events { + game.ecs.insert_entity_event(player, event)?; + } + Ok(()) +} + +/// Triggers a ViewUpdateEvent when a player joins the game. +fn update_view_on_join(game: &mut Game) -> SysResult { + let mut events = Vec::new(); + for (player, (&view, name, _)) in game.ecs.query::<(&View, &Name, &PlayerJoinEvent)>().iter() { + let event = ViewUpdateEvent::new(View::empty(), view); + events.push((player, event)); + log::trace!("View of {} has been updated (player joined)", name); + } + for (player, event) in events { + game.ecs.insert_entity_event(player, event)?; + } + Ok(()) +} + +/// The view of a player, representing the set of chunks +/// within their view distance. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct View { + center: ChunkPosition, + view_distance: u32, +} + +impl View { + /// Creates a `View` from a center chunk (the position of the player) + /// and the view distance. + pub fn new(center: ChunkPosition, view_distance: u32) -> Self { + Self { + center, + view_distance, + } + } + + /// Gets the empty view, i.e., the view containing no chunks. + pub fn empty() -> Self { + Self::new(ChunkPosition::new(0, 0), 0) + } + + /// Determines whether this is the empty view. + pub fn is_empty(&self) -> bool { + self.view_distance == 0 + } + + pub fn center(&self) -> ChunkPosition { + self.center + } + + pub fn view_distance(&self) -> u32 { + self.view_distance + } + + pub fn set_center(&mut self, center: ChunkPosition) { + self.center = center; + } + + pub fn set_view_distance(&mut self, view_distance: u32) { + self.view_distance = view_distance; + } + + /// Iterates over chunks visible to the player. + pub fn iter(self) -> impl Iterator<Item = ChunkPosition> { + if self.is_empty() { + Either::Left(std::iter::empty()) + } else { + Either::Right(Self::iter_2d( + self.min_x(), + self.min_z(), + self.max_x(), + self.max_z(), + )) + } + } + + /// Returns the set of chunks that are in `self` but not in `other`. + pub fn difference(self, other: View) -> impl Iterator<Item = ChunkPosition> { + // PERF: consider analytical approach instead of sets + let self_chunks: AHashSet<_> = self.iter().collect(); + let other_chunks: AHashSet<_> = other.iter().collect(); + self_chunks + .difference(&other_chunks) + .copied() + .collect::<Vec<_>>() + .into_iter() + } + + /// Determines whether the given chunk is visible. + pub fn contains(&self, pos: ChunkPosition) -> bool { + pos.x >= self.min_x() + && pos.x <= self.max_x() + && pos.z >= self.min_z() + && pos.z <= self.max_z() + } + + fn iter_2d( + min_x: i32, + min_z: i32, + max_x: i32, + max_z: i32, + ) -> impl Iterator<Item = ChunkPosition> { + (min_x..=max_x) + .flat_map(move |x| (min_z..=max_z).map(move |z| (x, z))) + .map(|(x, z)| ChunkPosition { x, z }) + } + + /// Returns the minimum X chunk coordinate. + pub fn min_x(&self) -> i32 { + self.center.x - self.view_distance as i32 + } + + /// Returns the minimum Z coordinate. + pub fn min_z(&self) -> i32 { + self.center.z - self.view_distance as i32 + } + + /// Returns the maximum X coordinate. + pub fn max_x(&self) -> i32 { + self.center.x + self.view_distance as i32 + } + + /// Returns the maximum Z coordinate. + pub fn max_z(&self) -> i32 { + self.center.z + self.view_distance as i32 + } +} diff --git a/feather/common/src/window.rs b/feather/common/src/window.rs new file mode 100644 index 000000000..ba41b6381 --- /dev/null +++ b/feather/common/src/window.rs @@ -0,0 +1,818 @@ +use std::mem; + +use anyhow::{anyhow, bail}; + +use base::{Area, Item}; + +use ecs::SysResult; +pub use libcraft_inventory::Window as BackingWindow; +use libcraft_inventory::WindowError; +use libcraft_items::InventorySlot::{self, Empty}; +use parking_lot::MutexGuard; + +/// A player's window. Wraps one or more inventories and handles +/// conversion between protocol and slot indices. +/// +/// Also provides high-level methods to interact with the inventory, +/// like [`Window::right_click`], [`Window::shift_click`], etc. +#[derive(Debug)] +pub struct Window { + /// The backing window (contains the `Inventory`s) + inner: BackingWindow, + /// The item currently held by the player's cursor. + cursor_item: InventorySlot, + /// Current painting state (mouse drag) + paint_state: Option<PaintState>, +} + +impl Window { + /// Creates a window from the backing window representation. + pub fn new(inner: BackingWindow) -> Self { + Self { + inner, + cursor_item: Empty, + paint_state: None, + } + } + + /// Left-click a slot in the window. + pub fn left_click(&mut self, slot: usize) -> SysResult { + let slot = &mut *self.inner.item(slot)?; + let cursor_slot = &mut self.cursor_item; + + // Cases: + // * Either the cursor slot or the clicked slot is empty; swap the two. + // * Both slots are present but are of different types; swap the two. + // * Both slots are present and have the same type; merge the two. + + if slot.is_filled() && cursor_slot.is_filled() && cursor_slot.is_mergable(slot) { + slot.merge(cursor_slot); + } else { + mem::swap(cursor_slot, slot); + } + + Ok(()) + } + + /// Right-clicks a slot in the window. + pub fn right_click(&mut self, slot_index: usize) -> SysResult { + let slot = &mut *self.inner.item(slot_index)?; + let cursor_slot = &mut self.cursor_item; + + // Cases: + // * Cursor slot is present and clicked slot has the same item type; drop one item in the clicked slot. + // * Clicked slot is present but cursor slot is not; move half the items into the cursor slot. + // * Both slots are present but differ in type; swap the two. + + match (slot.is_filled(), cursor_slot.is_filled()) { + (true, true) => { + if slot.is_mergable(cursor_slot) { + cursor_slot.transfer_to(1, slot); + } else { + mem::swap(slot, cursor_slot); + } + } + (true, false) => { + *cursor_slot = slot.take_half(); + } + (false, true) => { + *slot = cursor_slot.try_take(1); + } + (false, false) => {} + } + + Ok(()) + } + + /// Shift-clicks the given slot. (Either right or left click.) + pub fn shift_click(&mut self, slot: usize) -> SysResult { + // If we are shift clicking on a empty slot, then nothing happens. + { + let slot_inventory = &mut *self.inner.item(slot)?; + if slot_inventory.is_empty() { + // Shift clicking on a empty inventory slot does nothing. + return Ok(()); + } + } + + match &self.inner { + BackingWindow::Player { player: _ } => self.shift_click_in_player_window(slot), + + BackingWindow::Generic9x1 { + block: _, + player: _, + } + | BackingWindow::Generic9x2 { + block: _, + player: _, + } + | BackingWindow::Generic9x3 { + block: _, + player: _, + } + | BackingWindow::Generic9x4 { + block: _, + player: _, + } + | BackingWindow::Generic9x5 { + block: _, + player: _, + } + | BackingWindow::Generic3x3 { + block: _, + player: _, + } + | BackingWindow::Generic9x6 { + left_chest: _, + right_chest: _, + player: _, + } => self.shift_click_in_generic_window(slot), + + BackingWindow::Crafting { + crafting_table: _, + player: _, + } => self.shift_click_in_crafting_window(slot), + BackingWindow::Furnace { + furnace: _, + player: _, + } => self.shift_click_in_furnace(slot), + + BackingWindow::BlastFurnace { + blast_furnace: _, + player: _, + } => self.shift_click_in_blast_furnace(slot), + + BackingWindow::Smoker { + smoker: _, + player: _, + } => self.shift_click_in_smoker(slot), + + BackingWindow::Enchantment { + enchantment_table: _, + player: _, + } => self.shift_click_in_enchantment(slot), + + BackingWindow::BrewingStand { + brewing_stand: _, + player: _, + } => self.shift_click_in_brewing_window(slot), + + BackingWindow::Beacon { + beacon: _, + player: _, + } => self.shift_click_in_beacon(slot), + + BackingWindow::Anvil { + anvil: _, + player: _, + } => self.shift_click_in_anvil(slot), + BackingWindow::Hopper { + hopper: _, + player: _, + } => self.shift_click_in_hopper(slot), + BackingWindow::ShulkerBox { + shulker_box: _, + player: _, + } => self.shift_click_in_shulker_box(slot), + + BackingWindow::Cartography { + cartography_table: _, + player: _, + } => self.shift_click_in_cartography_window(slot), + BackingWindow::Grindstone { + grindstone: _, + player: _, + } => self.shift_click_in_grindstone(slot), + BackingWindow::Lectern { + lectern: _, + player: _, + } => self.shift_click_in_lectern(slot), + BackingWindow::Loom { loom: _, player: _ } => self.shift_click_in_loom(slot), + BackingWindow::Stonecutter { + stonecutter: _, + player: _, + } => self.shift_click_in_stonecutter(slot), + } + } + + fn shift_click_in_player_window(&mut self, slot: usize) -> SysResult { + let slot_item = &mut *self.inner.item(slot)?; + + let (inventory, slot_area, _) = self.inner.index_to_slot(slot).unwrap(); + let areas_to_try = [ + Area::Helmet, + Area::Chestplate, + Area::Leggings, + Area::Boots, + Area::CraftingInput, + Area::Hotbar, + Area::Storage, + ]; + + for &area in &areas_to_try { + if area == slot_area || !will_accept(area, slot_item) { + continue; + } + + // Find slot with same type first + let mut i = 0; + while let Some(mut stack) = inventory.item(area, i) { + if slot_item.is_mergable(&stack) && stack.is_filled() { + stack.merge(slot_item); + } + i += 1; + } + + if slot_item.is_empty() { + return Ok(()); + } + } + + if slot_item.is_filled() { + for &area in &areas_to_try { + if area == slot_area || !will_accept(area, slot_item) { + continue; + } + + // If we still haven't moved all the items, transfer to any empty space + let mut i = 0; + while let Some(mut stack) = inventory.item(area, i) { + if stack.is_empty() { + stack.merge(slot_item); + } + i += 1; + } + + if slot_item.is_empty() { + break; + } + } + } + + Ok(()) + } + + fn shift_click_in_generic_window(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_crafting_window(&mut self, _slot: usize) -> SysResult { + // TODO: If you shift click an item in the crafting table, then you craft + // as many as possible. So the items are crafted and put in Area::CraftingOutput + // We don't currently have a working crafting system, and once we have we probably + // need to change the function signature to get acsess to the crafting system. + todo!() + } + + fn shift_click_in_furnace(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_blast_furnace(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_smoker(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_enchantment(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_brewing_window(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_beacon(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_anvil(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_hopper(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_shulker_box(&mut self, _slot: usize) -> SysResult { + todo!() + } + + fn shift_click_in_cartography_window(&mut self, _slot: usize) -> SysResult { + todo!() + } + fn shift_click_in_grindstone(&mut self, _slot: usize) -> SysResult { + todo!() + } + fn shift_click_in_lectern(&mut self, _slot: usize) -> SysResult { + todo!() + } + fn shift_click_in_loom(&mut self, _slot: usize) -> SysResult { + todo!() + } + fn shift_click_in_stonecutter(&mut self, _slot: usize) -> SysResult { + todo!() + } + + /// Starts a left mouse paint operation. + pub fn begin_left_mouse_paint(&mut self) { + self.paint_state = Some(PaintState::new(Mouse::Left)); + } + + /// Starts a right mouse paint operation. + pub fn begin_right_mouse_paint(&mut self) { + self.paint_state = Some(PaintState::new(Mouse::Right)); + } + + /// Adds a slot to the current paint operation. + pub fn add_paint_slot(&mut self, slot: usize) -> SysResult { + if let Some(state) = &mut self.paint_state { + state.add_slot(slot) + } else { + Err(anyhow!("no paint operation was active")) + } + } + + /// Completes and executes the current paint operation. + pub fn end_paint(&mut self) -> SysResult { + if let Some(state) = self.paint_state.take() { + state.finish(self) + } else { + Err(anyhow!("no paint operation was active")) + } + } + + /// Gets the item currently held in the cursor. + pub fn cursor_item(&self) -> &InventorySlot { + &self.cursor_item + } + + pub fn item(&self, index: usize) -> Result<MutexGuard<InventorySlot>, WindowError> { + self.inner.item(index) + } + + /// Sets an [`InventorySlot`] at the index. + /// # Error + /// Returns an error if the index is [`WindowError::OutOfBounds`] + pub fn set_item(&self, index: usize, item: InventorySlot) -> Result<(), WindowError> { + self.inner.set_item(index, item) + } + + pub fn inner(&self) -> &BackingWindow { + &self.inner + } +} + +/// Determines whether the given area will accept the given item +/// for shift-click transfer. +fn will_accept(area: Area, stack: &InventorySlot) -> bool { + match area { + Area::Storage => true, + Area::CraftingOutput => false, + Area::CraftingInput => false, + Area::Helmet => matches!( + stack.item_kind(), + Some(Item::LeatherHelmet) + | Some(Item::ChainmailHelmet) + | Some(Item::GoldenHelmet) + | Some(Item::IronHelmet) + | Some(Item::DiamondHelmet) + | Some(Item::NetheriteHelmet) + ), + Area::Chestplate => matches!( + stack.item_kind(), + Some(Item::LeatherChestplate) + | Some(Item::ChainmailChestplate) + | Some(Item::GoldenChestplate) + | Some(Item::IronChestplate) + | Some(Item::DiamondChestplate) + | Some(Item::NetheriteChestplate) + ), + Area::Leggings => matches!( + stack.item_kind(), + Some(Item::LeatherHelmet) + | Some(Item::ChainmailLeggings) + | Some(Item::GoldenLeggings) + | Some(Item::IronLeggings) + | Some(Item::DiamondLeggings) + | Some(Item::NetheriteLeggings) + ), + Area::Boots => matches!( + stack.item_kind(), + Some(Item::LeatherBoots) + | Some(Item::ChainmailBoots) + | Some(Item::GoldenBoots) + | Some(Item::IronBoots) + | Some(Item::DiamondBoots) + | Some(Item::NetheriteBoots) + ), + Area::Hotbar => true, + Area::Offhand => true, + Area::FurnaceIngredient => true, + Area::FurnaceFuel => true, + Area::FurnaceOutput => false, + Area::EnchantmentItem => true, + Area::EnchantmentLapis => stack.item_kind() == Some(Item::LapisLazuli), + Area::BrewingBottle => matches!( + stack.item_kind(), + Some(Item::GlassBottle) + | Some(Item::Potion) + | Some(Item::SplashPotion) + | Some(Item::LingeringPotion) + ), + Area::BrewingIngredient => true, + Area::BrewingBlazePowder => stack.item_kind() == Some(Item::BlazePowder), + Area::VillagerInput => true, + Area::VillagerOutput => false, + Area::BeaconPayment => matches!( + stack.item_kind(), + Some(Item::IronIngot) + | Some(Item::GoldIngot) + | Some(Item::Diamond) + | Some(Item::NetheriteIngot) + | Some(Item::Emerald) + ), + Area::AnvilInput1 => true, + Area::AnvilInput2 => true, + Area::AnvilOutput => false, + Area::Saddle => stack.item_kind() == Some(Item::Saddle), + Area::HorseArmor => matches!( + stack.item_kind(), + Some(Item::LeatherHorseArmor) + | Some(Item::IronHorseArmor) + | Some(Item::GoldenHorseArmor) + | Some(Item::DiamondHorseArmor) + ), + Area::LlamaCarpet => true, + Area::CartographyMap => { + matches!(stack.item_kind(), Some(Item::Map) | Some(Item::FilledMap)) + } + Area::CartographyPaper => stack.item_kind() == Some(Item::Paper), + Area::CartographyOutput => false, + Area::GrindstoneInput1 => true, + Area::GrindstoneInput2 => true, + Area::GrindstoneOutput => false, + Area::LecternBook => true, + Area::LoomBanner => true, + Area::LoomDye => true, + Area::LoomPattern => true, + Area::LoomOutput => false, + Area::StonecutterInput => true, + Area::StonecutterOutput => false, + } +} + +/// State for a paint operation (left mouse or right mouse drag). +#[derive(Debug)] +struct PaintState { + mouse: Mouse, + slots: Vec<usize>, +} + +impl PaintState { + pub fn new(mouse: Mouse) -> Self { + Self { + mouse, + slots: Vec::new(), + } + } + + pub fn add_slot(&mut self, slot: usize) -> SysResult { + self.slots.push(slot); + if self.slots.len() > 1000 { + bail!("too many paint slots! malicious client?"); + } + Ok(()) + } + + pub fn finish(self, window: &mut Window) -> SysResult { + match self.mouse { + Mouse::Left => self.handle_left_drag(window), + Mouse::Right => self.handle_right_drag(window), + } + Ok(()) + } + + /** + Splits cursor items evenly into every selected slot. + Remainder of even split ends up in `window.cursor_item`. + */ + fn handle_left_drag(&self, window: &mut Window) { + // If the cursor has no item then there are no items to share. + if window.cursor_item().is_empty() { + return; + } + + // Number of slots that can contain cursors item kind. + let slots = self + .slots + .iter() + .filter(|s| { + // unwrap is safe because index is valid. + let slot = &*window.inner.item(**s).unwrap(); + slot.is_mergable(window.cursor_item()) + }) + .count() as u32; + + // If slots is 0 that means there are no slots to put items into. + // So the cursor keeps all the items. + if slots == 0 { + return; + }; + + let items_for_cursor = window.cursor_item().count(); + // This can't be zero because items_cursor is the count of an ItemStack and ItemStack is NonZeroU32. + let items_per_slot = (items_for_cursor / slots).max(1); + self.move_items_into_slots(window, items_per_slot); + } + + /// Tries to move items_per_slot items from cursor to the slots that can contain the item + fn move_items_into_slots(&self, window: &mut Window, items_per_slot: u32) { + for s in &self.slots { + let slot = &mut *window.inner.item(*s).unwrap(); + if !slot.is_mergable(window.cursor_item()) { + continue; + } + + window.cursor_item.transfer_to(items_per_slot, slot); + if window.cursor_item().is_empty() { + break; + }; + } + } + + fn handle_right_drag(&self, window: &mut Window) { + self.move_items_into_slots(window, 1) + } +} + +#[derive(Debug)] +enum Mouse { + Left, + Right, +} + +#[cfg(test)] +mod tests { + use base::{Inventory, Item, ItemStack}; + + use super::*; + + #[test] + fn window_left_click_swap() { + let mut window = window(); + + window.left_click(0).unwrap(); + assert_eq!(window.cursor_item, Empty); + + let stack = ItemStack::new(Item::Diamond, 32).unwrap(); + window + .set_item(0, InventorySlot::Filled(stack.clone())) + .unwrap(); + window.left_click(0).unwrap(); + + assert_eq!(window.cursor_item, InventorySlot::Filled(stack.clone())); + assert!(window.item(0).unwrap().is_empty()); + + window.left_click(1).unwrap(); + assert_eq!(window.cursor_item, Empty); + assert_eq!(*window.item(1).unwrap(), InventorySlot::Filled(stack)); + } + + #[test] + fn window_left_click_same_item() { + let mut window = window(); + + let item = ItemStack::new(Item::AcaciaSlab, 32).unwrap(); + window + .set_item(0, InventorySlot::Filled(item.clone())) + .unwrap(); + window.left_click(0).unwrap(); + + window.set_item(1, InventorySlot::Filled(item)).unwrap(); + window.left_click(1).unwrap(); + + assert_eq!(window.cursor_item, Empty); + assert_eq!( + *window.item(1).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::AcaciaSlab, 64).unwrap()) + ); + } + + /* + thread 'window::tests::window_left_click_same_item' panicked at 'assertion failed: `(left == right)` + left: `Filled(ItemStack { item: AcaciaSlab, count: 32, meta: Some(ItemStackMeta { title: "acacia_slab", lore: "", damage: None, repair_cost: None, enchantments: [] }) })`, + right: `Filled(ItemStack { item: AcaciaSlab, count: 64, meta: Some(ItemStackMeta { title: "acacia_slab", lore: "", damage: None, repair_cost: None, enchantments: [] }) })`', + feather/common/src/window.rs:452:9 + */ + + #[test] + fn window_right_click_pick_up_half() { + let mut window = window(); + let stack = ItemStack::new(Item::GlassPane, 17).unwrap(); + window.set_item(0, InventorySlot::Filled(stack)).unwrap(); + + window.right_click(0).unwrap(); + assert_eq!( + window.cursor_item, + InventorySlot::Filled(ItemStack::new(Item::GlassPane, 9).unwrap()) + ); + assert_eq!( + *window.item(0).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::GlassPane, 8).unwrap()) + ); + } + + #[test] + fn window_right_click_drop_one_item() { + let mut window = window(); + let stack = ItemStack::new(Item::GlassPane, 17).unwrap(); + window.cursor_item = InventorySlot::Filled(stack); + + window.right_click(1).unwrap(); + assert_eq!( + window.cursor_item, + InventorySlot::Filled(ItemStack::new(Item::GlassPane, 16).unwrap()) + ); + assert_eq!( + *window.item(1).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::GlassPane, 1).unwrap()) + ); + } + + #[test] + fn window_right_click_swap() { + let mut window = window(); + let stack1 = ItemStack::new(Item::GlassPane, 17).unwrap(); + let stack2 = ItemStack::new(Item::Diamond, 2).unwrap(); + window.cursor_item = InventorySlot::Filled(stack1.clone()); + window + .set_item(0, InventorySlot::Filled(stack2.clone())) + .unwrap(); + + window.right_click(0).unwrap(); + assert_eq!(window.cursor_item, InventorySlot::Filled(stack2)); + assert_eq!(*window.item(0).unwrap(), InventorySlot::Filled(stack1)); + } + + #[test] + fn window_shift_click_full_hotbar() { + let inventory = Inventory::player(); + for i in 0..9 { + *inventory.item(Area::Hotbar, i).unwrap() = + InventorySlot::Filled(ItemStack::new(Item::EnderPearl, 1).unwrap()); + } + *inventory.item(Area::Storage, 0).unwrap() = + InventorySlot::Filled(ItemStack::new(Item::AcaciaSign, 1).unwrap()); + let mut window = Window::new(BackingWindow::Player { + player: inventory.new_handle(), + }); + let index = window + .inner() + .slot_to_index(&inventory, Area::Storage, 0) + .unwrap(); + window.shift_click(index).unwrap(); + assert_eq!( + *window.item(index).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::AcaciaSign, 1).unwrap()) + ); + } + + #[test] + fn window_shift_click_available_item_in_hotbar() { + let inventory = Inventory::player(); + + *inventory.item(Area::Hotbar, 3).unwrap() = + InventorySlot::Filled(ItemStack::new(Item::Stone, 4).unwrap()); + *inventory.item(Area::Storage, 3).unwrap() = + InventorySlot::Filled(ItemStack::new(Item::Stone, 7).unwrap()); + + let mut window = Window::new(BackingWindow::Player { + player: inventory.new_handle(), + }); + + let index = window + .inner() + .slot_to_index(&inventory, Area::Storage, 3) + .unwrap(); + + window.shift_click(index).unwrap(); + + dbg!(&window); + + let hotbar_index = window + .inner() + .slot_to_index(&inventory, Area::Hotbar, 3) + .unwrap(); + + assert_eq!( + *window.item(hotbar_index).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::Stone, 11).unwrap()) + ); + assert!(window.item(index).unwrap().is_empty()); + } + + #[test] + fn window_shift_click_empty_hotbar() { + let inventory = Inventory::player(); + *inventory.item(Area::Storage, 3).unwrap() = + InventorySlot::Filled(ItemStack::new(Item::Stone, 7).unwrap()); + let mut window = Window::new(BackingWindow::Player { + player: inventory.new_handle(), + }); + + let storage_index = window + .inner() + .slot_to_index(&inventory, Area::Storage, 3) + .unwrap(); + window.shift_click(storage_index).unwrap(); + let hotbar_index = window + .inner() + .slot_to_index(&inventory, Area::Hotbar, 0) + .unwrap(); + assert_eq!( + *window.item(hotbar_index).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::Stone, 7).unwrap()) + ); + assert!(window.item(storage_index).unwrap().is_empty()); + } + + #[test] + fn left_mouse_paint() { + let mut window = window(); + window + .set_item( + 0, + InventorySlot::Filled(ItemStack::new(Item::Stone, 64).unwrap()), + ) + .unwrap(); + window.left_click(0).unwrap(); + + window.begin_left_mouse_paint(); + window.add_paint_slot(0).unwrap(); + window.add_paint_slot(1).unwrap(); + window.add_paint_slot(5).unwrap(); + window.end_paint().unwrap(); + + for &slot in &[0, 1, 5] { + assert_eq!( + *window.item(slot).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::Stone, 21).unwrap()) + ); + } + assert_eq!( + window.cursor_item, + InventorySlot::Filled(ItemStack::new(Item::Stone, 1).unwrap()) + ); + } + + #[test] + fn right_mouse_paint() { + let mut window = window(); + window + .set_item( + 0, + InventorySlot::Filled(ItemStack::new(Item::Stone, 2).unwrap()), + ) + .unwrap(); + window + .set_item( + 4, + InventorySlot::Filled(ItemStack::new(Item::Stone, 3).unwrap()), + ) + .unwrap(); + window.left_click(0).unwrap(); + + window.begin_right_mouse_paint(); + window.add_paint_slot(4).unwrap(); + window.add_paint_slot(5).unwrap(); + window.end_paint().unwrap(); + + assert_eq!( + *window.item(4).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::Stone, 4).unwrap()) + ); + assert_eq!( + *window.item(5).unwrap(), + InventorySlot::Filled(ItemStack::new(Item::Stone, 1).unwrap()) + ); + assert_eq!(window.cursor_item, InventorySlot::Empty); + } + + fn window() -> Window { + Window::new(BackingWindow::Player { + player: Inventory::player(), + }) + } + + #[test] + fn set_item_test() { + let window = window(); + + window + .set_item(45, InventorySlot::new(Item::Stone, 1)) + .unwrap(); + } +} diff --git a/feather/common/src/world.rs b/feather/common/src/world.rs new file mode 100644 index 000000000..f82ffc427 --- /dev/null +++ b/feather/common/src/world.rs @@ -0,0 +1,283 @@ +use std::{path::PathBuf, sync::Arc}; + +use ahash::{AHashMap, AHashSet}; +use parking_lot::{RwLockReadGuard, RwLockWriteGuard}; +use uuid::Uuid; + +use base::anvil::player::PlayerData; +use base::{ + BlockPosition, Chunk, ChunkHandle, ChunkLock, ChunkPosition, ValidBlockPosition, CHUNK_HEIGHT, +}; +use blocks::BlockId; +use ecs::{Ecs, SysResult}; +use worldgen::{ComposableGenerator, WorldGenerator}; + +use crate::{ + chunk::cache::ChunkCache, + chunk::worker::{ChunkWorker, LoadRequest, SaveRequest}, + events::ChunkLoadEvent, +}; + +/// Stores all blocks and chunks in a world, +/// along with global world data like weather, time, +/// and the [`WorldSource`](crate::world_source::WorldSource). +/// +/// NB: _not_ what most Rust ECSs call "world." +/// This does not store entities; it only contains blocks. +pub struct World { + chunk_map: ChunkMap, + pub cache: ChunkCache, + chunk_worker: ChunkWorker, + loading_chunks: AHashSet<ChunkPosition>, + canceled_chunk_loads: AHashSet<ChunkPosition>, + world_dir: PathBuf, +} + +impl Default for World { + fn default() -> Self { + Self { + chunk_map: ChunkMap::new(), + chunk_worker: ChunkWorker::new( + "world", + Arc::new(ComposableGenerator::default_with_seed(0)), + ), + cache: ChunkCache::new(), + loading_chunks: AHashSet::new(), + canceled_chunk_loads: AHashSet::new(), + world_dir: "world".into(), + } + } +} + +impl World { + pub fn new() -> Self { + Self::default() + } + + pub fn with_gen_and_path( + generator: Arc<dyn WorldGenerator>, + world_dir: impl Into<PathBuf> + Clone, + ) -> Self { + Self { + world_dir: world_dir.clone().into(), + chunk_worker: ChunkWorker::new(world_dir, generator), + ..Default::default() + } + } + + /// Queues the given chunk to be loaded. If the chunk was cached, it is loaded immediately. + pub fn queue_chunk_load(&mut self, req: LoadRequest) { + let pos = req.pos; + if self.cache.contains(&pos) { + // Move the chunk from the cache to the map + self.chunk_map + .0 + .insert(pos, self.cache.remove(pos).unwrap()); + self.chunk_map.chunk_handle_at(pos).unwrap().set_loaded(); + } else { + self.loading_chunks.insert(req.pos); + self.chunk_worker.queue_load(req); + } + } + + /// Loads any chunks that have been loaded asynchronously + /// after a call to [`World::queue_chunk_load`]. + pub fn load_chunks(&mut self, ecs: &mut Ecs) -> SysResult { + while let Some(loaded) = self.chunk_worker.poll_loaded_chunk()? { + self.loading_chunks.remove(&loaded.pos); + if self.canceled_chunk_loads.remove(&loaded.pos) { + continue; + } + let chunk = loaded.chunk; + + self.chunk_map.insert_chunk(chunk); + ecs.insert_event(ChunkLoadEvent { + chunk: Arc::clone(&self.chunk_map.0[&loaded.pos]), + position: loaded.pos, + }); + log::trace!("Loaded chunk {:?}", loaded.pos); + } + Ok(()) + } + + /// Unloads the given chunk. + pub fn unload_chunk(&mut self, pos: ChunkPosition) -> anyhow::Result<()> { + if let Some((pos, handle)) = self.chunk_map.0.remove_entry(&pos) { + handle.set_unloaded()?; + self.chunk_worker.queue_chunk_save(SaveRequest { + pos, + chunk: handle.clone(), + entities: vec![], + block_entities: vec![], + }); + self.cache.insert(pos, handle); + } + self.chunk_map.remove_chunk(pos); + if self.is_chunk_loading(pos) { + self.canceled_chunk_loads.insert(pos); + } + + log::trace!("Unloaded chunk {:?}", pos); + Ok(()) + } + + /// Returns whether the given chunk is loaded. + pub fn is_chunk_loaded(&self, pos: ChunkPosition) -> bool { + self.chunk_map.0.contains_key(&pos) + } + + /// Returns whether the given chunk is queued to be loaded. + pub fn is_chunk_loading(&self, pos: ChunkPosition) -> bool { + self.loading_chunks.contains(&pos) + } + + /// Sets the block at the given position. + /// + /// Returns `true` if the block was set, or `false` + /// if its chunk was not loaded or the coordinates + /// are out of bounds and thus no operation + /// was performed. + pub fn set_block_at(&self, pos: ValidBlockPosition, block: BlockId) -> bool { + self.chunk_map.set_block_at(pos, block) + } + + /// Retrieves the block at the specified + /// location. If the chunk in which the block + /// exists is not loaded or the coordinates + /// are out of bounds, `None` is returned. + pub fn block_at(&self, pos: ValidBlockPosition) -> Option<BlockId> { + self.chunk_map.block_at(pos) + } + + /// Returns the chunk map. + pub fn chunk_map(&self) -> &ChunkMap { + &self.chunk_map + } + + /// Mutably gets the chunk map. + pub fn chunk_map_mut(&mut self) -> &mut ChunkMap { + &mut self.chunk_map + } + + pub fn load_player_data(&self, uuid: Uuid) -> anyhow::Result<PlayerData> { + Ok(base::anvil::player::load_player_data( + &self.world_dir, + uuid, + )?) + } + + pub fn save_player_data(&self, uuid: Uuid, data: &PlayerData) -> anyhow::Result<()> { + base::anvil::player::save_player_data(&self.world_dir, uuid, data) + } +} + +pub type ChunkMapInner = AHashMap<ChunkPosition, ChunkHandle>; + +/// This struct stores all the chunks on the server, +/// so it allows access to blocks and lighting data. +/// +/// Chunks are internally wrapped in `Arc<RwLock>`, +/// allowing multiple systems to access different parts +/// of the world in parallel. Mutable access to this +/// type is only required for inserting and removing +/// chunks. +#[derive(Default)] +pub struct ChunkMap(ChunkMapInner); + +impl ChunkMap { + /// Creates a new, empty world. + pub fn new() -> Self { + Self::default() + } + + /// Retrieves a handle to the chunk at the given + /// position, or `None` if it is not loaded. + pub fn chunk_at(&self, pos: ChunkPosition) -> Option<RwLockReadGuard<Chunk>> { + self.0.get(&pos).map(|lock| lock.read()) + } + + /// Retrieves a handle to the chunk at the given + /// position, or `None` if it is not loaded. + pub fn chunk_at_mut(&self, pos: ChunkPosition) -> Option<RwLockWriteGuard<Chunk>> { + self.0.get(&pos).and_then(|lock| lock.write()) + } + + /// Returns an `Arc<RwLock<Chunk>>` at the given position. + pub fn chunk_handle_at(&self, pos: ChunkPosition) -> Option<ChunkHandle> { + self.0.get(&pos).map(Arc::clone) + } + + pub fn block_at(&self, pos: ValidBlockPosition) -> Option<BlockId> { + check_coords(pos)?; + + let (x, y, z) = chunk_relative_pos(pos.into()); + self.chunk_at(pos.chunk()) + .and_then(|chunk| chunk.block_at(x, y, z)) + } + + pub fn set_block_at(&self, pos: ValidBlockPosition, block: BlockId) -> bool { + if check_coords(pos).is_none() { + return false; + } + + let (x, y, z) = chunk_relative_pos(pos.into()); + + self.chunk_at_mut(pos.chunk()) + .map(|mut chunk| chunk.set_block_at(x, y, z, block)) + .is_some() + } + + /// Returns an iterator over chunks. + pub fn iter_chunks(&self) -> impl IntoIterator<Item = &ChunkHandle> { + self.0.values() + } + + /// Inserts a new chunk into the chunk map. + pub fn insert_chunk(&mut self, chunk: Chunk) { + self.0 + .insert(chunk.position(), Arc::new(ChunkLock::new(chunk, true))); + } + + /// Removes the chunk at the given position, returning `true` if it existed. + pub fn remove_chunk(&mut self, pos: ChunkPosition) -> bool { + self.0.remove(&pos).is_some() + } +} + +fn check_coords(pos: ValidBlockPosition) -> Option<()> { + if pos.y() >= 0 && pos.y() < CHUNK_HEIGHT as i32 { + Some(()) + } else { + None + } +} + +fn chunk_relative_pos(block_pos: BlockPosition) -> (usize, usize, usize) { + ( + block_pos.x as usize & 0xf, + block_pos.y as usize, + block_pos.z as usize & 0xf, + ) +} + +#[cfg(test)] +mod tests { + use std::convert::TryInto; + + use super::*; + + #[test] + fn world_out_of_bounds() { + let mut world = World::new(); + world + .chunk_map_mut() + .insert_chunk(Chunk::new(ChunkPosition::new(0, 0))); + + assert!(world + .block_at(BlockPosition::new(0, -1, 0).try_into().unwrap()) + .is_none()); + assert!(world + .block_at(BlockPosition::new(0, 0, 0).try_into().unwrap()) + .is_some()); + } +} diff --git a/feather/datapacks/Cargo.toml b/feather/datapacks/Cargo.toml new file mode 100644 index 000000000..d7bfd149c --- /dev/null +++ b/feather/datapacks/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "feather-datapacks" +version = "0.1.0" +authors = [ "caelunshun <caelunshun@gmail.com>" ] +edition = "2018" + +[dependencies] +ahash = "0.4" +anyhow = "1" +log = "0.4" +serde = { version = "1", features = [ "derive" ] } +serde_json = "1" +smartstring = { version = "0.2", features = [ "serde" ] } +thiserror = "1" +ureq = { version = "2", default-features = false, features = [ "tls" ] } +zip = { version = "0.5", default-features = false, features = [ "deflate", "bzip2" ] } diff --git a/feather/datapacks/src/id.rs b/feather/datapacks/src/id.rs new file mode 100644 index 000000000..e0e9beebb --- /dev/null +++ b/feather/datapacks/src/id.rs @@ -0,0 +1,213 @@ +use crate::DEFAULT_NAMESPACE; +use serde::{de, Deserialize, Serialize}; +use smartstring::{LazyCompact, SmartString}; +use std::{ + fmt::{self, Display}, + str::FromStr, +}; + +/// A namespaced identifier, also known as a "resource location" +/// in Forge. See <https://minecraft.gamepedia.com/Namespaced_ID>. +/// +/// Namespaced IDs can be parsed using the `FromStr` implementation, +/// and they can be formatted using the `Display` impl or by calling `to_string()`. +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct NamespacedId { + // Smart (inlineable) strings are used to reduce heap + // fragmentation and memory usage. + namespace: SmartString<LazyCompact>, + name: SmartString<LazyCompact>, +} + +impl NamespacedId { + /// Returns the namespace for this ID. + pub fn namespace(&self) -> &str { + &self.namespace + } + + /// Returns the name for this ID. + pub fn name(&self) -> &str { + &self.name + } +} + +/// Error returned when a namespaced ID was formatted incorrectly. +#[derive(Debug, thiserror::Error, PartialEq)] +pub enum ParseError { + #[error("'{0}' is not a valid character for namespaces")] + InvalidNamespaceChar(char), + #[error("'{0}' is not a valid character for namespaced ID names")] + InvalidNameChar(char), +} + +impl FromStr for NamespacedId { + type Err = ParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + // Determine the namespace and name components. + let mut parts = s.split(':'); + let part1 = parts.next().unwrap_or(""); + let part2 = parts.next(); + + let (namespace, name) = if let Some(part2) = part2 { + (part1, part2) + } else { + (DEFAULT_NAMESPACE, part1) + }; + + // Ensure that the namespace and name are legal. + validate_namespace(namespace)?; + validate_name(name)?; + + Ok(NamespacedId { + namespace: SmartString::from(namespace), + name: SmartString::from(name), + }) + } +} + +fn validate_namespace(namespace: &str) -> Result<(), ParseError> { + for c in namespace.chars() { + if !is_valid_namespace_char(c) { + return Err(ParseError::InvalidNamespaceChar(c)); + } + } + Ok(()) +} + +fn validate_name(name: &str) -> Result<(), ParseError> { + for c in name.chars() { + if !is_valid_name_char(c) { + return Err(ParseError::InvalidNameChar(c)); + } + } + Ok(()) +} + +fn is_valid_namespace_char(c: char) -> bool { + c.is_ascii_alphanumeric() || c == '_' || c == '-' +} + +fn is_valid_name_char(c: char) -> bool { + // Names can have some extra characters in addition + // to those allowed for namespaces. + is_valid_namespace_char(c) || c == '/' || c == '.' +} + +impl<'de> Deserialize<'de> for NamespacedId { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + let string = SmartString::<LazyCompact>::deserialize(deserializer)?; + + NamespacedId::from_str(&string).map_err(|e| de::Error::custom(e.to_string())) + } +} + +impl Display for NamespacedId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}:{}", self.namespace, self.name) + } +} + +impl Serialize for NamespacedId { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + self.to_string().serialize(serializer) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn legal_namespace_chars() { + for c in ('a'..='z').chain('A'..='Z').chain('0'..='9') { + assert!(is_valid_name_char(c)); + assert!(is_valid_namespace_char(c)); + } + } + + #[test] + fn legal_name_chars() { + for &c in &['/', '.'] { + assert!(is_valid_name_char(c)); + assert!(!is_valid_namespace_char(c)); + } + } + + #[test] + fn illegal_namespace_chars() { + for &c in &['/', '.', '\\', '\n', '@', '%', '?'] { + assert!(!is_valid_namespace_char(c)); + } + } + + #[test] + fn illegal_name_chars() { + for &c in &['\\', '\n', '@', '%', '?'] { + assert!(!is_valid_namespace_char(c)); + } + } + + #[test] + fn parse_id_with_namespace() { + let id = NamespacedId::from_str("namespace-caelunshun_66:folder/file.ext").unwrap(); + assert_eq!(&id.name, "folder/file.ext"); + assert_eq!(&id.namespace, "namespace-caelunshun_66"); + } + + #[test] + fn parse_id_with_default_namespace() { + let id = NamespacedId::from_str("acacia_leaves-2").unwrap(); + assert_eq!(&id.name, "acacia_leaves-2"); + assert_eq!(&id.namespace, DEFAULT_NAMESPACE); + } + + #[test] + fn parse_empty_id() { + let id = NamespacedId::from_str("").unwrap(); + assert_eq!(id.name(), ""); + assert_eq!(id.namespace(), DEFAULT_NAMESPACE); + } + + #[test] + fn parse_id_with_invalid_namespace() { + assert_eq!( + NamespacedId::from_str("ewhi@iho:name"), + Err(ParseError::InvalidNamespaceChar('@')) + ); + assert_eq!( + NamespacedId::from_str("dir1/dir2:file"), + Err(ParseError::InvalidNamespaceChar('/')) + ); + } + + #[test] + fn parse_id_with_invalid_name() { + assert_eq!( + NamespacedId::from_str("name^"), + Err(ParseError::InvalidNameChar('^')) + ); + assert_eq!( + NamespacedId::from_str("spaces galore"), + Err(ParseError::InvalidNameChar(' ')) + ); + } + + #[test] + fn formatting() { + let id = NamespacedId::from_str("namespace:name").unwrap(); + assert_eq!(id.to_string(), "namespace:name"); + } + + #[test] + fn formatting_default_namespace() { + let id = NamespacedId::from_str("name").unwrap(); + assert_eq!(id.to_string(), "minecraft:name"); + } +} diff --git a/feather/datapacks/src/lib.rs b/feather/datapacks/src/lib.rs new file mode 100644 index 000000000..a0c705819 --- /dev/null +++ b/feather/datapacks/src/lib.rs @@ -0,0 +1,35 @@ +//! Data pack implementation for Feather. +//! +//! Data packs can register loot tables, recipes, advancements, functions, +//! etc. This implementation aims to be compatible with vanilla data packs. +//! +//! This crate also downloads vanilla JARs and assets +//! at startup; see `download_vanilla_assets`. + +use ahash::AHashMap; +use serde::Deserialize; +use smartstring::{LazyCompact, SmartString}; + +mod vanilla; +pub use vanilla::download_vanilla_assets; + +mod id; +pub use id::NamespacedId; + +/// The default namespace for resource locations (NamespacedIds). +pub const DEFAULT_NAMESPACE: &str = "minecraft"; + +/// The pack.mcmeta file at the root of a datapack. +/// +/// Formatted with JSON. +#[derive(Debug, Deserialize)] +pub struct PackMeta { + pub pack_format: i32, + pub description: String, +} + +/// Stores all loaded data packs and their assets. +pub struct Datapacks { + /// The metadata of loaded packs. Keyed by the datapack name. + _meta: AHashMap<SmartString<LazyCompact>, PackMeta>, +} diff --git a/feather/datapacks/src/vanilla.rs b/feather/datapacks/src/vanilla.rs new file mode 100644 index 000000000..05e36053e --- /dev/null +++ b/feather/datapacks/src/vanilla.rs @@ -0,0 +1,120 @@ +use anyhow::Context; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::SystemTime; +use std::{ + fs::{self, File}, + io, + path::Path, + time::Duration, +}; +use zip::ZipArchive; + +// Taken from https://www.minecraft.net/en-us/download/server +const JAR_URL: &str = + "https://launcher.mojang.com/v1/objects/c5f6fb23c3876461d46ec380421e42b289789530/server.jar"; +const JAR_NAME: &str = "server-1.16.2.jar"; +const DOWNLOAD_WARNING_MINUTES: f64 = 2.0; +const DOWNLOAD_TIMEOUT_MINUTES: u64 = 30; + +/// Downloads vanilla server/client JARs and assets, used +/// for loot tables, recipes, etc. +/// +/// The server JAR will be placed in `$base/downloaded`. +/// The vanilla datapack will be extracted to `$base/datapacks`. +pub fn download_vanilla_assets(base: &Path) -> anyhow::Result<()> { + let jar = download_jar(base) + .context(format!( + "failed to download vanilla server JAR in {} minutes", + DOWNLOAD_TIMEOUT_MINUTES + )) + .context("please make sure you have an Internet connection.")?; + + // NB: JAR files are just glorified ZIP files, so we can use the zip crate + // to process the data. + let mut zip = ZipArchive::new(jar)?; + + create_minecraft_datapack(base, &mut zip)?; + + Ok(()) +} + +fn download_jar(base: &Path) -> anyhow::Result<File> { + log::info!("Downloading vanilla server JAR from {}", JAR_URL); + + let downloaded = Arc::new(AtomicBool::new(false)); + let download_start_time = SystemTime::now(); + let mut download_time = 1.0; + let mut warning = 1; + let downloaded1 = downloaded.clone(); + std::thread::spawn(move || { + while !downloaded1.load(Ordering::Relaxed) { + let elapsed = download_start_time.elapsed().unwrap().as_secs_f64(); + if elapsed / 60.0 >= warning as f64 * DOWNLOAD_WARNING_MINUTES + && download_time / 60.0 < warning as f64 * DOWNLOAD_WARNING_MINUTES + { + log::warn!("Looks like you have a slow internet connection! Downloading vanilla server JAR for {} minutes", warning as f64 * DOWNLOAD_WARNING_MINUTES); + warning += 1; + } + download_time = elapsed; + std::thread::sleep(Duration::from_secs(1)); + } + }); + + let mut data = ureq::get(JAR_URL) + .timeout(Duration::from_secs(60 * DOWNLOAD_TIMEOUT_MINUTES)) + .call() + .map_err(|err| { + // stop download time counter + downloaded.store(true, Ordering::Relaxed); + err + })? + .into_reader(); + downloaded.store(true, Ordering::Relaxed); + log::info!("Downloaded vanilla server JAR successfully"); + + let downloaded_dir = base.join("downloaded"); + fs::create_dir_all(&downloaded_dir)?; + let mut file = File::create(downloaded_dir.join(JAR_NAME))?; + + io::copy(&mut data, &mut file)?; + Ok(file) +} + +fn create_minecraft_datapack(base: &Path, zip: &mut ZipArchive<File>) -> anyhow::Result<()> { + log::info!("Extracting vanilla JAR"); + // We'll create a datapack by copying `pack.mcmeta` and the `data` + // directory to a new datapack called `minecraft`. + let target = base.join("datapacks/minecraft"); + fs::create_dir_all(&target)?; + + // copy pack.mcmeta + { + let mut pack_mcmeta = zip.by_name("pack.mcmeta")?; + let mut pack_mcmeta_target = File::create(target.join("pack.mcmeta"))?; + io::copy(&mut pack_mcmeta, &mut pack_mcmeta_target)?; + } + + // copy data directory + let mut files = Vec::new(); + for file_name in zip.file_names() { + let path = Path::new(file_name); + let path_in_target = fs::canonicalize(target.join(path))?; + if path.starts_with("data") && path_in_target.starts_with(&target) { + files.push((file_name.to_owned(), path_in_target)); + } + } + for (file_name, path_in_target) in files { + let mut reader = zip.by_name(&file_name)?; + + if let Some(parent) = path_in_target.parent() { + fs::create_dir_all(parent)?; + } + let mut writer = File::create(&path_in_target)?; + + io::copy(&mut reader, &mut writer)?; + log::debug!("Extracted {}", file_name); + } + + Ok(()) +} diff --git a/feather/ecs/Cargo.toml b/feather/ecs/Cargo.toml new file mode 100644 index 000000000..976652287 --- /dev/null +++ b/feather/ecs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "feather-ecs" +version = "0.1.0" +authors = [ "caelunshun <caelunshun@gmail.com>" ] +edition = "2018" + +[dependencies] +ahash = "0.7" +anyhow = "1" +hecs = { git = "https://github.com/feather-rs/feather-hecs" } +log = "0.4" +thiserror = "1" +utils = { path = "../utils", package = "feather-utils" } + diff --git a/feather/ecs/src/change.rs b/feather/ecs/src/change.rs new file mode 100644 index 000000000..cf3d71161 --- /dev/null +++ b/feather/ecs/src/change.rs @@ -0,0 +1,54 @@ +use std::{any::TypeId, collections::VecDeque}; + +use ahash::AHashMap; +use hecs::{Component, DynamicBundle, Entity}; + +/// Tracks changes made to certain components. +#[derive(Default)] +pub struct ChangeTracker { + registries: AHashMap<TypeId, ChangeRegistry>, +} + +impl ChangeTracker { + pub fn track_component<T: Component>(&mut self) { + self.registries + .insert(TypeId::of::<T>(), ChangeRegistry::default()); + } + + pub fn on_insert(&mut self, entity: Entity, components: &impl DynamicBundle) { + components.with_ids(|typs| { + for ty in typs { + let registry = self.registries.get_mut(ty); + if let Some(registry) = registry { + registry.mark_changed(entity); + } + } + }); + } + + pub fn iter_changed<T: Component>(&self) -> impl Iterator<Item = Entity> + '_ { + self.registries.get(&TypeId::of::<T>()) + .unwrap_or_else(|| panic!("Components of type {} are not tracked for changes. Call `Ecs::track_component` to enable change tracking.", std::any::type_name::<T>())) + .changed_entities + .iter() + .copied() + } +} + +#[derive(Default)] +struct ChangeRegistry { + changed_entities: VecDeque<Entity>, +} + +impl ChangeRegistry { + pub fn mark_changed(&mut self, entity: Entity) { + if !self.changed_entities.contains(&entity) { + self.changed_entities.push_back(entity); + } + } + + #[allow(unused)] + pub fn pop(&mut self) { + self.changed_entities.pop_front(); + } +} diff --git a/feather/ecs/src/event.rs b/feather/ecs/src/event.rs new file mode 100644 index 000000000..3ed66c3d3 --- /dev/null +++ b/feather/ecs/src/event.rs @@ -0,0 +1,77 @@ +use hecs::{Component, Entity, World}; + +/// Function to remove an event from the ECS. +type EventRemoveFn = fn(&mut World, Entity); + +fn entity_event_remove_fn<T: Component>() -> EventRemoveFn { + |ecs, entity| { + let _ = ecs.remove_one::<T>(entity); + } +} + +fn event_remove_fn(world: &mut World, event_entity: Entity) { + let _ = world.despawn(event_entity); +} + +/// Maintains a set of events that need to be removed +/// from entities. +/// +/// An event's lifecycle is as follows: +/// 1. The event is added as a component to its entity +/// by calling `Ecs::insert_event`. The system that +/// inserts the event is called the "triggering system." +/// 2. Each system runs and has exactly one chance to observe +/// the event through a query. +/// 3. Immediately before the triggering system runs again, +/// the event is removed from the entity. +#[derive(Default)] +pub struct EventTracker { + /// Events to remove from entities. + /// + /// Indexed by the index of the triggering system. + events: Vec<Vec<(Entity, EventRemoveFn)>>, + + current_system_index: usize, +} + +impl EventTracker { + /// Adds an entity event to be tracked. + pub fn insert_entity_event<T: Component>(&mut self, entity: Entity) { + let events_vec = self.current_events_vec(); + events_vec.push((entity, entity_event_remove_fn::<T>())) + } + + /// Adds an event to be tracked. + pub fn insert_event(&mut self, event_entity: Entity) { + let events_vec = self.current_events_vec(); + events_vec.push((event_entity, event_remove_fn)); + } + + /// Adds a custom function to run + /// before the current systems executes again. + #[allow(unused)] + pub fn insert_custom(&mut self, entity: Entity, callback: fn(&mut World, Entity)) { + let events_vec = self.current_events_vec(); + events_vec.push((entity, callback)); + } + + pub fn set_current_system_index(&mut self, index: usize) { + self.current_system_index = index; + } + + /// Deletes events that were triggered on the previous tick + /// by the current system. + pub fn remove_old_events(&mut self, world: &mut World) { + let events_vec = self.current_events_vec(); + for (entity, remove_fn) in events_vec.drain(..) { + remove_fn(world, entity); + } + } + + fn current_events_vec(&mut self) -> &mut Vec<(Entity, EventRemoveFn)> { + while self.events.len() <= self.current_system_index { + self.events.push(Vec::new()); + } + &mut self.events[self.current_system_index] + } +} diff --git a/feather/ecs/src/lib.rs b/feather/ecs/src/lib.rs new file mode 100644 index 000000000..77fd48c2d --- /dev/null +++ b/feather/ecs/src/lib.rs @@ -0,0 +1,218 @@ +//! A lightweight ECS wrapper tailored to Feather's needs. +//! +//! This is implemented as a wrapper around the Bevy Engine's fork of the +//! `hecs` crate, but we've made some interface changes: +//! * A system framework has been implemented, with systems written as plain functions and +//! executed sequentially. +//! * `World` is renamed to `Ecs` so as to avoid conflict with Minecraft's concept of worlds. +//! * We add support for events based on components. +//! +//! This wrapper library exists in case we need additional features in the ECS. If necessary, +//! we can change the backend crate or fork it as needed, without refactoring the rest of the codebase. + +use change::ChangeTracker; +use event::EventTracker; +use hecs::{Component, DynamicBundle, Fetch, Query, World}; + +#[doc(inline)] +pub use hecs::{ + BuiltEntity, ComponentError, DynamicQuery, DynamicQueryTypes, Entity, EntityBuilder, + MissingComponent, NoSuchEntity, QueryBorrow, Ref, RefMut, +}; + +mod system; +pub use system::{GroupBuilder, HasEcs, HasResources, SysResult, SystemExecutor}; + +mod resources; +pub use resources::{ResourceError, Resources}; + +mod change; +mod event; + +/// Stores entities and their components. This is a wrapper +/// around `hecs::World` with a slightly changed interface +/// and support for events. +/// +/// # Events +/// This struct supports _events_ by adding components to entities. +/// For example, the `EntityDamageEvent` is triggered whenever an +/// entity takes damage. What happens next: +/// 1. The system that damaged the entity adds `EntityDamageEvent` as a component +/// to the entity. +/// 2. All systems get a chance to observe that event by calling [`Ecs::query`] +/// using the `EntityDamageEvent` type. +/// 3. When the system that triggered the event runs again, the component +/// is automatically removed. +/// +/// This ensures that each event is observed exactly once by each system. +/// +/// Events can either be associated with an entity—in which case they +/// are added as a component to the entity—or they can be standalone. +/// For example, `BlockChangeEvent` is not related to any specific +/// entity. These standalone events are entities with only one component—the event. +#[derive(Default)] +pub struct Ecs { + world: World, + event_tracker: EventTracker, + change_tracker: ChangeTracker, +} + +impl Ecs { + pub fn new() -> Self { + Self::default() + } + + /// Returns the inner `hecs::World`. Should be used with caution. + pub fn inner(&self) -> &World { + &self.world + } + + pub fn inner_mut(&mut self) -> &mut World { + &mut self.world + } + + /// Spawns an entity with the provided components. + pub fn spawn(&mut self, components: impl DynamicBundle) -> Entity { + let entity = self.world.reserve_entity(); + self.change_tracker.on_insert(entity, &components); + self.world.insert(entity, components).unwrap(); + entity + } + + /// Returns an `EntityRef` for an entity. + pub fn entity(&self, entity: Entity) -> Result<EntityRef, NoSuchEntity> { + self.world.entity(entity).map(EntityRef) + } + + /// Gets a component of an entity. + pub fn get<T: Component>(&self, entity: Entity) -> Result<Ref<T>, ComponentError> { + self.world.get(entity) + } + + /// Mutably gets a component of an entity. + pub fn get_mut<T: Component>(&self, entity: Entity) -> Result<RefMut<T>, ComponentError> { + self.world.get_mut(entity) + } + + /// Adds a component to an entity. + /// + /// Do not use this function to add events. Use [`Ecs::insert_event`] + /// instead. + pub fn insert( + &mut self, + entity: Entity, + component: impl Component, + ) -> Result<(), NoSuchEntity> { + self.world.insert_one(entity, component) + } + + /// Creates an event not related to any entity. Use + /// `insert_entity_event` for events regarding specific + /// entities (`PlayerJoinEvent`, `EntityDamageEvent`, etc...) + pub fn insert_event<T: Component>(&mut self, event: T) { + let entity = self.world.spawn((event,)); + self.event_tracker.insert_event(entity); + } + + /// Adds an event component to an entity and schedules + /// it to be removed immeditately before the current system + /// runs again. Thus, all systems have exactly one chance + /// to observe the event before it is dropped. + pub fn insert_entity_event<T: Component>( + &mut self, + entity: Entity, + event: T, + ) -> Result<(), NoSuchEntity> { + self.insert(entity, event)?; + self.event_tracker.insert_entity_event::<T>(entity); + Ok(()) + } + + /// Removes a component from an entit and returns it. + pub fn remove<T: Component>(&mut self, entity: Entity) -> Result<T, ComponentError> { + self.world.remove_one(entity) + } + + /// Removes an entity from the ECS. + pub fn despawn(&mut self, entity: Entity) -> Result<(), NoSuchEntity> { + self.world.despawn(entity) + } + + /// Defers removing an entity until before the next time this system + /// runs, allowing it to be observed by systems one last time. + pub fn defer_despawn(&mut self, entity: Entity) { + // a bit of a hack - but this will change once + // hecs allows taking out components of a despawned entity + self.event_tracker.insert_event(entity); + } + + /// Returns an iterator over all entities that match a query parameter. + pub fn query<Q: Query>(&self) -> QueryBorrow<Q> { + self.world.query() + } + + /// Performs a dynamic query. Used for plugins. + pub fn query_dynamic<'q>(&'q self, types: DynamicQueryTypes<'q>) -> DynamicQuery<'q> { + self.world.query_dynamic(types) + } + + /// Sets the index of the currently executing system, + /// used for event tracking. + pub fn set_current_system_index(&mut self, index: usize) { + self.event_tracker.set_current_system_index(index); + } + + /// Should be called before each system runs. + pub fn remove_old_events(&mut self) { + self.event_tracker.remove_old_events(&mut self.world); + } + + /// Enables change tracking for `T` components. + /// + /// Calling this allows using `query_changed` + /// to iterate over entities whose `T` has changed. + pub fn track_component<T: Component>(&mut self) { + self.change_tracker.track_component::<T>() + } + + /// Iterates over entities whose `T` component + /// changed since the previous time the current + /// system was executed. + /// + /// # Panics + /// Panics if `track_component` was not called for `T`. + pub fn for_each_changed<T: Component, Q: Query>( + &self, + mut function: impl FnMut(&T, <<Q as Query>::Fetch as Fetch>::Item), + ) { + for entity in self.change_tracker.iter_changed::<T>() { + let mut query = match self.world.query_one::<(&T, Q)>(entity) { + Ok(q) => q, + Err(_) => continue, + }; + let components = query.get(); + if let Some((tracked, components)) = components { + function(tracked, components); + } + } + } +} + +/// Allows access to all components of a single entity. +pub struct EntityRef<'a>(hecs::EntityRef<'a>); + +impl<'a> EntityRef<'a> { + /// Borrows the component of type `T` from this entity. + pub fn get<T: Component>(&self) -> Result<Ref<'a, T>, ComponentError> { + self.0 + .get() + .ok_or_else(|| ComponentError::MissingComponent(MissingComponent::new::<T>())) + } + + /// Uniquely borrows the component of type `T` from this entity. + pub fn get_mut<T: Component>(&self) -> Result<RefMut<'a, T>, ComponentError> { + self.0 + .get_mut() + .ok_or_else(|| ComponentError::MissingComponent(MissingComponent::new::<T>())) + } +} diff --git a/feather/ecs/src/resources.rs b/feather/ecs/src/resources.rs new file mode 100644 index 000000000..ba9dd1278 --- /dev/null +++ b/feather/ecs/src/resources.rs @@ -0,0 +1,74 @@ +use std::{ + any::{type_name, Any, TypeId}, + cell::{Ref, RefCell, RefMut}, +}; + +use ahash::AHashMap; + +#[derive(Debug, thiserror::Error)] +pub enum ResourceError { + #[error("resource of type '{0}' does not exist")] + Missing(&'static str), + #[error( + "resource of type '{0}' borrowed invalidly (mutably and immutable borrow at the same time)" + )] + Borrow(&'static str), +} + +/// Structure storing _resources_, where each +/// resource is identified by its Rust type. At most +/// one resource of each type can exist. +/// +/// Resources are borrow-checked at runtime using `RefCell`. +#[derive(Default)] +pub struct Resources { + resources: AHashMap<TypeId, RefCell<Box<dyn Any>>>, +} + +impl Resources { + pub fn new() -> Self { + Self::default() + } + + /// Inserts a new resource into this container. + /// + /// Returns the old resource of the same type, if it existed. + pub fn insert<T: 'static>(&mut self, resource: T) -> Option<T> { + self.resources + .insert(TypeId::of::<T>(), RefCell::new(Box::new(resource))) + .map(|resource| *resource.into_inner().downcast::<T>().unwrap()) + } + + /// Removes a resource from the container, returning it. + pub fn remove<T: 'static>(&mut self) -> Option<T> { + self.resources + .remove(&TypeId::of::<T>()) + .map(|resource| *resource.into_inner().downcast::<T>().unwrap()) + } + + /// Gets the resource of type `T`. + pub fn get<T: 'static>(&self) -> Result<Ref<T>, ResourceError> { + let resource = self + .resources + .get(&TypeId::of::<T>()) + .ok_or_else(|| ResourceError::Missing(type_name::<T>()))?; + + resource + .try_borrow() + .map_err(|_| ResourceError::Borrow(type_name::<T>())) + .map(|b| Ref::map(b, |b| b.downcast_ref::<T>().unwrap())) + } + + /// Mutably gets the resource of type `T`. + pub fn get_mut<T: 'static>(&self) -> Result<RefMut<T>, ResourceError> { + let resource = self + .resources + .get(&TypeId::of::<T>()) + .ok_or_else(|| ResourceError::Missing(type_name::<T>()))?; + + resource + .try_borrow_mut() + .map_err(|_| ResourceError::Borrow(type_name::<T>())) + .map(|b| RefMut::map(b, |b| b.downcast_mut::<T>().unwrap())) + } +} diff --git a/feather/ecs/src/system.rs b/feather/ecs/src/system.rs new file mode 100644 index 000000000..3fd8aa840 --- /dev/null +++ b/feather/ecs/src/system.rs @@ -0,0 +1,196 @@ +//! System execution, using a simple "systems as functions" model. + +use std::{any::type_name, marker::PhantomData, sync::Arc}; + +use crate::{Ecs, Resources}; + +/// The result type returned by a system function. +/// +/// When a system encounters an internal error, it should return +/// an error instead of panicking. The system executor will then +/// log an error message to the console and attempt to gracefully +/// recover. +/// +/// Examples of internal errors include: +/// * An entity was missing a component which it was expected to have. +/// (For example, all entities have a `Position` component; if an entity +/// is missing it, then that is valid grounds for a system to return an error.) +/// * IO errors +/// +/// That said, these errors should never happen in production. +pub type SysResult<T = ()> = anyhow::Result<T>; + +type SystemFn<Input> = Box<dyn FnMut(&mut Input) -> SysResult>; + +struct System<Input> { + function: SystemFn<Input>, + name: String, +} + +impl<Input> System<Input> { + fn from_fn<F: FnMut(&mut Input) -> SysResult + 'static>(f: F) -> Self { + Self { + function: Box::new(f), + name: type_name::<F>().to_owned(), + } + } +} + +/// A type containing a `Resources`. +pub trait HasResources { + fn resources(&self) -> Arc<Resources>; +} + +/// A type containing an `Ecs`. +pub trait HasEcs { + fn ecs(&self) -> &Ecs; + + fn ecs_mut(&mut self) -> &mut Ecs; +} + +impl HasEcs for Ecs { + fn ecs(&self) -> &Ecs { + self + } + + fn ecs_mut(&mut self) -> &mut Ecs { + self + } +} + +/// An executor for systems. +/// +/// This executor contains a sequence of systems, each +/// of which is simply a function taking an `&mut Input`. +/// +/// Systems may belong to _groups_, where each system +/// gets an additional parameter representing the group state. +/// For example, the `Server` group has state contained in the `Server` +/// struct, so all its systems get `Server` as an extra parameter. +/// +/// Systems run sequentially in the order they are added to the executor. +pub struct SystemExecutor<Input> { + systems: Vec<System<Input>>, + + is_first_run: bool, +} + +impl<Input> Default for SystemExecutor<Input> { + fn default() -> Self { + Self { + systems: Vec::new(), + is_first_run: true, + } + } +} + +impl<Input> SystemExecutor<Input> { + pub fn new() -> Self { + Self::default() + } + + /// Adds a system to the executor. + pub fn add_system( + &mut self, + system: impl FnMut(&mut Input) -> SysResult + 'static, + ) -> &mut Self { + let system = System::from_fn(system); + self.systems.push(system); + self + } + + pub fn add_system_with_name( + &mut self, + system: impl FnMut(&mut Input) -> SysResult + 'static, + name: &str, + ) { + let mut system = System::from_fn(system); + system.name = name.to_owned(); + self.systems.push(system); + } + + /// Begins a group with the provided group state type. + /// + /// The group state must be added to the `resources`. + pub fn group<State>(&mut self) -> GroupBuilder<Input, State> + where + Input: HasResources, + { + GroupBuilder { + systems: self, + _marker: PhantomData, + } + } + + /// Runs all systems in order. + /// + /// Errors are logged using the `log` crate. + pub fn run(&mut self, input: &mut Input) + where + Input: HasEcs, + { + for (i, system) in self.systems.iter_mut().enumerate() { + input.ecs_mut().set_current_system_index(i); + + // For the first cycle, we don't want to clear + // events because some code may have triggered + // events _before_ the first system run. Without + // this check, these events would be cleared before + // any system could observe them. + if !self.is_first_run { + input.ecs_mut().remove_old_events(); + } + + let result = (system.function)(input); + if let Err(e) = result { + log::error!( + "System {} returned an error; this is a bug: {:?}", + system.name, + e + ); + } + } + + self.is_first_run = false; + } + + /// Gets an iterator over system names. + pub fn system_names(&self) -> impl Iterator<Item = &'_ str> + '_ { + self.systems.iter().map(|system| system.name.as_str()) + } +} + +/// Builder for a group. Created with [`SystemExecutor::group`]. +pub struct GroupBuilder<'a, Input, State> { + systems: &'a mut SystemExecutor<Input>, + _marker: PhantomData<State>, +} + +impl<'a, Input, State> GroupBuilder<'a, Input, State> +where + Input: HasResources + 'static, + State: 'static, +{ + /// Adds a system to the group. + pub fn add_system<F: FnMut(&mut Input, &mut State) -> SysResult + 'static>( + &mut self, + system: F, + ) -> &mut Self { + let function = Self::make_function(system); + self.systems + .add_system_with_name(function, type_name::<F>()); + self + } + + fn make_function( + mut system: impl FnMut(&mut Input, &mut State) -> SysResult + 'static, + ) -> impl FnMut(&mut Input) -> SysResult + 'static { + move |input: &mut Input| { + let resources = input.resources(); + let mut state = resources + .get_mut::<State>() + .expect("missing state resource for group"); + system(input, &mut *state) + } + } +} diff --git a/feather/ecs/tests/events.rs b/feather/ecs/tests/events.rs new file mode 100644 index 000000000..a9d6895ae --- /dev/null +++ b/feather/ecs/tests/events.rs @@ -0,0 +1,74 @@ +#![allow(clippy::unnecessary_wraps)] + +use feather_ecs::{Ecs, HasEcs, SysResult, SystemExecutor}; + +#[derive(Debug, PartialEq, Eq)] +struct Event { + x: i32, +} + +struct Input { + ecs: Ecs, + is_first_run: bool, +} + +impl HasEcs for Input { + fn ecs(&self) -> &Ecs { + &self.ecs + } + + fn ecs_mut(&mut self) -> &mut Ecs { + &mut self.ecs + } +} + +fn pre_system(input: &mut Input) -> SysResult { + if !input.is_first_run { + let mut query = input.ecs.query::<&Event>(); + assert_eq!(query.iter().next().unwrap().1, &Event { x: 10 }); + } + Ok(()) +} + +fn trigger_system(input: &mut Input) -> SysResult { + if input.is_first_run { + let entity = input.ecs.spawn(()); + let event = Event { x: 10 }; + input.ecs.insert_entity_event(entity, event)?; + } else { + let mut query = input.ecs.query::<&Event>(); + assert_eq!(query.iter().next(), None); + } + + Ok(()) +} + +fn post_system(input: &mut Input) -> SysResult { + let mut query = input.ecs.query::<&Event>(); + let next = query.iter().next(); + if input.is_first_run { + assert_eq!(next.unwrap().1, &Event { x: 10 }); + } else { + assert_eq!(next, None); + } + Ok(()) +} + +#[test] +fn events_observed_once() { + let mut systems = SystemExecutor::<Input>::new(); + systems + .add_system(pre_system) + .add_system(trigger_system) + .add_system(post_system); + + let mut input = Input { + ecs: Ecs::new(), + is_first_run: true, + }; + systems.run(&mut input); + input.is_first_run = false; + systems.run(&mut input); + + assert_eq!(input.ecs.inner().len(), 1); +} diff --git a/feather/ecs/tests/random_access.rs b/feather/ecs/tests/random_access.rs new file mode 100644 index 000000000..d36f16308 --- /dev/null +++ b/feather/ecs/tests/random_access.rs @@ -0,0 +1,63 @@ +use feather_ecs::{ComponentError, Ecs, EntityBuilder}; + +#[test] +fn add_simple_entity() { + let mut ecs = Ecs::new(); + let entity = ecs.inner_mut().spawn( + EntityBuilder::new() + .add(10i32) + .add(15u32) + .add(usize::MAX) + .build(), + ); + + assert_eq!(*ecs.get::<i32>(entity).unwrap(), 10); + assert_eq!(*ecs.get::<u32>(entity).unwrap(), 15); + assert_eq!(*ecs.get::<usize>(entity).unwrap(), usize::MAX); + + *ecs.get_mut::<i32>(entity).unwrap() = 324; + assert_eq!(*ecs.get::<i32>(entity).unwrap(), 324); +} + +#[test] +fn add_remove_entities() { + let mut ecs = Ecs::new(); + let entity = ecs + .inner_mut() + .spawn(EntityBuilder::new().add("test").build()); + + assert_eq!(*ecs.get::<&'static str>(entity).unwrap(), "test"); + + ecs.inner_mut().despawn(entity).unwrap(); + + assert!(matches!( + ecs.get::<&'static str>(entity).err(), + Some(ComponentError::NoSuchEntity) + )); + assert!(ecs.inner_mut().despawn(entity).is_err()); +} + +#[test] +fn fine_grained_borrow_checking() { + let mut ecs = Ecs::new(); + let entity1 = ecs + .inner_mut() + .spawn(EntityBuilder::new().add(()).add(16i32).build()); + let entity2 = ecs + .inner_mut() + .spawn(EntityBuilder::new().add(14i32).build()); + + let mut e1 = ecs.get_mut::<i32>(entity1).unwrap(); + let e2 = ecs.get_mut::<i32>(entity2).unwrap(); + + assert_eq!(*e1, 16); + assert_eq!(*e2, 14); + + *e1 = 12; + assert_eq!(*e1, 12); + + drop(e1); + assert_eq!(*ecs.get_mut::<i32>(entity1).unwrap(), 12); + + assert!(ecs.get_mut::<()>(entity1).is_ok()); +} diff --git a/feather/ecs/tests/systems.rs b/feather/ecs/tests/systems.rs new file mode 100644 index 000000000..40e0a449a --- /dev/null +++ b/feather/ecs/tests/systems.rs @@ -0,0 +1,42 @@ +#![allow(clippy::unnecessary_wraps)] + +use feather_ecs::{Ecs, HasEcs, SysResult, SystemExecutor}; + +struct Input { + x: i32, + ecs: Ecs, +} + +impl HasEcs for Input { + fn ecs(&self) -> &Ecs { + &self.ecs + } + + fn ecs_mut(&mut self) -> &mut Ecs { + &mut self.ecs + } +} + +fn system1(input: &mut Input) -> SysResult { + input.x += 10; + Ok(()) +} + +fn system2(input: &mut Input) -> SysResult { + input.x *= 10; + Ok(()) +} + +#[test] +fn systems_are_executed_in_order() { + let mut executor = SystemExecutor::new(); + executor.add_system(system1); + executor.add_system(system2); + + let mut input = Input { + x: 1, + ecs: Ecs::new(), + }; + executor.run(&mut input); + assert_eq!(input.x, 110); +} diff --git a/feather/old/README.md b/feather/old/README.md new file mode 100644 index 000000000..1c2ade967 --- /dev/null +++ b/feather/old/README.md @@ -0,0 +1,5 @@ +### Code archive + +This directory contains code from before the [1.16 refactor/rewrite](https://github.com/feather-rs/feather/pull/307). + +It may be useful to salvage some of this code to reimplement features that were lost in the rewrite. diff --git a/feather/old/core/Cargo.toml b/feather/old/core/Cargo.toml new file mode 100644 index 000000000..bcae39ae5 --- /dev/null +++ b/feather/old/core/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "feather-core" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-anvil = { path = "./anvil" } +feather-biomes = { path = "./biomes" } +feather-blocks = { path = "./blocks" } +feather-chunk = { path = "./chunk" } +feather-chunk-map = { path = "./chunk_map" } +feather-entity-metadata = { path = "./entity_metadata" } +feather-game-rules = { path = "./game_rules" } +feather-inventory = { path = "./inventory" } +feather-item-block = { path = "./item_block" } +feather-items = { path = "./items" } +feather-loot = { path = "./loot" } +feather-misc = { path = "./misc" } +feather-protocol = { path = "./protocol" } +feather-text = { path = "./text" } +feather-util = { path = "./util" } diff --git a/feather/old/core/biomes/Cargo.toml b/feather/old/core/biomes/Cargo.toml new file mode 100644 index 000000000..2339b0102 --- /dev/null +++ b/feather/old/core/biomes/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "feather-biomes" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +strum = "0.18" +strum_macros = "0.18" +num-traits = "0.2" +num-derive = "0.3" diff --git a/core/src/biomes.rs b/feather/old/core/biomes/src/lib.rs similarity index 98% rename from core/src/biomes.rs rename to feather/old/core/biomes/src/lib.rs index dc0677d3a..3b2d15b60 100644 --- a/core/src/biomes.rs +++ b/feather/old/core/biomes/src/lib.rs @@ -1,4 +1,22 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumCount, FromPrimitive, ToPrimitive)] +use num_derive::{FromPrimitive, ToPrimitive}; +use strum_macros::*; + +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + EnumString, + Display, + EnumIter, + EnumCount, + FromPrimitive, + ToPrimitive, +)] pub enum Biome { Badlands, BadlandsPlateau, diff --git a/feather/old/core/game_rules/Cargo.toml b/feather/old/core/game_rules/Cargo.toml new file mode 100644 index 000000000..27be23aba --- /dev/null +++ b/feather/old/core/game_rules/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "feather-game-rules" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] \ No newline at end of file diff --git a/feather/old/core/game_rules/src/lib.rs b/feather/old/core/game_rules/src/lib.rs new file mode 100644 index 000000000..1ae8bca6a --- /dev/null +++ b/feather/old/core/game_rules/src/lib.rs @@ -0,0 +1,54 @@ +macro_rules! gamerules { + {$($name:ident: $value:ty = $default:literal),*$(,)*} => { + #[derive(Debug)] + pub struct GameRules { + $( + pub $name: $value + ),* + } + + impl Default for GameRules { + fn default() -> Self { + Self { + $( + $name: $default + ),* + } + } + } + }; +} + +gamerules! { + announce_advancements: bool = true, + command_block_output: bool = true, + disable_elytra_movement_check: bool = false, + disable_raids: bool = false, + do_daylight_cycle: bool = true, + do_entity_drops: bool = true, + do_fire_tick: bool = true, + do_insomnia: bool = true, + do_immediate_respawn: bool = false, + do_limited_crafting: bool = false, + do_mob_loot: bool = true, + do_mob_spawning: bool = true, + do_patrol_spawning: bool = true, + do_tile_drops: bool = true, + do_trader_spawning: bool = true, + do_weather_cycle: bool = true, + drowning_damage: bool = true, + fall_damage: bool = true, + fire_damage: bool = true, + keep_inventory: bool = false, + log_admin_commands: bool = true, + max_command_chain_length: u32 = 65536, + max_entity_cramming: u32 = 24, + mob_griefing: bool = true, + natural_regeneration: bool = true, + random_tick_speed: u32 = 3, + reduced_debug_info: bool = false, + send_command_feedback: bool = true, + show_death_messages: bool = true, + spawn_radius: u32 = 10, + spectators_generate_chunks: bool = true, +} diff --git a/feather/old/core/inventory/Cargo.toml b/feather/old/core/inventory/Cargo.toml new file mode 100644 index 000000000..f862ed870 --- /dev/null +++ b/feather/old/core/inventory/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "feather-inventory" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-items = { path = "../items" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +legion = { git = "https://github.com/TomGillen/legion", rev = "bd441f4811e7a9e877a0f479a674bbdbf4e4cda3" } +thiserror = "1.0" +parking_lot = "0.10" +maplit = "1.0" +smallvec = "1.4" +once_cell = "1.3" diff --git a/feather/old/core/inventory/src/lib.rs b/feather/old/core/inventory/src/lib.rs new file mode 100644 index 000000000..2ae03de55 --- /dev/null +++ b/feather/old/core/inventory/src/lib.rs @@ -0,0 +1,338 @@ +//! An implementation of inventory handling. +//! +//! # Key types +//! * `Area`: an area in an inventory, e.g. hotbar, storage, crafting +//! * `Inventory`: stores the items inside an inventory, associated +//! with their respective areas +//! * `Window`: handles mapping from protocol inventory indices +//! to internal indices used for `Inventory`. + +use feather_items::ItemStack; +use maplit::btreemap; +use parking_lot::{RwLock, RwLockWriteGuard}; +use std::collections::BTreeMap; +use std::iter::repeat_with; +use thiserror::Error; + +mod window; + +use once_cell::sync::Lazy; +use smallvec::{Array, SmallVec}; +use std::cmp::min; +pub use window::{constants as player_constants, Error as WindowError, Window, WindowAccessor}; + +static COLLECT_SEARCH_ORDER: Lazy<Vec<(Area, usize)>> = Lazy::new(|| { + let mut result = vec![]; + // TODO: move to constants + for x in 0..9 { + result.push((Area::Hotbar, x)); + } + + for x in 0..27 { + result.push((Area::Main, x)); + } + + result +}); + +/// An area inside an inventory, used to differentiate between +/// different parts. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Area { + /// The crafting output slot inside either a player's + /// inventory or a crafting table. (1 slot total) + CraftingOutput, + /// Crafting input slots. (Total depends on window: + /// 4 slots for `Player` and 9 slots for `Crafting`) + CraftingInput, + + // armor + Head, + /// A player's chestplate + Torso, + Legs, + Feet, + Offhand, + + /// Main part of a player's inventory (27 slots total) + Main, + + /// A player's hotbar (9 slots total) + Hotbar, + + /// Chest storage (27 or 54 slots total, depending on whether + /// chest is single or large) + /// + /// Note that this is not the chestplate slot; use `Torso` instead. + Chest, +} + +/// Index into a slot. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct SlotIndex { + pub area: Area, + pub slot: usize, +} + +/// Creates a `SlotIndex`. +pub fn slot(area: Area, slot: usize) -> SlotIndex { + SlotIndex { area, slot } +} + +/// A slot in an inventory. This is an `Option<ItemStack>`; +/// if set to `None`, then there is no item in this slot. +pub type Slot = Option<ItemStack>; + +/// An error emitted when accessing an item +/// fails. +#[derive(Debug, Error)] +pub enum Error { + #[error("index {0} for area {1:?} out of bounds")] + OutOfBounds(usize, Area), + #[error("area {0:?} does not exist in this inventory")] + NoSuchArea(Area), + #[error("invalid protocol index {0}")] + InvalidProtocolIndex(usize), +} + +/// Stores items in some inventory. +/// +/// Internally, items are each wrapped in a `RwLock`. +/// This allows for convenient access and shared +/// references to an `Inventory` without using +/// `RefCell`. The overhead from the use of locks +/// should be minimal. +/// +/// # Structure +/// `Inventory` uses a composition-based design. It +/// stores a vector of items for each `Area` which it contains. +/// +/// # Initialization +/// `Inventory` provides assorted functions to initialize inventories +/// of some kind. For example, `Inventory::large_chest()` creates an +/// empty inventory for a large chest. +/// +/// # Indexing conventions +/// When an area consists of a rectangle +/// of slots on the client GUI, then indexing +/// starts at 0 with the top-left corner and proceeds +/// horizontally, then vertically. +#[derive(Default, Debug)] +pub struct Inventory { + /// Associative array from `Area` => items + /// contained within the `Area`. + /// + /// Might switch to another, more efficient map + /// type at some point, but we have no profile + /// results which indicate inventory handling + /// is a bottleneck. + slots: BTreeMap<Area, Vec<RwLock<Slot>>>, +} + +impl Inventory { + /// Creates an inventory for a player, i.e. + /// one with hotbar, main storage, armor, offhand, survival + /// crafting slots. + pub fn player() -> Self { + let slots = btreemap! { + Area::Hotbar => empty(9), + Area::Main => empty(27), + + Area::Head => empty(1), + Area::Torso => empty(1), + Area::Legs => empty(1), + Area::Feet => empty(1), + Area::Offhand => empty(1), + + Area::CraftingInput => empty(4), + Area::CraftingOutput => empty(1), + }; + + Self { slots } + } + + /// Creates an inventory for a crafting table. + /// Contains `CraftingInput` and `CraftingOutput` + /// areas. + pub fn crafting_table() -> Self { + let slots = btreemap! { + Area::CraftingInput => empty(9), + Area::CraftingOutput => empty(9), + }; + + Self { slots } + } + + /// Creates an inventory for a chest. + /// Contains a single `Chest` area with 27 slots. + pub fn chest() -> Self { + let slots = btreemap! { + Area::Chest => empty(27), + }; + + Self { slots } + } + + /// Returns the item at the given + /// index inside some area. + pub fn item_at(&self, area: Area, index: usize) -> Result<Slot, Error> { + self.slot(area, index).map(RwLock::read).map(|guard| *guard) + } + + /// Returns a mutable guard for an item + /// at the given slot. + pub fn item_at_mut(&self, area: Area, index: usize) -> Result<RwLockWriteGuard<Slot>, Error> { + self.slot(area, index).map(RwLock::write) + } + + /// Sets the item at the given index inside some area. + /// + /// Returns the old item in the slot. + pub fn set_item_at(&self, area: Area, index: usize, stack: ItemStack) -> Result<Slot, Error> { + let mut slot = self.item_at_mut(area, index)?; + let old = *slot; + *slot = if stack.amount == 0 { + Slot::None + } else { + Slot::Some(stack) + }; + Ok(old) + } + + /// Removes the item at the given position. Returns + /// the removed item. + pub fn remove_item_at(&self, area: Area, index: usize) -> Result<Slot, Error> { + let mut item = self.item_at_mut(area, index)?; + + Ok(item.take()) + } + + /// Returns an iterator over mutable references to all + /// items in this inventory. + pub fn iter_mut(&self) -> impl Iterator<Item = RwLockWriteGuard<Slot>> { + self.slots + .values() + .flat_map(Vec::as_slice) + .map(RwLock::write) + } + + /// Returns an iterator over items + indices. + pub fn enumerate<'a>(&'a self) -> impl Iterator<Item = (SlotIndex, Slot)> + 'a { + self.slots + .iter() + .flat_map(|(area, slots)| std::iter::repeat(*area).zip(slots.iter().enumerate())) + .map(|(area, (index, slot))| (SlotIndex { area, slot: index }, *slot.read())) + } + + /// Returns an iterator over the areas in this inventory. + pub fn areas<'a>(&'a self) -> impl Iterator<Item = Area> + 'a { + self.slots.keys().copied() + } + + /// Attempts to insert the given item into a player + /// inventory. + /// + /// Returns the affected slots and the number of remaining + /// items which were not added to the inventory. + /// + /// TODO: replace with inventory query API + pub fn collect_item(&self, mut item: ItemStack) -> (SmallVec<[SlotIndex; 2]>, u8) { + let mut affected_slots = SmallVec::new(); + + // First, look for slots already having the type. + for (area, slot) in COLLECT_SEARCH_ORDER.iter() { + if let Some(slot_item) = self.item_at(*area, *slot).expect("index out of bounds") { + if slot_item.eq_ignore_amount(item) { + self.add_to_stack( + &mut item, + slot_item, + SlotIndex { + area: *area, + slot: *slot, + }, + &mut affected_slots, + ); + + if item.amount == 0 { + return (affected_slots, 0); + } + } + } + } + + for (area, slot) in COLLECT_SEARCH_ORDER.iter() { + let slot_item = self.item_at(*area, *slot).unwrap(); + if slot_item.is_none() { + let fake = item.of_amount(0); + self.add_to_stack( + &mut item, + fake, + SlotIndex { + area: *area, + slot: *slot, + }, + &mut affected_slots, + ); + if item.amount == 0 { + return (affected_slots, 0); + } + } + + if let Some(slot_item) = slot_item { + if slot_item.eq_ignore_amount(item) { + self.add_to_stack( + &mut item, + slot_item, + SlotIndex { + area: *area, + slot: *slot, + }, + &mut affected_slots, + ); + + if item.amount == 0 { + return (affected_slots, 0); + } + } + } + } + + (affected_slots, item.amount) + } + + /// Adds an item to a stack. + fn add_to_stack<A: Array<Item = SlotIndex>>( + &self, + item: &mut ItemStack, + slot_item: ItemStack, + slot: SlotIndex, + affected_slots: &mut SmallVec<A>, + ) { + let added = min(item.amount, item.ty.stack_size() as u8 - slot_item.amount); + item.amount -= added; + + self.set_item_at( + slot.area, + slot.slot, + slot_item.of_amount(slot_item.amount + added), + ) + .unwrap(); + affected_slots.push(slot); + } + + fn slot(&self, area: Area, index: usize) -> Result<&RwLock<Slot>, Error> { + let slots = self.slots(area)?; + slots.get(index).ok_or(Error::OutOfBounds(index, area)) + } + + fn slots(&self, area: Area) -> Result<&[RwLock<Slot>], Error> { + self.slots + .get(&area) + .ok_or(Error::NoSuchArea(area)) + .map(Vec::as_slice) + } +} + +fn empty(n: usize) -> Vec<RwLock<Slot>> { + repeat_with(|| RwLock::new(None)).take(n).collect() +} diff --git a/feather/old/core/inventory/src/window.rs b/feather/old/core/inventory/src/window.rs new file mode 100644 index 000000000..beda44d5c --- /dev/null +++ b/feather/old/core/inventory/src/window.rs @@ -0,0 +1,319 @@ +//! Window management. Used to map inventory slot indices +//! in the protocol to `(Area, usize)` indices into an `Inventory`. +//! +//! See https://wiki.vg/Inventory for more information. + +use crate::{Area, Inventory, Slot, SlotIndex}; +use feather_items::ItemStack; +use fecs::{Entity, World}; +use legion::borrow::Ref; +use smallvec::{smallvec, SmallVec}; +use thiserror::Error; + +pub mod constants { + +} + +/// Converted from of a protocol index, used +/// to access inventories directly. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Index { + /// The index into `Window.inventories`, used + /// when the window consists of multiple inventories. + pub inventory: usize, + /// The area inside the inventory. + pub area: Area, + /// The index inside the area. + pub slot: usize, +} + +impl From<Index> for SlotIndex { + fn from(idx: Index) -> Self { + SlotIndex { + area: idx.area, + slot: idx.slot, + } + } +} + +/// Error returned when a `Window` fails to create +/// a `WindowAccessor` +#[derive(Debug, Error)] +pub enum Error { + #[error("no inventory component for entity")] + MissingComponent, +} + +/// A window represents the current context of a player's GUI. +/// It defines the functions to convert slot indices in the protocol +/// to those used for `Inventory`. +/// +/// Critically, a window may wrap over multiple inventories. For example, +/// if a player is inside a chest, then their context is `Window::chest(player, chest)`. +/// The `Window` then delegates raw `usize`s from the protocol to either +/// `player` or `chest` depending on the value of said `usize`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Window { + /// Mapping from `usize` in the protocol + /// to indices into the inventory. + protocol_to_slot: fn(usize) -> Option<Index>, + /// Inverse of `protocol_to_slot`. + slot_to_protocol: fn(Index) -> usize, + /// Inventories wrapped over by this `Window`. + /// + /// Internally, we store the `Entity` handles. + /// When accessing inventories, we retrieve the `Inventory` + /// component. + inventories: SmallVec<[Entity; 2]>, +} + +impl Window { + /// Creates a new `Window` for a normal player, + /// i.e. a player's own inventory without any + /// crafting tables, chests, furnaces, etc. open. + /// + /// https://wiki.vg/Inventory#Player_Inventory + pub fn player(player: Entity) -> Self { + Self { + protocol_to_slot: player_to_slot, + slot_to_protocol: player_from_slot, + inventories: smallvec![player], + } + } + + /// Creates a new `Window` for an opened chest. + pub fn chest(player: Entity, chest: Entity) -> Self { + Self { + protocol_to_slot: chest_to_slot, + slot_to_protocol: chest_from_slot, + inventories: smallvec![player, chest], + } + } + + /// Creates a new `Window` for a large opened chest. + /// + /// `left_chest` is the northern or western chest, while + //// `right_chest` is the southern or eastern one. + pub fn large_chest(player: Entity, left_chest: Entity, right_chest: Entity) -> Self { + Self { + protocol_to_slot: large_chest_to_slot, + slot_to_protocol: large_chest_from_slot, + inventories: smallvec![player, left_chest, right_chest], + } + } + + /// Returns the entities other than the player + /// which this window wraps over. For example, + /// for `Window::chest(),` this will return the chest. + /// For `Window::player()`, this is the empty slice. + pub fn wrapped_entities(&self) -> &[Entity] { + // convention: index 0 is the player + &self.inventories[1..] + } + + /// Retrieves a `WindowAccessor` which may be used + /// to access the underlying inventories. + /// + /// Returns an error if the `Entity`s stored in the `Window` + /// do not exist in the `World` or have no inventory components. + pub fn accessor<'a>(&'a self, world: &'a World) -> Result<WindowAccessor<'a>, Error> { + let inventories = self + .inventories + .iter() + .map(|entity| world.try_get::<Inventory>(*entity)) + .collect::<Option<_>>() + .ok_or(Error::MissingComponent)?; + + Ok(WindowAccessor { + window: self, + inventories, + }) + } + + /// Converts a network index to a `SlotIndex`. + pub fn convert_network(&self, network: usize) -> Option<Index> { + let protocol_to_slot = self.protocol_to_slot; + protocol_to_slot(network) + } + + /// Converts a `SlotIndex` and the entity whose + /// inventory the `SlotIndex` belongs to to a network index. + pub fn convert_slot(&self, slot: SlotIndex, entity: Entity) -> Option<usize> { + let slot_to_protocol = self.slot_to_protocol; + let inventory = self.inventories.iter().position(|e| *e == entity)?; + let index = Index { + area: slot.area, + inventory, + slot: slot.slot, + }; + Some(slot_to_protocol(index)) + } + + /// Returns which entity has the inventory corresponding to the given + /// protocol index. + pub fn corresponding_entity(&self, network: usize) -> Option<Entity> { + self.convert_network(network) + .map(|index| self.inventories[index.inventory]) + } + + // TODO: more mappings as the need arises +} + +/// Accessor to a set of inventories returned by `Window::accessor`. +/// +/// This stores references to the wrapped `Inventory`s +/// and allows for direct inventory access through protocol +/// indices. +pub struct WindowAccessor<'a> { + window: &'a Window, + inventories: SmallVec<[Ref<'a, Inventory>; 2]>, +} + +impl<'a> WindowAccessor<'a> { + /// Retrieves the item at the given protocol index. + pub fn item_at(&self, index: usize) -> Result<Slot, crate::Error> { + self.with_inv(index, |inv, idx| inv.item_at(idx.area, idx.slot)) + } + + /// Sets the slot (`Option<ItemStack>`) at the given protocol + /// index. + /// + /// Returns the old slot. + pub fn set_slot_at(&self, index: usize, slot: Slot) -> Result<Slot, crate::Error> { + self.with_inv(index, |inv, idx| { + inv.item_at_mut(idx.area, idx.slot).map(|mut guard| { + let old = *guard; + *guard = slot; + old + }) + }) + } + + /// Sets the item at the given protocol index. + /// + /// Returns the old item. + pub fn set_item_at(&self, index: usize, stack: ItemStack) -> Result<Slot, crate::Error> { + self.with_inv(index, |inv, idx| inv.set_item_at(idx.area, idx.slot, stack)) + } + + /// Removes the item at the given index. + /// + /// Returns the removed item. + pub fn remove_item_at(&self, index: usize) -> Result<Slot, crate::Error> { + self.with_inv(index, |inv, idx| inv.remove_item_at(idx.area, idx.slot)) + } + + fn with_inv<T>( + &self, + index: usize, + f: impl FnOnce(&Inventory, Index) -> Result<T, crate::Error>, + ) -> Result<T, crate::Error> { + let protocol_to_slot = self.window.protocol_to_slot; + let index = protocol_to_slot(index).ok_or(crate::Error::InvalidProtocolIndex(index))?; + let inventory = &self.inventories[index.inventory]; + + f(inventory, index) + } +} + +/// https://wiki.vg/Inventory#Player_Inventory +fn player_to_slot(x: usize) -> Option<Index> { + Some(match x { + 0 => index(0, Area::CraftingOutput, 0), + 1..=4 => index(0, Area::CraftingInput, x - 1), + 5 => index(0, Area::Head, 0), + 6 => index(0, Area::Torso, 0), + 7 => index(0, Area::Legs, 0), + 8 => index(0, Area::Feet, 0), + 9..=35 => index(0, Area::Main, x - 9), + 36..=44 => index(0, Area::Hotbar, x - 36), + 45 => index(0, Area::Offhand, 0), + _ => return None, + }) +} + +fn player_from_slot(slot: Index) -> usize { + use Area::*; + match slot.area { + CraftingOutput => 0, + CraftingInput => slot.slot + 1, + Head => 5, + Torso => 6, + Legs => 7, + Feet => 8, + Main => 9 + slot.slot, + Hotbar => 36 + slot.slot, + Offhand => 45, + x => panic!("unreachable area {:?} for player window", x), + } +} + +fn chest_to_slot(x: usize) -> Option<Index> { + Some(match x { + 0..=26 => index(1, Area::Chest, x), + 27..=53 => index(0, Area::Main, x - 27), + 54..=62 => index(0, Area::Hotbar, x - 54), + _ => return None, + }) +} + +fn chest_from_slot(slot: Index) -> usize { + use Area::*; + match slot.area { + Chest => slot.slot, + Main => slot.slot + 27, + Hotbar => slot.slot + 54, + x => panic!("unreachable area {:?} for chest window", x), + } +} + +fn large_chest_to_slot(x: usize) -> Option<Index> { + Some(match x { + 0..=26 => index(1, Area::Chest, x), // top half of chest + 27..=53 => index(2, Area::Chest, x - 27), // bottom half of chest + 54..=80 => index(0, Area::Main, x - 54), + 81..=89 => index(0, Area::Hotbar, x - 81), + _ => return None, + }) +} + +fn large_chest_from_slot(slot: Index) -> usize { + use Area::*; + match slot.area { + Chest => { + let offset = if slot.inventory == 2 { 27 } else { 0 }; + slot.slot + offset + } + Main => slot.slot + 54, + Hotbar => slot.slot + 81, + x => panic!("unreachable area {:?} for chest window", x), + } +} + +fn index(inventory: usize, area: Area, slot: usize) -> Index { + Index { + inventory, + area, + slot, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn player_roundtrip() { + (0..=45).for_each(|i| assert_eq!(i, player_from_slot(player_to_slot(i).unwrap()))); + } + + #[test] + fn chest_roundtrip() { + (0..62).for_each(|i| assert_eq!(i, chest_from_slot(chest_to_slot(i).unwrap()))); + } + + #[test] + fn large_chest_roundtrip() { + (0..89).for_each(|i| assert_eq!(i, large_chest_from_slot(large_chest_to_slot(i).unwrap()))); + } +} diff --git a/item_block/Cargo.toml b/feather/old/core/item_block/Cargo.toml similarity index 63% rename from item_block/Cargo.toml rename to feather/old/core/item_block/Cargo.toml index 210f3c5da..5c73fe515 100644 --- a/item_block/Cargo.toml +++ b/feather/old/core/item_block/Cargo.toml @@ -1,11 +1,9 @@ [package] name = "feather-item-block" -version = "0.5.0" +version = "0.6.0" authors = ["caelunshun <caelum12321@gmail.com>"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] feather-blocks = { path = "../blocks" } feather-items = { path = "../items" } diff --git a/item_block/src/lib.rs b/feather/old/core/item_block/src/lib.rs similarity index 62% rename from item_block/src/lib.rs rename to feather/old/core/item_block/src/lib.rs index a0ac9772c..139ba9612 100644 --- a/item_block/src/lib.rs +++ b/feather/old/core/item_block/src/lib.rs @@ -1,14 +1,14 @@ -use feather_blocks::Block; +use feather_blocks::BlockId; use feather_items::Item; mod mappings; pub trait ItemToBlock { - fn to_block(self) -> Option<Block>; + fn to_block(self) -> Option<BlockId>; } impl ItemToBlock for Item { - fn to_block(self) -> Option<Block> { + fn to_block(self) -> Option<BlockId> { mappings::item_to_block(self) } } @@ -17,7 +17,7 @@ pub trait BlockToItem { fn to_item(self) -> Option<Item>; } -impl BlockToItem for Block { +impl BlockToItem for BlockId { fn to_item(self) -> Option<Item> { mappings::block_to_item(self) } @@ -26,7 +26,6 @@ impl BlockToItem for Block { #[cfg(test)] mod tests { use super::*; - use feather_blocks::{AcaciaWoodAxis, AcaciaWoodData, GrassBlockData}; #[test] fn test_item_to_block() { @@ -39,11 +38,9 @@ mod tests { ]; let blocks = [ None, - Some(Block::Stone), - Some(Block::AcaciaWood(AcaciaWoodData { - axis: AcaciaWoodAxis::Y, - })), - Some(Block::Cobblestone), + Some(BlockId::stone()), + Some(BlockId::acacia_wood()), + Some(BlockId::cobblestone()), None, ]; @@ -55,10 +52,10 @@ mod tests { #[test] fn test_block_to_item() { let blocks = [ - Block::Cobblestone, - Block::GrassBlock(GrassBlockData { snowy: true }), - Block::GrassBlock(GrassBlockData { snowy: false }), - Block::Sandstone, + BlockId::cobblestone(), + BlockId::grass_block().with_snowy(true), + BlockId::grass_block().with_snowy(false), + BlockId::sandstone(), ]; let items = [ @@ -69,7 +66,7 @@ mod tests { ]; for (block, item) in blocks.iter().zip(items.iter()) { - assert_eq!(block.clone().to_item(), Some(*item)); + assert_eq!(block.to_item(), Some(*item)); } } } diff --git a/feather/old/core/item_block/src/mappings.rs b/feather/old/core/item_block/src/mappings.rs new file mode 100644 index 000000000..ad695b1ce --- /dev/null +++ b/feather/old/core/item_block/src/mappings.rs @@ -0,0 +1,1048 @@ +use feather_blocks::*; +use feather_items::Item; +pub fn item_to_block(item: Item) -> Option<BlockId> { + match item { + Item::Air => Some(BlockId::air()), + Item::Stone => Some(BlockId::stone()), + Item::Granite => Some(BlockId::granite()), + Item::PolishedGranite => Some(BlockId::polished_granite()), + Item::Diorite => Some(BlockId::diorite()), + Item::PolishedDiorite => Some(BlockId::polished_diorite()), + Item::Andesite => Some(BlockId::andesite()), + Item::PolishedAndesite => Some(BlockId::polished_andesite()), + Item::GrassBlock => Some(BlockId::grass_block()), + Item::Dirt => Some(BlockId::dirt()), + Item::CoarseDirt => Some(BlockId::coarse_dirt()), + Item::Podzol => Some(BlockId::podzol()), + Item::Cobblestone => Some(BlockId::cobblestone()), + Item::OakPlanks => Some(BlockId::oak_planks()), + Item::SprucePlanks => Some(BlockId::spruce_planks()), + Item::BirchPlanks => Some(BlockId::birch_planks()), + Item::JunglePlanks => Some(BlockId::jungle_planks()), + Item::AcaciaPlanks => Some(BlockId::acacia_planks()), + Item::DarkOakPlanks => Some(BlockId::dark_oak_planks()), + Item::OakSapling => Some(BlockId::oak_sapling()), + Item::SpruceSapling => Some(BlockId::spruce_sapling()), + Item::BirchSapling => Some(BlockId::birch_sapling()), + Item::JungleSapling => Some(BlockId::jungle_sapling()), + Item::AcaciaSapling => Some(BlockId::acacia_sapling()), + Item::DarkOakSapling => Some(BlockId::dark_oak_sapling()), + Item::Bedrock => Some(BlockId::bedrock()), + Item::Sand => Some(BlockId::sand()), + Item::RedSand => Some(BlockId::red_sand()), + Item::Gravel => Some(BlockId::gravel()), + Item::GoldOre => Some(BlockId::gold_ore()), + Item::IronOre => Some(BlockId::iron_ore()), + Item::CoalOre => Some(BlockId::coal_ore()), + Item::OakLog => Some(BlockId::oak_log()), + Item::SpruceLog => Some(BlockId::spruce_log()), + Item::BirchLog => Some(BlockId::birch_log()), + Item::JungleLog => Some(BlockId::jungle_log()), + Item::AcaciaLog => Some(BlockId::acacia_log()), + Item::DarkOakLog => Some(BlockId::dark_oak_log()), + Item::StrippedOakLog => Some(BlockId::stripped_oak_log()), + Item::StrippedSpruceLog => Some(BlockId::stripped_spruce_log()), + Item::StrippedBirchLog => Some(BlockId::stripped_birch_log()), + Item::StrippedJungleLog => Some(BlockId::stripped_jungle_log()), + Item::StrippedAcaciaLog => Some(BlockId::stripped_acacia_log()), + Item::StrippedDarkOakLog => Some(BlockId::stripped_dark_oak_log()), + Item::StrippedOakWood => Some(BlockId::stripped_oak_wood()), + Item::StrippedSpruceWood => Some(BlockId::stripped_spruce_wood()), + Item::StrippedBirchWood => Some(BlockId::stripped_birch_wood()), + Item::StrippedJungleWood => Some(BlockId::stripped_jungle_wood()), + Item::StrippedAcaciaWood => Some(BlockId::stripped_acacia_wood()), + Item::StrippedDarkOakWood => Some(BlockId::stripped_dark_oak_wood()), + Item::OakWood => Some(BlockId::oak_wood()), + Item::SpruceWood => Some(BlockId::spruce_wood()), + Item::BirchWood => Some(BlockId::birch_wood()), + Item::JungleWood => Some(BlockId::jungle_wood()), + Item::AcaciaWood => Some(BlockId::acacia_wood()), + Item::DarkOakWood => Some(BlockId::dark_oak_wood()), + Item::OakLeaves => Some(BlockId::oak_leaves()), + Item::SpruceLeaves => Some(BlockId::spruce_leaves()), + Item::BirchLeaves => Some(BlockId::birch_leaves()), + Item::JungleLeaves => Some(BlockId::jungle_leaves()), + Item::AcaciaLeaves => Some(BlockId::acacia_leaves()), + Item::DarkOakLeaves => Some(BlockId::dark_oak_leaves()), + Item::Sponge => Some(BlockId::sponge()), + Item::WetSponge => Some(BlockId::wet_sponge()), + Item::Glass => Some(BlockId::glass()), + Item::LapisOre => Some(BlockId::lapis_ore()), + Item::LapisBlock => Some(BlockId::lapis_block()), + Item::Dispenser => Some(BlockId::dispenser()), + Item::Sandstone => Some(BlockId::sandstone()), + Item::ChiseledSandstone => Some(BlockId::chiseled_sandstone()), + Item::CutSandstone => Some(BlockId::cut_sandstone()), + Item::NoteBlock => Some(BlockId::note_block()), + Item::PoweredRail => Some(BlockId::powered_rail()), + Item::DetectorRail => Some(BlockId::detector_rail()), + Item::StickyPiston => Some(BlockId::sticky_piston()), + Item::Cobweb => Some(BlockId::cobweb()), + Item::Grass => Some(BlockId::grass()), + Item::Fern => Some(BlockId::fern()), + Item::DeadBush => Some(BlockId::dead_bush()), + Item::Seagrass => Some(BlockId::seagrass()), + Item::SeaPickle => Some(BlockId::sea_pickle()), + Item::Piston => Some(BlockId::piston()), + Item::WhiteWool => Some(BlockId::white_wool()), + Item::OrangeWool => Some(BlockId::orange_wool()), + Item::MagentaWool => Some(BlockId::magenta_wool()), + Item::LightBlueWool => Some(BlockId::light_blue_wool()), + Item::YellowWool => Some(BlockId::yellow_wool()), + Item::LimeWool => Some(BlockId::lime_wool()), + Item::PinkWool => Some(BlockId::pink_wool()), + Item::GrayWool => Some(BlockId::gray_wool()), + Item::LightGrayWool => Some(BlockId::light_gray_wool()), + Item::CyanWool => Some(BlockId::cyan_wool()), + Item::PurpleWool => Some(BlockId::purple_wool()), + Item::BlueWool => Some(BlockId::blue_wool()), + Item::BrownWool => Some(BlockId::brown_wool()), + Item::GreenWool => Some(BlockId::green_wool()), + Item::RedWool => Some(BlockId::red_wool()), + Item::BlackWool => Some(BlockId::black_wool()), + Item::Dandelion => Some(BlockId::dandelion()), + Item::Poppy => Some(BlockId::poppy()), + Item::BlueOrchid => Some(BlockId::blue_orchid()), + Item::Allium => Some(BlockId::allium()), + Item::AzureBluet => Some(BlockId::azure_bluet()), + Item::RedTulip => Some(BlockId::red_tulip()), + Item::OrangeTulip => Some(BlockId::orange_tulip()), + Item::WhiteTulip => Some(BlockId::white_tulip()), + Item::PinkTulip => Some(BlockId::pink_tulip()), + Item::OxeyeDaisy => Some(BlockId::oxeye_daisy()), + Item::BrownMushroom => Some(BlockId::brown_mushroom()), + Item::RedMushroom => Some(BlockId::red_mushroom()), + Item::GoldBlock => Some(BlockId::gold_block()), + Item::IronBlock => Some(BlockId::iron_block()), + Item::OakSlab => Some(BlockId::oak_slab()), + Item::SpruceSlab => Some(BlockId::spruce_slab()), + Item::BirchSlab => Some(BlockId::birch_slab()), + Item::JungleSlab => Some(BlockId::jungle_slab()), + Item::AcaciaSlab => Some(BlockId::acacia_slab()), + Item::DarkOakSlab => Some(BlockId::dark_oak_slab()), + Item::StoneSlab => Some(BlockId::stone_slab()), + Item::SandstoneSlab => Some(BlockId::sandstone_slab()), + Item::PetrifiedOakSlab => Some(BlockId::petrified_oak_slab()), + Item::CobblestoneSlab => Some(BlockId::cobblestone_slab()), + Item::BrickSlab => Some(BlockId::brick_slab()), + Item::StoneBrickSlab => Some(BlockId::stone_brick_slab()), + Item::NetherBrickSlab => Some(BlockId::nether_brick_slab()), + Item::QuartzSlab => Some(BlockId::quartz_slab()), + Item::RedSandstoneSlab => Some(BlockId::red_sandstone_slab()), + Item::PurpurSlab => Some(BlockId::purpur_slab()), + Item::PrismarineSlab => Some(BlockId::prismarine_slab()), + Item::PrismarineBrickSlab => Some(BlockId::prismarine_brick_slab()), + Item::DarkPrismarineSlab => Some(BlockId::dark_prismarine_slab()), + Item::SmoothQuartz => Some(BlockId::smooth_quartz()), + Item::SmoothRedSandstone => Some(BlockId::smooth_red_sandstone()), + Item::SmoothSandstone => Some(BlockId::smooth_sandstone()), + Item::SmoothStone => Some(BlockId::smooth_stone()), + Item::Bricks => Some(BlockId::bricks()), + Item::Tnt => Some(BlockId::tnt()), + Item::Bookshelf => Some(BlockId::bookshelf()), + Item::MossyCobblestone => Some(BlockId::mossy_cobblestone()), + Item::Obsidian => Some(BlockId::obsidian()), + Item::Torch => Some(BlockId::torch()), + Item::EndRod => Some(BlockId::end_rod()), + Item::ChorusPlant => Some(BlockId::chorus_plant()), + Item::ChorusFlower => Some(BlockId::chorus_flower()), + Item::PurpurBlock => Some(BlockId::purpur_block()), + Item::PurpurPillar => Some(BlockId::purpur_pillar()), + Item::PurpurStairs => Some(BlockId::purpur_stairs()), + Item::Spawner => Some(BlockId::spawner()), + Item::OakStairs => Some(BlockId::oak_stairs()), + Item::Chest => Some(BlockId::chest()), + Item::DiamondOre => Some(BlockId::diamond_ore()), + Item::DiamondBlock => Some(BlockId::diamond_block()), + Item::CraftingTable => Some(BlockId::crafting_table()), + Item::Farmland => Some(BlockId::farmland()), + Item::Furnace => Some(BlockId::furnace()), + Item::Ladder => Some(BlockId::ladder()), + Item::Rail => Some(BlockId::rail()), + Item::CobblestoneStairs => Some(BlockId::cobblestone_stairs()), + Item::Lever => Some(BlockId::lever()), + Item::StonePressurePlate => Some(BlockId::stone_pressure_plate()), + Item::OakPressurePlate => Some(BlockId::oak_pressure_plate()), + Item::SprucePressurePlate => Some(BlockId::spruce_pressure_plate()), + Item::BirchPressurePlate => Some(BlockId::birch_pressure_plate()), + Item::JunglePressurePlate => Some(BlockId::jungle_pressure_plate()), + Item::AcaciaPressurePlate => Some(BlockId::acacia_pressure_plate()), + Item::DarkOakPressurePlate => Some(BlockId::dark_oak_pressure_plate()), + Item::RedstoneOre => Some(BlockId::redstone_ore()), + Item::RedstoneTorch => Some(BlockId::redstone_torch()), + Item::StoneButton => Some(BlockId::stone_button()), + Item::Snow => Some(BlockId::snow()), + Item::Ice => Some(BlockId::ice()), + Item::SnowBlock => Some(BlockId::snow_block()), + Item::Cactus => Some(BlockId::cactus()), + Item::Clay => Some(BlockId::clay()), + Item::Jukebox => Some(BlockId::jukebox()), + Item::OakFence => Some(BlockId::oak_fence()), + Item::SpruceFence => Some(BlockId::spruce_fence()), + Item::BirchFence => Some(BlockId::birch_fence()), + Item::JungleFence => Some(BlockId::jungle_fence()), + Item::AcaciaFence => Some(BlockId::acacia_fence()), + Item::DarkOakFence => Some(BlockId::dark_oak_fence()), + Item::Pumpkin => Some(BlockId::pumpkin()), + Item::CarvedPumpkin => Some(BlockId::carved_pumpkin()), + Item::Netherrack => Some(BlockId::netherrack()), + Item::SoulSand => Some(BlockId::soul_sand()), + Item::Glowstone => Some(BlockId::glowstone()), + Item::JackOLantern => Some(BlockId::jack_o_lantern()), + Item::OakTrapdoor => Some(BlockId::oak_trapdoor()), + Item::SpruceTrapdoor => Some(BlockId::spruce_trapdoor()), + Item::BirchTrapdoor => Some(BlockId::birch_trapdoor()), + Item::JungleTrapdoor => Some(BlockId::jungle_trapdoor()), + Item::AcaciaTrapdoor => Some(BlockId::acacia_trapdoor()), + Item::DarkOakTrapdoor => Some(BlockId::dark_oak_trapdoor()), + Item::InfestedStone => Some(BlockId::infested_stone()), + Item::InfestedCobblestone => Some(BlockId::infested_cobblestone()), + Item::InfestedStoneBricks => Some(BlockId::infested_stone_bricks()), + Item::InfestedMossyStoneBricks => Some(BlockId::infested_mossy_stone_bricks()), + Item::InfestedCrackedStoneBricks => Some(BlockId::infested_cracked_stone_bricks()), + Item::InfestedChiseledStoneBricks => Some(BlockId::infested_chiseled_stone_bricks()), + Item::StoneBricks => Some(BlockId::stone_bricks()), + Item::MossyStoneBricks => Some(BlockId::mossy_stone_bricks()), + Item::CrackedStoneBricks => Some(BlockId::cracked_stone_bricks()), + Item::ChiseledStoneBricks => Some(BlockId::chiseled_stone_bricks()), + Item::BrownMushroomBlock => Some(BlockId::brown_mushroom_block()), + Item::RedMushroomBlock => Some(BlockId::red_mushroom_block()), + Item::MushroomStem => Some(BlockId::mushroom_stem()), + Item::IronBars => Some(BlockId::iron_bars()), + Item::GlassPane => Some(BlockId::glass_pane()), + Item::Melon => Some(BlockId::melon()), + Item::Vine => Some(BlockId::vine()), + Item::OakFenceGate => Some(BlockId::oak_fence_gate()), + Item::SpruceFenceGate => Some(BlockId::spruce_fence_gate()), + Item::BirchFenceGate => Some(BlockId::birch_fence_gate()), + Item::JungleFenceGate => Some(BlockId::jungle_fence_gate()), + Item::AcaciaFenceGate => Some(BlockId::acacia_fence_gate()), + Item::DarkOakFenceGate => Some(BlockId::dark_oak_fence_gate()), + Item::BrickStairs => Some(BlockId::brick_stairs()), + Item::StoneBrickStairs => Some(BlockId::stone_brick_stairs()), + Item::Mycelium => Some(BlockId::mycelium()), + Item::LilyPad => Some(BlockId::lily_pad()), + Item::NetherBricks => Some(BlockId::nether_bricks()), + Item::NetherBrickFence => Some(BlockId::nether_brick_fence()), + Item::NetherBrickStairs => Some(BlockId::nether_brick_stairs()), + Item::EnchantingTable => Some(BlockId::enchanting_table()), + Item::EndPortalFrame => Some(BlockId::end_portal_frame()), + Item::EndStone => Some(BlockId::end_stone()), + Item::EndStoneBricks => Some(BlockId::end_stone_bricks()), + Item::DragonEgg => Some(BlockId::dragon_egg()), + Item::RedstoneLamp => Some(BlockId::redstone_lamp()), + Item::SandstoneStairs => Some(BlockId::sandstone_stairs()), + Item::EmeraldOre => Some(BlockId::emerald_ore()), + Item::EnderChest => Some(BlockId::ender_chest()), + Item::TripwireHook => Some(BlockId::tripwire_hook()), + Item::EmeraldBlock => Some(BlockId::emerald_block()), + Item::SpruceStairs => Some(BlockId::spruce_stairs()), + Item::BirchStairs => Some(BlockId::birch_stairs()), + Item::JungleStairs => Some(BlockId::jungle_stairs()), + Item::CommandBlock => Some(BlockId::command_block()), + Item::Beacon => Some(BlockId::beacon()), + Item::CobblestoneWall => Some(BlockId::cobblestone_wall()), + Item::MossyCobblestoneWall => Some(BlockId::mossy_cobblestone_wall()), + Item::OakButton => Some(BlockId::oak_button()), + Item::SpruceButton => Some(BlockId::spruce_button()), + Item::BirchButton => Some(BlockId::birch_button()), + Item::JungleButton => Some(BlockId::jungle_button()), + Item::AcaciaButton => Some(BlockId::acacia_button()), + Item::DarkOakButton => Some(BlockId::dark_oak_button()), + Item::Anvil => Some(BlockId::anvil()), + Item::ChippedAnvil => Some(BlockId::chipped_anvil()), + Item::DamagedAnvil => Some(BlockId::damaged_anvil()), + Item::TrappedChest => Some(BlockId::trapped_chest()), + Item::LightWeightedPressurePlate => Some(BlockId::light_weighted_pressure_plate()), + Item::HeavyWeightedPressurePlate => Some(BlockId::heavy_weighted_pressure_plate()), + Item::DaylightDetector => Some(BlockId::daylight_detector()), + Item::RedstoneBlock => Some(BlockId::redstone_block()), + Item::NetherQuartzOre => Some(BlockId::nether_quartz_ore()), + Item::Hopper => Some(BlockId::hopper()), + Item::ChiseledQuartzBlock => Some(BlockId::chiseled_quartz_block()), + Item::QuartzBlock => Some(BlockId::quartz_block()), + Item::QuartzPillar => Some(BlockId::quartz_pillar()), + Item::QuartzStairs => Some(BlockId::quartz_stairs()), + Item::ActivatorRail => Some(BlockId::activator_rail()), + Item::Dropper => Some(BlockId::dropper()), + Item::WhiteTerracotta => Some(BlockId::white_terracotta()), + Item::OrangeTerracotta => Some(BlockId::orange_terracotta()), + Item::MagentaTerracotta => Some(BlockId::magenta_terracotta()), + Item::LightBlueTerracotta => Some(BlockId::light_blue_terracotta()), + Item::YellowTerracotta => Some(BlockId::yellow_terracotta()), + Item::LimeTerracotta => Some(BlockId::lime_terracotta()), + Item::PinkTerracotta => Some(BlockId::pink_terracotta()), + Item::GrayTerracotta => Some(BlockId::gray_terracotta()), + Item::LightGrayTerracotta => Some(BlockId::light_gray_terracotta()), + Item::CyanTerracotta => Some(BlockId::cyan_terracotta()), + Item::PurpleTerracotta => Some(BlockId::purple_terracotta()), + Item::BlueTerracotta => Some(BlockId::blue_terracotta()), + Item::BrownTerracotta => Some(BlockId::brown_terracotta()), + Item::GreenTerracotta => Some(BlockId::green_terracotta()), + Item::RedTerracotta => Some(BlockId::red_terracotta()), + Item::BlackTerracotta => Some(BlockId::black_terracotta()), + Item::Barrier => Some(BlockId::barrier()), + Item::IronTrapdoor => Some(BlockId::iron_trapdoor()), + Item::HayBlock => Some(BlockId::hay_block()), + Item::WhiteCarpet => Some(BlockId::white_carpet()), + Item::OrangeCarpet => Some(BlockId::orange_carpet()), + Item::MagentaCarpet => Some(BlockId::magenta_carpet()), + Item::LightBlueCarpet => Some(BlockId::light_blue_carpet()), + Item::YellowCarpet => Some(BlockId::yellow_carpet()), + Item::LimeCarpet => Some(BlockId::lime_carpet()), + Item::PinkCarpet => Some(BlockId::pink_carpet()), + Item::GrayCarpet => Some(BlockId::gray_carpet()), + Item::LightGrayCarpet => Some(BlockId::light_gray_carpet()), + Item::CyanCarpet => Some(BlockId::cyan_carpet()), + Item::PurpleCarpet => Some(BlockId::purple_carpet()), + Item::BlueCarpet => Some(BlockId::blue_carpet()), + Item::BrownCarpet => Some(BlockId::brown_carpet()), + Item::GreenCarpet => Some(BlockId::green_carpet()), + Item::RedCarpet => Some(BlockId::red_carpet()), + Item::BlackCarpet => Some(BlockId::black_carpet()), + Item::Terracotta => Some(BlockId::terracotta()), + Item::CoalBlock => Some(BlockId::coal_block()), + Item::PackedIce => Some(BlockId::packed_ice()), + Item::AcaciaStairs => Some(BlockId::acacia_stairs()), + Item::DarkOakStairs => Some(BlockId::dark_oak_stairs()), + Item::SlimeBlock => Some(BlockId::slime_block()), + Item::GrassPath => Some(BlockId::grass_path()), + Item::Sunflower => Some(BlockId::sunflower()), + Item::Lilac => Some(BlockId::lilac()), + Item::RoseBush => Some(BlockId::rose_bush()), + Item::Peony => Some(BlockId::peony()), + Item::TallGrass => Some(BlockId::tall_grass()), + Item::LargeFern => Some(BlockId::large_fern()), + Item::WhiteStainedGlass => Some(BlockId::white_stained_glass()), + Item::OrangeStainedGlass => Some(BlockId::orange_stained_glass()), + Item::MagentaStainedGlass => Some(BlockId::magenta_stained_glass()), + Item::LightBlueStainedGlass => Some(BlockId::light_blue_stained_glass()), + Item::YellowStainedGlass => Some(BlockId::yellow_stained_glass()), + Item::LimeStainedGlass => Some(BlockId::lime_stained_glass()), + Item::PinkStainedGlass => Some(BlockId::pink_stained_glass()), + Item::GrayStainedGlass => Some(BlockId::gray_stained_glass()), + Item::LightGrayStainedGlass => Some(BlockId::light_gray_stained_glass()), + Item::CyanStainedGlass => Some(BlockId::cyan_stained_glass()), + Item::PurpleStainedGlass => Some(BlockId::purple_stained_glass()), + Item::BlueStainedGlass => Some(BlockId::blue_stained_glass()), + Item::BrownStainedGlass => Some(BlockId::brown_stained_glass()), + Item::GreenStainedGlass => Some(BlockId::green_stained_glass()), + Item::RedStainedGlass => Some(BlockId::red_stained_glass()), + Item::BlackStainedGlass => Some(BlockId::black_stained_glass()), + Item::WhiteStainedGlassPane => Some(BlockId::white_stained_glass_pane()), + Item::OrangeStainedGlassPane => Some(BlockId::orange_stained_glass_pane()), + Item::MagentaStainedGlassPane => Some(BlockId::magenta_stained_glass_pane()), + Item::LightBlueStainedGlassPane => Some(BlockId::light_blue_stained_glass_pane()), + Item::YellowStainedGlassPane => Some(BlockId::yellow_stained_glass_pane()), + Item::LimeStainedGlassPane => Some(BlockId::lime_stained_glass_pane()), + Item::PinkStainedGlassPane => Some(BlockId::pink_stained_glass_pane()), + Item::GrayStainedGlassPane => Some(BlockId::gray_stained_glass_pane()), + Item::LightGrayStainedGlassPane => Some(BlockId::light_gray_stained_glass_pane()), + Item::CyanStainedGlassPane => Some(BlockId::cyan_stained_glass_pane()), + Item::PurpleStainedGlassPane => Some(BlockId::purple_stained_glass_pane()), + Item::BlueStainedGlassPane => Some(BlockId::blue_stained_glass_pane()), + Item::BrownStainedGlassPane => Some(BlockId::brown_stained_glass_pane()), + Item::GreenStainedGlassPane => Some(BlockId::green_stained_glass_pane()), + Item::RedStainedGlassPane => Some(BlockId::red_stained_glass_pane()), + Item::BlackStainedGlassPane => Some(BlockId::black_stained_glass_pane()), + Item::Prismarine => Some(BlockId::prismarine()), + Item::PrismarineBricks => Some(BlockId::prismarine_bricks()), + Item::DarkPrismarine => Some(BlockId::dark_prismarine()), + Item::PrismarineStairs => Some(BlockId::prismarine_stairs()), + Item::PrismarineBrickStairs => Some(BlockId::prismarine_brick_stairs()), + Item::DarkPrismarineStairs => Some(BlockId::dark_prismarine_stairs()), + Item::SeaLantern => Some(BlockId::sea_lantern()), + Item::RedSandstone => Some(BlockId::red_sandstone()), + Item::ChiseledRedSandstone => Some(BlockId::chiseled_red_sandstone()), + Item::CutRedSandstone => Some(BlockId::cut_red_sandstone()), + Item::RedSandstoneStairs => Some(BlockId::red_sandstone_stairs()), + Item::RepeatingCommandBlock => Some(BlockId::repeating_command_block()), + Item::ChainCommandBlock => Some(BlockId::chain_command_block()), + Item::MagmaBlock => Some(BlockId::magma_block()), + Item::NetherWartBlock => Some(BlockId::nether_wart_block()), + Item::RedNetherBricks => Some(BlockId::red_nether_bricks()), + Item::BoneBlock => Some(BlockId::bone_block()), + Item::StructureVoid => Some(BlockId::structure_void()), + Item::Observer => Some(BlockId::observer()), + Item::ShulkerBox => Some(BlockId::shulker_box()), + Item::WhiteShulkerBox => Some(BlockId::white_shulker_box()), + Item::OrangeShulkerBox => Some(BlockId::orange_shulker_box()), + Item::MagentaShulkerBox => Some(BlockId::magenta_shulker_box()), + Item::LightBlueShulkerBox => Some(BlockId::light_blue_shulker_box()), + Item::YellowShulkerBox => Some(BlockId::yellow_shulker_box()), + Item::LimeShulkerBox => Some(BlockId::lime_shulker_box()), + Item::PinkShulkerBox => Some(BlockId::pink_shulker_box()), + Item::GrayShulkerBox => Some(BlockId::gray_shulker_box()), + Item::LightGrayShulkerBox => Some(BlockId::light_gray_shulker_box()), + Item::CyanShulkerBox => Some(BlockId::cyan_shulker_box()), + Item::PurpleShulkerBox => Some(BlockId::purple_shulker_box()), + Item::BlueShulkerBox => Some(BlockId::blue_shulker_box()), + Item::BrownShulkerBox => Some(BlockId::brown_shulker_box()), + Item::GreenShulkerBox => Some(BlockId::green_shulker_box()), + Item::RedShulkerBox => Some(BlockId::red_shulker_box()), + Item::BlackShulkerBox => Some(BlockId::black_shulker_box()), + Item::WhiteGlazedTerracotta => Some(BlockId::white_glazed_terracotta()), + Item::OrangeGlazedTerracotta => Some(BlockId::orange_glazed_terracotta()), + Item::MagentaGlazedTerracotta => Some(BlockId::magenta_glazed_terracotta()), + Item::LightBlueGlazedTerracotta => Some(BlockId::light_blue_glazed_terracotta()), + Item::YellowGlazedTerracotta => Some(BlockId::yellow_glazed_terracotta()), + Item::LimeGlazedTerracotta => Some(BlockId::lime_glazed_terracotta()), + Item::PinkGlazedTerracotta => Some(BlockId::pink_glazed_terracotta()), + Item::GrayGlazedTerracotta => Some(BlockId::gray_glazed_terracotta()), + Item::LightGrayGlazedTerracotta => Some(BlockId::light_gray_glazed_terracotta()), + Item::CyanGlazedTerracotta => Some(BlockId::cyan_glazed_terracotta()), + Item::PurpleGlazedTerracotta => Some(BlockId::purple_glazed_terracotta()), + Item::BlueGlazedTerracotta => Some(BlockId::blue_glazed_terracotta()), + Item::BrownGlazedTerracotta => Some(BlockId::brown_glazed_terracotta()), + Item::GreenGlazedTerracotta => Some(BlockId::green_glazed_terracotta()), + Item::RedGlazedTerracotta => Some(BlockId::red_glazed_terracotta()), + Item::BlackGlazedTerracotta => Some(BlockId::black_glazed_terracotta()), + Item::WhiteConcrete => Some(BlockId::white_concrete()), + Item::OrangeConcrete => Some(BlockId::orange_concrete()), + Item::MagentaConcrete => Some(BlockId::magenta_concrete()), + Item::LightBlueConcrete => Some(BlockId::light_blue_concrete()), + Item::YellowConcrete => Some(BlockId::yellow_concrete()), + Item::LimeConcrete => Some(BlockId::lime_concrete()), + Item::PinkConcrete => Some(BlockId::pink_concrete()), + Item::GrayConcrete => Some(BlockId::gray_concrete()), + Item::LightGrayConcrete => Some(BlockId::light_gray_concrete()), + Item::CyanConcrete => Some(BlockId::cyan_concrete()), + Item::PurpleConcrete => Some(BlockId::purple_concrete()), + Item::BlueConcrete => Some(BlockId::blue_concrete()), + Item::BrownConcrete => Some(BlockId::brown_concrete()), + Item::GreenConcrete => Some(BlockId::green_concrete()), + Item::RedConcrete => Some(BlockId::red_concrete()), + Item::BlackConcrete => Some(BlockId::black_concrete()), + Item::WhiteConcretePowder => Some(BlockId::white_concrete_powder()), + Item::OrangeConcretePowder => Some(BlockId::orange_concrete_powder()), + Item::MagentaConcretePowder => Some(BlockId::magenta_concrete_powder()), + Item::LightBlueConcretePowder => Some(BlockId::light_blue_concrete_powder()), + Item::YellowConcretePowder => Some(BlockId::yellow_concrete_powder()), + Item::LimeConcretePowder => Some(BlockId::lime_concrete_powder()), + Item::PinkConcretePowder => Some(BlockId::pink_concrete_powder()), + Item::GrayConcretePowder => Some(BlockId::gray_concrete_powder()), + Item::LightGrayConcretePowder => Some(BlockId::light_gray_concrete_powder()), + Item::CyanConcretePowder => Some(BlockId::cyan_concrete_powder()), + Item::PurpleConcretePowder => Some(BlockId::purple_concrete_powder()), + Item::BlueConcretePowder => Some(BlockId::blue_concrete_powder()), + Item::BrownConcretePowder => Some(BlockId::brown_concrete_powder()), + Item::GreenConcretePowder => Some(BlockId::green_concrete_powder()), + Item::RedConcretePowder => Some(BlockId::red_concrete_powder()), + Item::BlackConcretePowder => Some(BlockId::black_concrete_powder()), + Item::TurtleEgg => Some(BlockId::turtle_egg()), + Item::DeadTubeCoralBlock => Some(BlockId::dead_tube_coral_block()), + Item::DeadBrainCoralBlock => Some(BlockId::dead_brain_coral_block()), + Item::DeadBubbleCoralBlock => Some(BlockId::dead_bubble_coral_block()), + Item::DeadFireCoralBlock => Some(BlockId::dead_fire_coral_block()), + Item::DeadHornCoralBlock => Some(BlockId::dead_horn_coral_block()), + Item::TubeCoralBlock => Some(BlockId::tube_coral_block()), + Item::BrainCoralBlock => Some(BlockId::brain_coral_block()), + Item::BubbleCoralBlock => Some(BlockId::bubble_coral_block()), + Item::FireCoralBlock => Some(BlockId::fire_coral_block()), + Item::HornCoralBlock => Some(BlockId::horn_coral_block()), + Item::TubeCoral => Some(BlockId::tube_coral()), + Item::BrainCoral => Some(BlockId::brain_coral()), + Item::BubbleCoral => Some(BlockId::bubble_coral()), + Item::FireCoral => Some(BlockId::fire_coral()), + Item::HornCoral => Some(BlockId::horn_coral()), + Item::DeadBrainCoral => Some(BlockId::dead_brain_coral()), + Item::DeadBubbleCoral => Some(BlockId::dead_bubble_coral()), + Item::DeadFireCoral => Some(BlockId::dead_fire_coral()), + Item::DeadHornCoral => Some(BlockId::dead_horn_coral()), + Item::DeadTubeCoral => Some(BlockId::dead_tube_coral()), + Item::TubeCoralFan => Some(BlockId::tube_coral_fan()), + Item::BrainCoralFan => Some(BlockId::brain_coral_fan()), + Item::BubbleCoralFan => Some(BlockId::bubble_coral_fan()), + Item::FireCoralFan => Some(BlockId::fire_coral_fan()), + Item::HornCoralFan => Some(BlockId::horn_coral_fan()), + Item::DeadTubeCoralFan => Some(BlockId::dead_tube_coral_fan()), + Item::DeadBrainCoralFan => Some(BlockId::dead_brain_coral_fan()), + Item::DeadBubbleCoralFan => Some(BlockId::dead_bubble_coral_fan()), + Item::DeadFireCoralFan => Some(BlockId::dead_fire_coral_fan()), + Item::DeadHornCoralFan => Some(BlockId::dead_horn_coral_fan()), + Item::BlueIce => Some(BlockId::blue_ice()), + Item::Conduit => Some(BlockId::conduit()), + Item::IronDoor => Some(BlockId::iron_door()), + Item::OakDoor => Some(BlockId::oak_door()), + Item::SpruceDoor => Some(BlockId::spruce_door()), + Item::BirchDoor => Some(BlockId::birch_door()), + Item::JungleDoor => Some(BlockId::jungle_door()), + Item::AcaciaDoor => Some(BlockId::acacia_door()), + Item::DarkOakDoor => Some(BlockId::dark_oak_door()), + Item::Repeater => Some(BlockId::repeater()), + Item::Comparator => Some(BlockId::comparator()), + Item::StructureBlock => Some(BlockId::structure_block()), + Item::Wheat => Some(BlockId::wheat()), + Item::Sign => Some(BlockId::sign()), + Item::SugarCane => Some(BlockId::sugar_cane()), + Item::Kelp => Some(BlockId::kelp()), + Item::DriedKelpBlock => Some(BlockId::dried_kelp_block()), + Item::Cake => Some(BlockId::cake()), + Item::WhiteBed => Some(BlockId::white_bed()), + Item::OrangeBed => Some(BlockId::orange_bed()), + Item::MagentaBed => Some(BlockId::magenta_bed()), + Item::LightBlueBed => Some(BlockId::light_blue_bed()), + Item::YellowBed => Some(BlockId::yellow_bed()), + Item::LimeBed => Some(BlockId::lime_bed()), + Item::PinkBed => Some(BlockId::pink_bed()), + Item::GrayBed => Some(BlockId::gray_bed()), + Item::LightGrayBed => Some(BlockId::light_gray_bed()), + Item::CyanBed => Some(BlockId::cyan_bed()), + Item::PurpleBed => Some(BlockId::purple_bed()), + Item::BlueBed => Some(BlockId::blue_bed()), + Item::BrownBed => Some(BlockId::brown_bed()), + Item::GreenBed => Some(BlockId::green_bed()), + Item::RedBed => Some(BlockId::red_bed()), + Item::BlackBed => Some(BlockId::black_bed()), + Item::NetherWart => Some(BlockId::nether_wart()), + Item::BrewingStand => Some(BlockId::brewing_stand()), + Item::Cauldron => Some(BlockId::cauldron()), + Item::FlowerPot => Some(BlockId::flower_pot()), + Item::SkeletonSkull => Some(BlockId::skeleton_skull()), + Item::WitherSkeletonSkull => Some(BlockId::wither_skeleton_skull()), + Item::PlayerHead => Some(BlockId::player_head()), + Item::ZombieHead => Some(BlockId::zombie_head()), + Item::CreeperHead => Some(BlockId::creeper_head()), + Item::DragonHead => Some(BlockId::dragon_head()), + Item::WhiteBanner => Some(BlockId::white_banner()), + Item::OrangeBanner => Some(BlockId::orange_banner()), + Item::MagentaBanner => Some(BlockId::magenta_banner()), + Item::LightBlueBanner => Some(BlockId::light_blue_banner()), + Item::YellowBanner => Some(BlockId::yellow_banner()), + Item::LimeBanner => Some(BlockId::lime_banner()), + Item::PinkBanner => Some(BlockId::pink_banner()), + Item::GrayBanner => Some(BlockId::gray_banner()), + Item::LightGrayBanner => Some(BlockId::light_gray_banner()), + Item::CyanBanner => Some(BlockId::cyan_banner()), + Item::PurpleBanner => Some(BlockId::purple_banner()), + Item::BlueBanner => Some(BlockId::blue_banner()), + Item::BrownBanner => Some(BlockId::brown_banner()), + Item::GreenBanner => Some(BlockId::green_banner()), + Item::RedBanner => Some(BlockId::red_banner()), + Item::BlackBanner => Some(BlockId::black_banner()), + _ => None, + } +} +pub fn block_to_item(block: BlockId) -> Option<Item> { + match block.kind() { + BlockKind::Air => Some(Item::Air), + BlockKind::Stone => Some(Item::Stone), + BlockKind::Granite => Some(Item::Granite), + BlockKind::PolishedGranite => Some(Item::PolishedGranite), + BlockKind::Diorite => Some(Item::Diorite), + BlockKind::PolishedDiorite => Some(Item::PolishedDiorite), + BlockKind::Andesite => Some(Item::Andesite), + BlockKind::PolishedAndesite => Some(Item::PolishedAndesite), + BlockKind::GrassBlock => Some(Item::GrassBlock), + BlockKind::Dirt => Some(Item::Dirt), + BlockKind::CoarseDirt => Some(Item::CoarseDirt), + BlockKind::Podzol => Some(Item::Podzol), + BlockKind::Cobblestone => Some(Item::Cobblestone), + BlockKind::OakPlanks => Some(Item::OakPlanks), + BlockKind::SprucePlanks => Some(Item::SprucePlanks), + BlockKind::BirchPlanks => Some(Item::BirchPlanks), + BlockKind::JunglePlanks => Some(Item::JunglePlanks), + BlockKind::AcaciaPlanks => Some(Item::AcaciaPlanks), + BlockKind::DarkOakPlanks => Some(Item::DarkOakPlanks), + BlockKind::OakSapling => Some(Item::OakSapling), + BlockKind::SpruceSapling => Some(Item::SpruceSapling), + BlockKind::BirchSapling => Some(Item::BirchSapling), + BlockKind::JungleSapling => Some(Item::JungleSapling), + BlockKind::AcaciaSapling => Some(Item::AcaciaSapling), + BlockKind::DarkOakSapling => Some(Item::DarkOakSapling), + BlockKind::Bedrock => Some(Item::Bedrock), + BlockKind::Sand => Some(Item::Sand), + BlockKind::RedSand => Some(Item::RedSand), + BlockKind::Gravel => Some(Item::Gravel), + BlockKind::GoldOre => Some(Item::GoldOre), + BlockKind::IronOre => Some(Item::IronOre), + BlockKind::CoalOre => Some(Item::CoalOre), + BlockKind::OakLog => Some(Item::OakLog), + BlockKind::SpruceLog => Some(Item::SpruceLog), + BlockKind::BirchLog => Some(Item::BirchLog), + BlockKind::JungleLog => Some(Item::JungleLog), + BlockKind::AcaciaLog => Some(Item::AcaciaLog), + BlockKind::DarkOakLog => Some(Item::DarkOakLog), + BlockKind::StrippedOakLog => Some(Item::StrippedOakLog), + BlockKind::StrippedSpruceLog => Some(Item::StrippedSpruceLog), + BlockKind::StrippedBirchLog => Some(Item::StrippedBirchLog), + BlockKind::StrippedJungleLog => Some(Item::StrippedJungleLog), + BlockKind::StrippedAcaciaLog => Some(Item::StrippedAcaciaLog), + BlockKind::StrippedDarkOakLog => Some(Item::StrippedDarkOakLog), + BlockKind::StrippedOakWood => Some(Item::StrippedOakWood), + BlockKind::StrippedSpruceWood => Some(Item::StrippedSpruceWood), + BlockKind::StrippedBirchWood => Some(Item::StrippedBirchWood), + BlockKind::StrippedJungleWood => Some(Item::StrippedJungleWood), + BlockKind::StrippedAcaciaWood => Some(Item::StrippedAcaciaWood), + BlockKind::StrippedDarkOakWood => Some(Item::StrippedDarkOakWood), + BlockKind::OakWood => Some(Item::OakWood), + BlockKind::SpruceWood => Some(Item::SpruceWood), + BlockKind::BirchWood => Some(Item::BirchWood), + BlockKind::JungleWood => Some(Item::JungleWood), + BlockKind::AcaciaWood => Some(Item::AcaciaWood), + BlockKind::DarkOakWood => Some(Item::DarkOakWood), + BlockKind::OakLeaves => Some(Item::OakLeaves), + BlockKind::SpruceLeaves => Some(Item::SpruceLeaves), + BlockKind::BirchLeaves => Some(Item::BirchLeaves), + BlockKind::JungleLeaves => Some(Item::JungleLeaves), + BlockKind::AcaciaLeaves => Some(Item::AcaciaLeaves), + BlockKind::DarkOakLeaves => Some(Item::DarkOakLeaves), + BlockKind::Sponge => Some(Item::Sponge), + BlockKind::WetSponge => Some(Item::WetSponge), + BlockKind::Glass => Some(Item::Glass), + BlockKind::LapisOre => Some(Item::LapisOre), + BlockKind::LapisBlock => Some(Item::LapisBlock), + BlockKind::Dispenser => Some(Item::Dispenser), + BlockKind::Sandstone => Some(Item::Sandstone), + BlockKind::ChiseledSandstone => Some(Item::ChiseledSandstone), + BlockKind::CutSandstone => Some(Item::CutSandstone), + BlockKind::NoteBlock => Some(Item::NoteBlock), + BlockKind::PoweredRail => Some(Item::PoweredRail), + BlockKind::DetectorRail => Some(Item::DetectorRail), + BlockKind::StickyPiston => Some(Item::StickyPiston), + BlockKind::Cobweb => Some(Item::Cobweb), + BlockKind::Grass => Some(Item::Grass), + BlockKind::Fern => Some(Item::Fern), + BlockKind::DeadBush => Some(Item::DeadBush), + BlockKind::Seagrass => Some(Item::Seagrass), + BlockKind::SeaPickle => Some(Item::SeaPickle), + BlockKind::Piston => Some(Item::Piston), + BlockKind::WhiteWool => Some(Item::WhiteWool), + BlockKind::OrangeWool => Some(Item::OrangeWool), + BlockKind::MagentaWool => Some(Item::MagentaWool), + BlockKind::LightBlueWool => Some(Item::LightBlueWool), + BlockKind::YellowWool => Some(Item::YellowWool), + BlockKind::LimeWool => Some(Item::LimeWool), + BlockKind::PinkWool => Some(Item::PinkWool), + BlockKind::GrayWool => Some(Item::GrayWool), + BlockKind::LightGrayWool => Some(Item::LightGrayWool), + BlockKind::CyanWool => Some(Item::CyanWool), + BlockKind::PurpleWool => Some(Item::PurpleWool), + BlockKind::BlueWool => Some(Item::BlueWool), + BlockKind::BrownWool => Some(Item::BrownWool), + BlockKind::GreenWool => Some(Item::GreenWool), + BlockKind::RedWool => Some(Item::RedWool), + BlockKind::BlackWool => Some(Item::BlackWool), + BlockKind::Dandelion => Some(Item::Dandelion), + BlockKind::Poppy => Some(Item::Poppy), + BlockKind::BlueOrchid => Some(Item::BlueOrchid), + BlockKind::Allium => Some(Item::Allium), + BlockKind::AzureBluet => Some(Item::AzureBluet), + BlockKind::RedTulip => Some(Item::RedTulip), + BlockKind::OrangeTulip => Some(Item::OrangeTulip), + BlockKind::WhiteTulip => Some(Item::WhiteTulip), + BlockKind::PinkTulip => Some(Item::PinkTulip), + BlockKind::OxeyeDaisy => Some(Item::OxeyeDaisy), + BlockKind::BrownMushroom => Some(Item::BrownMushroom), + BlockKind::RedMushroom => Some(Item::RedMushroom), + BlockKind::GoldBlock => Some(Item::GoldBlock), + BlockKind::IronBlock => Some(Item::IronBlock), + BlockKind::OakSlab => Some(Item::OakSlab), + BlockKind::SpruceSlab => Some(Item::SpruceSlab), + BlockKind::BirchSlab => Some(Item::BirchSlab), + BlockKind::JungleSlab => Some(Item::JungleSlab), + BlockKind::AcaciaSlab => Some(Item::AcaciaSlab), + BlockKind::DarkOakSlab => Some(Item::DarkOakSlab), + BlockKind::StoneSlab => Some(Item::StoneSlab), + BlockKind::SandstoneSlab => Some(Item::SandstoneSlab), + BlockKind::PetrifiedOakSlab => Some(Item::PetrifiedOakSlab), + BlockKind::CobblestoneSlab => Some(Item::CobblestoneSlab), + BlockKind::BrickSlab => Some(Item::BrickSlab), + BlockKind::StoneBrickSlab => Some(Item::StoneBrickSlab), + BlockKind::NetherBrickSlab => Some(Item::NetherBrickSlab), + BlockKind::QuartzSlab => Some(Item::QuartzSlab), + BlockKind::RedSandstoneSlab => Some(Item::RedSandstoneSlab), + BlockKind::PurpurSlab => Some(Item::PurpurSlab), + BlockKind::PrismarineSlab => Some(Item::PrismarineSlab), + BlockKind::PrismarineBrickSlab => Some(Item::PrismarineBrickSlab), + BlockKind::DarkPrismarineSlab => Some(Item::DarkPrismarineSlab), + BlockKind::SmoothQuartz => Some(Item::SmoothQuartz), + BlockKind::SmoothRedSandstone => Some(Item::SmoothRedSandstone), + BlockKind::SmoothSandstone => Some(Item::SmoothSandstone), + BlockKind::SmoothStone => Some(Item::SmoothStone), + BlockKind::Bricks => Some(Item::Bricks), + BlockKind::Tnt => Some(Item::Tnt), + BlockKind::Bookshelf => Some(Item::Bookshelf), + BlockKind::MossyCobblestone => Some(Item::MossyCobblestone), + BlockKind::Obsidian => Some(Item::Obsidian), + BlockKind::Torch => Some(Item::Torch), + BlockKind::EndRod => Some(Item::EndRod), + BlockKind::ChorusPlant => Some(Item::ChorusPlant), + BlockKind::ChorusFlower => Some(Item::ChorusFlower), + BlockKind::PurpurBlock => Some(Item::PurpurBlock), + BlockKind::PurpurPillar => Some(Item::PurpurPillar), + BlockKind::PurpurStairs => Some(Item::PurpurStairs), + BlockKind::Spawner => Some(Item::Spawner), + BlockKind::OakStairs => Some(Item::OakStairs), + BlockKind::Chest => Some(Item::Chest), + BlockKind::DiamondOre => Some(Item::DiamondOre), + BlockKind::DiamondBlock => Some(Item::DiamondBlock), + BlockKind::CraftingTable => Some(Item::CraftingTable), + BlockKind::Farmland => Some(Item::Farmland), + BlockKind::Furnace => Some(Item::Furnace), + BlockKind::Ladder => Some(Item::Ladder), + BlockKind::Rail => Some(Item::Rail), + BlockKind::CobblestoneStairs => Some(Item::CobblestoneStairs), + BlockKind::Lever => Some(Item::Lever), + BlockKind::StonePressurePlate => Some(Item::StonePressurePlate), + BlockKind::OakPressurePlate => Some(Item::OakPressurePlate), + BlockKind::SprucePressurePlate => Some(Item::SprucePressurePlate), + BlockKind::BirchPressurePlate => Some(Item::BirchPressurePlate), + BlockKind::JunglePressurePlate => Some(Item::JunglePressurePlate), + BlockKind::AcaciaPressurePlate => Some(Item::AcaciaPressurePlate), + BlockKind::DarkOakPressurePlate => Some(Item::DarkOakPressurePlate), + BlockKind::RedstoneOre => Some(Item::RedstoneOre), + BlockKind::RedstoneTorch => Some(Item::RedstoneTorch), + BlockKind::StoneButton => Some(Item::StoneButton), + BlockKind::Snow => Some(Item::Snow), + BlockKind::Ice => Some(Item::Ice), + BlockKind::SnowBlock => Some(Item::SnowBlock), + BlockKind::Cactus => Some(Item::Cactus), + BlockKind::Clay => Some(Item::Clay), + BlockKind::Jukebox => Some(Item::Jukebox), + BlockKind::OakFence => Some(Item::OakFence), + BlockKind::SpruceFence => Some(Item::SpruceFence), + BlockKind::BirchFence => Some(Item::BirchFence), + BlockKind::JungleFence => Some(Item::JungleFence), + BlockKind::AcaciaFence => Some(Item::AcaciaFence), + BlockKind::DarkOakFence => Some(Item::DarkOakFence), + BlockKind::Pumpkin => Some(Item::Pumpkin), + BlockKind::CarvedPumpkin => Some(Item::CarvedPumpkin), + BlockKind::Netherrack => Some(Item::Netherrack), + BlockKind::SoulSand => Some(Item::SoulSand), + BlockKind::Glowstone => Some(Item::Glowstone), + BlockKind::JackOLantern => Some(Item::JackOLantern), + BlockKind::OakTrapdoor => Some(Item::OakTrapdoor), + BlockKind::SpruceTrapdoor => Some(Item::SpruceTrapdoor), + BlockKind::BirchTrapdoor => Some(Item::BirchTrapdoor), + BlockKind::JungleTrapdoor => Some(Item::JungleTrapdoor), + BlockKind::AcaciaTrapdoor => Some(Item::AcaciaTrapdoor), + BlockKind::DarkOakTrapdoor => Some(Item::DarkOakTrapdoor), + BlockKind::InfestedStone => Some(Item::InfestedStone), + BlockKind::InfestedCobblestone => Some(Item::InfestedCobblestone), + BlockKind::InfestedStoneBricks => Some(Item::InfestedStoneBricks), + BlockKind::InfestedMossyStoneBricks => Some(Item::InfestedMossyStoneBricks), + BlockKind::InfestedCrackedStoneBricks => Some(Item::InfestedCrackedStoneBricks), + BlockKind::InfestedChiseledStoneBricks => Some(Item::InfestedChiseledStoneBricks), + BlockKind::StoneBricks => Some(Item::StoneBricks), + BlockKind::MossyStoneBricks => Some(Item::MossyStoneBricks), + BlockKind::CrackedStoneBricks => Some(Item::CrackedStoneBricks), + BlockKind::ChiseledStoneBricks => Some(Item::ChiseledStoneBricks), + BlockKind::BrownMushroomBlock => Some(Item::BrownMushroomBlock), + BlockKind::RedMushroomBlock => Some(Item::RedMushroomBlock), + BlockKind::MushroomStem => Some(Item::MushroomStem), + BlockKind::IronBars => Some(Item::IronBars), + BlockKind::GlassPane => Some(Item::GlassPane), + BlockKind::Melon => Some(Item::Melon), + BlockKind::Vine => Some(Item::Vine), + BlockKind::OakFenceGate => Some(Item::OakFenceGate), + BlockKind::SpruceFenceGate => Some(Item::SpruceFenceGate), + BlockKind::BirchFenceGate => Some(Item::BirchFenceGate), + BlockKind::JungleFenceGate => Some(Item::JungleFenceGate), + BlockKind::AcaciaFenceGate => Some(Item::AcaciaFenceGate), + BlockKind::DarkOakFenceGate => Some(Item::DarkOakFenceGate), + BlockKind::BrickStairs => Some(Item::BrickStairs), + BlockKind::StoneBrickStairs => Some(Item::StoneBrickStairs), + BlockKind::Mycelium => Some(Item::Mycelium), + BlockKind::LilyPad => Some(Item::LilyPad), + BlockKind::NetherBricks => Some(Item::NetherBricks), + BlockKind::NetherBrickFence => Some(Item::NetherBrickFence), + BlockKind::NetherBrickStairs => Some(Item::NetherBrickStairs), + BlockKind::EnchantingTable => Some(Item::EnchantingTable), + BlockKind::EndPortalFrame => Some(Item::EndPortalFrame), + BlockKind::EndStone => Some(Item::EndStone), + BlockKind::EndStoneBricks => Some(Item::EndStoneBricks), + BlockKind::DragonEgg => Some(Item::DragonEgg), + BlockKind::RedstoneLamp => Some(Item::RedstoneLamp), + BlockKind::SandstoneStairs => Some(Item::SandstoneStairs), + BlockKind::EmeraldOre => Some(Item::EmeraldOre), + BlockKind::EnderChest => Some(Item::EnderChest), + BlockKind::TripwireHook => Some(Item::TripwireHook), + BlockKind::EmeraldBlock => Some(Item::EmeraldBlock), + BlockKind::SpruceStairs => Some(Item::SpruceStairs), + BlockKind::BirchStairs => Some(Item::BirchStairs), + BlockKind::JungleStairs => Some(Item::JungleStairs), + BlockKind::CommandBlock => Some(Item::CommandBlock), + BlockKind::Beacon => Some(Item::Beacon), + BlockKind::CobblestoneWall => Some(Item::CobblestoneWall), + BlockKind::MossyCobblestoneWall => Some(Item::MossyCobblestoneWall), + BlockKind::OakButton => Some(Item::OakButton), + BlockKind::SpruceButton => Some(Item::SpruceButton), + BlockKind::BirchButton => Some(Item::BirchButton), + BlockKind::JungleButton => Some(Item::JungleButton), + BlockKind::AcaciaButton => Some(Item::AcaciaButton), + BlockKind::DarkOakButton => Some(Item::DarkOakButton), + BlockKind::Anvil => Some(Item::Anvil), + BlockKind::ChippedAnvil => Some(Item::ChippedAnvil), + BlockKind::DamagedAnvil => Some(Item::DamagedAnvil), + BlockKind::TrappedChest => Some(Item::TrappedChest), + BlockKind::LightWeightedPressurePlate => Some(Item::LightWeightedPressurePlate), + BlockKind::HeavyWeightedPressurePlate => Some(Item::HeavyWeightedPressurePlate), + BlockKind::DaylightDetector => Some(Item::DaylightDetector), + BlockKind::RedstoneBlock => Some(Item::RedstoneBlock), + BlockKind::NetherQuartzOre => Some(Item::NetherQuartzOre), + BlockKind::Hopper => Some(Item::Hopper), + BlockKind::ChiseledQuartzBlock => Some(Item::ChiseledQuartzBlock), + BlockKind::QuartzBlock => Some(Item::QuartzBlock), + BlockKind::QuartzPillar => Some(Item::QuartzPillar), + BlockKind::QuartzStairs => Some(Item::QuartzStairs), + BlockKind::ActivatorRail => Some(Item::ActivatorRail), + BlockKind::Dropper => Some(Item::Dropper), + BlockKind::WhiteTerracotta => Some(Item::WhiteTerracotta), + BlockKind::OrangeTerracotta => Some(Item::OrangeTerracotta), + BlockKind::MagentaTerracotta => Some(Item::MagentaTerracotta), + BlockKind::LightBlueTerracotta => Some(Item::LightBlueTerracotta), + BlockKind::YellowTerracotta => Some(Item::YellowTerracotta), + BlockKind::LimeTerracotta => Some(Item::LimeTerracotta), + BlockKind::PinkTerracotta => Some(Item::PinkTerracotta), + BlockKind::GrayTerracotta => Some(Item::GrayTerracotta), + BlockKind::LightGrayTerracotta => Some(Item::LightGrayTerracotta), + BlockKind::CyanTerracotta => Some(Item::CyanTerracotta), + BlockKind::PurpleTerracotta => Some(Item::PurpleTerracotta), + BlockKind::BlueTerracotta => Some(Item::BlueTerracotta), + BlockKind::BrownTerracotta => Some(Item::BrownTerracotta), + BlockKind::GreenTerracotta => Some(Item::GreenTerracotta), + BlockKind::RedTerracotta => Some(Item::RedTerracotta), + BlockKind::BlackTerracotta => Some(Item::BlackTerracotta), + BlockKind::Barrier => Some(Item::Barrier), + BlockKind::IronTrapdoor => Some(Item::IronTrapdoor), + BlockKind::HayBlock => Some(Item::HayBlock), + BlockKind::WhiteCarpet => Some(Item::WhiteCarpet), + BlockKind::OrangeCarpet => Some(Item::OrangeCarpet), + BlockKind::MagentaCarpet => Some(Item::MagentaCarpet), + BlockKind::LightBlueCarpet => Some(Item::LightBlueCarpet), + BlockKind::YellowCarpet => Some(Item::YellowCarpet), + BlockKind::LimeCarpet => Some(Item::LimeCarpet), + BlockKind::PinkCarpet => Some(Item::PinkCarpet), + BlockKind::GrayCarpet => Some(Item::GrayCarpet), + BlockKind::LightGrayCarpet => Some(Item::LightGrayCarpet), + BlockKind::CyanCarpet => Some(Item::CyanCarpet), + BlockKind::PurpleCarpet => Some(Item::PurpleCarpet), + BlockKind::BlueCarpet => Some(Item::BlueCarpet), + BlockKind::BrownCarpet => Some(Item::BrownCarpet), + BlockKind::GreenCarpet => Some(Item::GreenCarpet), + BlockKind::RedCarpet => Some(Item::RedCarpet), + BlockKind::BlackCarpet => Some(Item::BlackCarpet), + BlockKind::Terracotta => Some(Item::Terracotta), + BlockKind::CoalBlock => Some(Item::CoalBlock), + BlockKind::PackedIce => Some(Item::PackedIce), + BlockKind::AcaciaStairs => Some(Item::AcaciaStairs), + BlockKind::DarkOakStairs => Some(Item::DarkOakStairs), + BlockKind::SlimeBlock => Some(Item::SlimeBlock), + BlockKind::GrassPath => Some(Item::GrassPath), + BlockKind::Sunflower => Some(Item::Sunflower), + BlockKind::Lilac => Some(Item::Lilac), + BlockKind::RoseBush => Some(Item::RoseBush), + BlockKind::Peony => Some(Item::Peony), + BlockKind::TallGrass => Some(Item::TallGrass), + BlockKind::LargeFern => Some(Item::LargeFern), + BlockKind::WhiteStainedGlass => Some(Item::WhiteStainedGlass), + BlockKind::OrangeStainedGlass => Some(Item::OrangeStainedGlass), + BlockKind::MagentaStainedGlass => Some(Item::MagentaStainedGlass), + BlockKind::LightBlueStainedGlass => Some(Item::LightBlueStainedGlass), + BlockKind::YellowStainedGlass => Some(Item::YellowStainedGlass), + BlockKind::LimeStainedGlass => Some(Item::LimeStainedGlass), + BlockKind::PinkStainedGlass => Some(Item::PinkStainedGlass), + BlockKind::GrayStainedGlass => Some(Item::GrayStainedGlass), + BlockKind::LightGrayStainedGlass => Some(Item::LightGrayStainedGlass), + BlockKind::CyanStainedGlass => Some(Item::CyanStainedGlass), + BlockKind::PurpleStainedGlass => Some(Item::PurpleStainedGlass), + BlockKind::BlueStainedGlass => Some(Item::BlueStainedGlass), + BlockKind::BrownStainedGlass => Some(Item::BrownStainedGlass), + BlockKind::GreenStainedGlass => Some(Item::GreenStainedGlass), + BlockKind::RedStainedGlass => Some(Item::RedStainedGlass), + BlockKind::BlackStainedGlass => Some(Item::BlackStainedGlass), + BlockKind::WhiteStainedGlassPane => Some(Item::WhiteStainedGlassPane), + BlockKind::OrangeStainedGlassPane => Some(Item::OrangeStainedGlassPane), + BlockKind::MagentaStainedGlassPane => Some(Item::MagentaStainedGlassPane), + BlockKind::LightBlueStainedGlassPane => Some(Item::LightBlueStainedGlassPane), + BlockKind::YellowStainedGlassPane => Some(Item::YellowStainedGlassPane), + BlockKind::LimeStainedGlassPane => Some(Item::LimeStainedGlassPane), + BlockKind::PinkStainedGlassPane => Some(Item::PinkStainedGlassPane), + BlockKind::GrayStainedGlassPane => Some(Item::GrayStainedGlassPane), + BlockKind::LightGrayStainedGlassPane => Some(Item::LightGrayStainedGlassPane), + BlockKind::CyanStainedGlassPane => Some(Item::CyanStainedGlassPane), + BlockKind::PurpleStainedGlassPane => Some(Item::PurpleStainedGlassPane), + BlockKind::BlueStainedGlassPane => Some(Item::BlueStainedGlassPane), + BlockKind::BrownStainedGlassPane => Some(Item::BrownStainedGlassPane), + BlockKind::GreenStainedGlassPane => Some(Item::GreenStainedGlassPane), + BlockKind::RedStainedGlassPane => Some(Item::RedStainedGlassPane), + BlockKind::BlackStainedGlassPane => Some(Item::BlackStainedGlassPane), + BlockKind::Prismarine => Some(Item::Prismarine), + BlockKind::PrismarineBricks => Some(Item::PrismarineBricks), + BlockKind::DarkPrismarine => Some(Item::DarkPrismarine), + BlockKind::PrismarineStairs => Some(Item::PrismarineStairs), + BlockKind::PrismarineBrickStairs => Some(Item::PrismarineBrickStairs), + BlockKind::DarkPrismarineStairs => Some(Item::DarkPrismarineStairs), + BlockKind::SeaLantern => Some(Item::SeaLantern), + BlockKind::RedSandstone => Some(Item::RedSandstone), + BlockKind::ChiseledRedSandstone => Some(Item::ChiseledRedSandstone), + BlockKind::CutRedSandstone => Some(Item::CutRedSandstone), + BlockKind::RedSandstoneStairs => Some(Item::RedSandstoneStairs), + BlockKind::RepeatingCommandBlock => Some(Item::RepeatingCommandBlock), + BlockKind::ChainCommandBlock => Some(Item::ChainCommandBlock), + BlockKind::MagmaBlock => Some(Item::MagmaBlock), + BlockKind::NetherWartBlock => Some(Item::NetherWartBlock), + BlockKind::RedNetherBricks => Some(Item::RedNetherBricks), + BlockKind::BoneBlock => Some(Item::BoneBlock), + BlockKind::StructureVoid => Some(Item::StructureVoid), + BlockKind::Observer => Some(Item::Observer), + BlockKind::ShulkerBox => Some(Item::ShulkerBox), + BlockKind::WhiteShulkerBox => Some(Item::WhiteShulkerBox), + BlockKind::OrangeShulkerBox => Some(Item::OrangeShulkerBox), + BlockKind::MagentaShulkerBox => Some(Item::MagentaShulkerBox), + BlockKind::LightBlueShulkerBox => Some(Item::LightBlueShulkerBox), + BlockKind::YellowShulkerBox => Some(Item::YellowShulkerBox), + BlockKind::LimeShulkerBox => Some(Item::LimeShulkerBox), + BlockKind::PinkShulkerBox => Some(Item::PinkShulkerBox), + BlockKind::GrayShulkerBox => Some(Item::GrayShulkerBox), + BlockKind::LightGrayShulkerBox => Some(Item::LightGrayShulkerBox), + BlockKind::CyanShulkerBox => Some(Item::CyanShulkerBox), + BlockKind::PurpleShulkerBox => Some(Item::PurpleShulkerBox), + BlockKind::BlueShulkerBox => Some(Item::BlueShulkerBox), + BlockKind::BrownShulkerBox => Some(Item::BrownShulkerBox), + BlockKind::GreenShulkerBox => Some(Item::GreenShulkerBox), + BlockKind::RedShulkerBox => Some(Item::RedShulkerBox), + BlockKind::BlackShulkerBox => Some(Item::BlackShulkerBox), + BlockKind::WhiteGlazedTerracotta => Some(Item::WhiteGlazedTerracotta), + BlockKind::OrangeGlazedTerracotta => Some(Item::OrangeGlazedTerracotta), + BlockKind::MagentaGlazedTerracotta => Some(Item::MagentaGlazedTerracotta), + BlockKind::LightBlueGlazedTerracotta => Some(Item::LightBlueGlazedTerracotta), + BlockKind::YellowGlazedTerracotta => Some(Item::YellowGlazedTerracotta), + BlockKind::LimeGlazedTerracotta => Some(Item::LimeGlazedTerracotta), + BlockKind::PinkGlazedTerracotta => Some(Item::PinkGlazedTerracotta), + BlockKind::GrayGlazedTerracotta => Some(Item::GrayGlazedTerracotta), + BlockKind::LightGrayGlazedTerracotta => Some(Item::LightGrayGlazedTerracotta), + BlockKind::CyanGlazedTerracotta => Some(Item::CyanGlazedTerracotta), + BlockKind::PurpleGlazedTerracotta => Some(Item::PurpleGlazedTerracotta), + BlockKind::BlueGlazedTerracotta => Some(Item::BlueGlazedTerracotta), + BlockKind::BrownGlazedTerracotta => Some(Item::BrownGlazedTerracotta), + BlockKind::GreenGlazedTerracotta => Some(Item::GreenGlazedTerracotta), + BlockKind::RedGlazedTerracotta => Some(Item::RedGlazedTerracotta), + BlockKind::BlackGlazedTerracotta => Some(Item::BlackGlazedTerracotta), + BlockKind::WhiteConcrete => Some(Item::WhiteConcrete), + BlockKind::OrangeConcrete => Some(Item::OrangeConcrete), + BlockKind::MagentaConcrete => Some(Item::MagentaConcrete), + BlockKind::LightBlueConcrete => Some(Item::LightBlueConcrete), + BlockKind::YellowConcrete => Some(Item::YellowConcrete), + BlockKind::LimeConcrete => Some(Item::LimeConcrete), + BlockKind::PinkConcrete => Some(Item::PinkConcrete), + BlockKind::GrayConcrete => Some(Item::GrayConcrete), + BlockKind::LightGrayConcrete => Some(Item::LightGrayConcrete), + BlockKind::CyanConcrete => Some(Item::CyanConcrete), + BlockKind::PurpleConcrete => Some(Item::PurpleConcrete), + BlockKind::BlueConcrete => Some(Item::BlueConcrete), + BlockKind::BrownConcrete => Some(Item::BrownConcrete), + BlockKind::GreenConcrete => Some(Item::GreenConcrete), + BlockKind::RedConcrete => Some(Item::RedConcrete), + BlockKind::BlackConcrete => Some(Item::BlackConcrete), + BlockKind::WhiteConcretePowder => Some(Item::WhiteConcretePowder), + BlockKind::OrangeConcretePowder => Some(Item::OrangeConcretePowder), + BlockKind::MagentaConcretePowder => Some(Item::MagentaConcretePowder), + BlockKind::LightBlueConcretePowder => Some(Item::LightBlueConcretePowder), + BlockKind::YellowConcretePowder => Some(Item::YellowConcretePowder), + BlockKind::LimeConcretePowder => Some(Item::LimeConcretePowder), + BlockKind::PinkConcretePowder => Some(Item::PinkConcretePowder), + BlockKind::GrayConcretePowder => Some(Item::GrayConcretePowder), + BlockKind::LightGrayConcretePowder => Some(Item::LightGrayConcretePowder), + BlockKind::CyanConcretePowder => Some(Item::CyanConcretePowder), + BlockKind::PurpleConcretePowder => Some(Item::PurpleConcretePowder), + BlockKind::BlueConcretePowder => Some(Item::BlueConcretePowder), + BlockKind::BrownConcretePowder => Some(Item::BrownConcretePowder), + BlockKind::GreenConcretePowder => Some(Item::GreenConcretePowder), + BlockKind::RedConcretePowder => Some(Item::RedConcretePowder), + BlockKind::BlackConcretePowder => Some(Item::BlackConcretePowder), + BlockKind::TurtleEgg => Some(Item::TurtleEgg), + BlockKind::DeadTubeCoralBlock => Some(Item::DeadTubeCoralBlock), + BlockKind::DeadBrainCoralBlock => Some(Item::DeadBrainCoralBlock), + BlockKind::DeadBubbleCoralBlock => Some(Item::DeadBubbleCoralBlock), + BlockKind::DeadFireCoralBlock => Some(Item::DeadFireCoralBlock), + BlockKind::DeadHornCoralBlock => Some(Item::DeadHornCoralBlock), + BlockKind::TubeCoralBlock => Some(Item::TubeCoralBlock), + BlockKind::BrainCoralBlock => Some(Item::BrainCoralBlock), + BlockKind::BubbleCoralBlock => Some(Item::BubbleCoralBlock), + BlockKind::FireCoralBlock => Some(Item::FireCoralBlock), + BlockKind::HornCoralBlock => Some(Item::HornCoralBlock), + BlockKind::TubeCoral => Some(Item::TubeCoral), + BlockKind::BrainCoral => Some(Item::BrainCoral), + BlockKind::BubbleCoral => Some(Item::BubbleCoral), + BlockKind::FireCoral => Some(Item::FireCoral), + BlockKind::HornCoral => Some(Item::HornCoral), + BlockKind::DeadBrainCoral => Some(Item::DeadBrainCoral), + BlockKind::DeadBubbleCoral => Some(Item::DeadBubbleCoral), + BlockKind::DeadFireCoral => Some(Item::DeadFireCoral), + BlockKind::DeadHornCoral => Some(Item::DeadHornCoral), + BlockKind::DeadTubeCoral => Some(Item::DeadTubeCoral), + BlockKind::TubeCoralFan => Some(Item::TubeCoralFan), + BlockKind::BrainCoralFan => Some(Item::BrainCoralFan), + BlockKind::BubbleCoralFan => Some(Item::BubbleCoralFan), + BlockKind::FireCoralFan => Some(Item::FireCoralFan), + BlockKind::HornCoralFan => Some(Item::HornCoralFan), + BlockKind::DeadTubeCoralFan => Some(Item::DeadTubeCoralFan), + BlockKind::DeadBrainCoralFan => Some(Item::DeadBrainCoralFan), + BlockKind::DeadBubbleCoralFan => Some(Item::DeadBubbleCoralFan), + BlockKind::DeadFireCoralFan => Some(Item::DeadFireCoralFan), + BlockKind::DeadHornCoralFan => Some(Item::DeadHornCoralFan), + BlockKind::BlueIce => Some(Item::BlueIce), + BlockKind::Conduit => Some(Item::Conduit), + BlockKind::IronDoor => Some(Item::IronDoor), + BlockKind::OakDoor => Some(Item::OakDoor), + BlockKind::SpruceDoor => Some(Item::SpruceDoor), + BlockKind::BirchDoor => Some(Item::BirchDoor), + BlockKind::JungleDoor => Some(Item::JungleDoor), + BlockKind::AcaciaDoor => Some(Item::AcaciaDoor), + BlockKind::DarkOakDoor => Some(Item::DarkOakDoor), + BlockKind::Repeater => Some(Item::Repeater), + BlockKind::Comparator => Some(Item::Comparator), + BlockKind::StructureBlock => Some(Item::StructureBlock), + BlockKind::Wheat => Some(Item::Wheat), + BlockKind::Sign => Some(Item::Sign), + BlockKind::SugarCane => Some(Item::SugarCane), + BlockKind::Kelp => Some(Item::Kelp), + BlockKind::DriedKelpBlock => Some(Item::DriedKelpBlock), + BlockKind::Cake => Some(Item::Cake), + BlockKind::WhiteBed => Some(Item::WhiteBed), + BlockKind::OrangeBed => Some(Item::OrangeBed), + BlockKind::MagentaBed => Some(Item::MagentaBed), + BlockKind::LightBlueBed => Some(Item::LightBlueBed), + BlockKind::YellowBed => Some(Item::YellowBed), + BlockKind::LimeBed => Some(Item::LimeBed), + BlockKind::PinkBed => Some(Item::PinkBed), + BlockKind::GrayBed => Some(Item::GrayBed), + BlockKind::LightGrayBed => Some(Item::LightGrayBed), + BlockKind::CyanBed => Some(Item::CyanBed), + BlockKind::PurpleBed => Some(Item::PurpleBed), + BlockKind::BlueBed => Some(Item::BlueBed), + BlockKind::BrownBed => Some(Item::BrownBed), + BlockKind::GreenBed => Some(Item::GreenBed), + BlockKind::RedBed => Some(Item::RedBed), + BlockKind::BlackBed => Some(Item::BlackBed), + BlockKind::NetherWart => Some(Item::NetherWart), + BlockKind::BrewingStand => Some(Item::BrewingStand), + BlockKind::Cauldron => Some(Item::Cauldron), + BlockKind::FlowerPot => Some(Item::FlowerPot), + BlockKind::SkeletonSkull => Some(Item::SkeletonSkull), + BlockKind::WitherSkeletonSkull => Some(Item::WitherSkeletonSkull), + BlockKind::PlayerHead => Some(Item::PlayerHead), + BlockKind::ZombieHead => Some(Item::ZombieHead), + BlockKind::CreeperHead => Some(Item::CreeperHead), + BlockKind::DragonHead => Some(Item::DragonHead), + BlockKind::WhiteBanner => Some(Item::WhiteBanner), + BlockKind::OrangeBanner => Some(Item::OrangeBanner), + BlockKind::MagentaBanner => Some(Item::MagentaBanner), + BlockKind::LightBlueBanner => Some(Item::LightBlueBanner), + BlockKind::YellowBanner => Some(Item::YellowBanner), + BlockKind::LimeBanner => Some(Item::LimeBanner), + BlockKind::PinkBanner => Some(Item::PinkBanner), + BlockKind::GrayBanner => Some(Item::GrayBanner), + BlockKind::LightGrayBanner => Some(Item::LightGrayBanner), + BlockKind::CyanBanner => Some(Item::CyanBanner), + BlockKind::PurpleBanner => Some(Item::PurpleBanner), + BlockKind::BlueBanner => Some(Item::BlueBanner), + BlockKind::BrownBanner => Some(Item::BrownBanner), + BlockKind::GreenBanner => Some(Item::GreenBanner), + BlockKind::RedBanner => Some(Item::RedBanner), + BlockKind::BlackBanner => Some(Item::BlackBanner), + _ => None, + } +} diff --git a/feather/old/core/items/Cargo.toml b/feather/old/core/items/Cargo.toml new file mode 100644 index 000000000..a8018cf63 --- /dev/null +++ b/feather/old/core/items/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "feather-items" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-definitions = { path = "../../definitions" } diff --git a/items/data/1.13.2.dat b/feather/old/core/items/data/1.13.2.dat similarity index 100% rename from items/data/1.13.2.dat rename to feather/old/core/items/data/1.13.2.dat diff --git a/feather/old/core/items/src/lib.rs b/feather/old/core/items/src/lib.rs new file mode 100644 index 000000000..456b6c34f --- /dev/null +++ b/feather/old/core/items/src/lib.rs @@ -0,0 +1,56 @@ +#![forbid(unsafe_code, warnings)] + +pub use feather_definitions::Item; + +/// Represents an item stack. +/// +/// An item stack includes a type, an amount, and a bunch of properties (enchantments, etc.) +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ItemStack { + /// The type of this item. + pub ty: Item, + /// The number of items in this stack. + pub amount: u8, + /// Amount of damage taken on tools/equipment (how much durability expended). + pub damage: Option<i32>, + // TODO enchantments, more +} + +impl Default for ItemStack { + fn default() -> Self { + ItemStack::new(Item::Stone, 1) + } +} + +impl ItemStack { + pub const fn new(ty: Item, amount: u8) -> Self { + Self { + ty, + amount, + damage: None, + } + } + + /// Create a copy of the `ItemStack` which has the specified amount of items. + pub fn of_amount(self, amount: u8) -> Self { + let mut s = self; + s.amount = amount; + s + } + + pub fn eq_ignore_amount(self, other: Self) -> bool { + self.of_amount(0) == other.of_amount(0) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_item() { + let item = Item::Air; + assert_eq!(item.vanilla_id(), 0); + assert_eq!(Item::from_vanilla_id(0), Some(item)); + } +} diff --git a/feather/old/core/loot/Cargo.toml b/feather/old/core/loot/Cargo.toml new file mode 100644 index 000000000..fa1d938a7 --- /dev/null +++ b/feather/old/core/loot/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "feather-loot" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-loot-model = { path = "model" } +feather-items = { path = "../items" } + +serde_json = "1.0" +once_cell = "1.4" +rand = "0.7" +smallvec = "1.4" +thiserror = "1.0" +ahash = "0.3" +inlinable_string = "0.1" +itertools = "0.9" + +[build-dependencies] +feather-data = { path = "../../data" } + +feather-loot-model = { path = "model" } +serde_json = "1.0" +walkdir = "2.3" +anyhow = "1.0" diff --git a/feather/old/core/loot/build.rs b/feather/old/core/loot/build.rs new file mode 100644 index 000000000..2b3097dbd --- /dev/null +++ b/feather/old/core/loot/build.rs @@ -0,0 +1,67 @@ +use anyhow::Context; +use feather_loot_model::LootTable; +use std::io::{Read, Write}; +use std::{env, fs::File}; +use walkdir::WalkDir; + +fn main() { + if let Err(e) = run() { + panic!("{:?}", e); + } + + println!( + "cargo:rerun-if-changed={}", + concat!(env!("CARGO_MANIFEST_DIR"), "/build.rs") + ); +} + +fn run() -> anyhow::Result<()> { + // Load in all loot tables, then dump them into ${OUT_DIR}/dump.ron + // for inclusion in `feather-loot`. + let input = format!( + "{}/minecraft-1.15/data/minecraft/loot_tables", + feather_data::minecraft::PATH + ); + + let mut map = feather_loot_model::LootTableSet::default(); + + for entry in WalkDir::new(&input) { + let entry = entry.context("entry access failed")?; + + if entry.metadata()?.is_dir() { + continue; + } + + // Determine path of file relative to the base directory + let mut relative_path = entry + .path() + .strip_prefix(&input) + .with_context(|| format!("failed to strip prefix for `{}`", entry.path().display()))? + .to_str() + .context("path contains invalid UTF-8")?; + // strip .json suffix + relative_path = &relative_path[..relative_path.len() - 5]; + + // replace \\ with / for windows + let relative_path = relative_path.replace("\\", "/"); + + let mut s = String::new(); + let mut file = File::open(entry.path())?; + file.read_to_string(&mut s)?; + + let table = serde_json::from_str::<Option<LootTable>>(&s) + .with_context(|| format!("failed to parse loot table `{}`", relative_path))?; + + if let Some(table) = table { + map.0.insert(relative_path.into(), table); + } + } + + // Write the loot table map out to the dump + let dump_path = format!("{}/dump.json", env::var("OUT_DIR")?); + let mut dump = File::create(&dump_path)?; + let vec = serde_json::to_vec(&map).unwrap(); + dump.write_all(vec.as_slice())?; + + Ok(()) +} diff --git a/feather/old/core/loot/model/Cargo.toml b/feather/old/core/loot/model/Cargo.toml new file mode 100644 index 000000000..9b8f05791 --- /dev/null +++ b/feather/old/core/loot/model/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "feather-loot-model" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +smallvec = { version = "1.4", features = ["serde"] } +inlinable_string = { version = "0.1", features = ["serde"] } +ahash = "0.3" +rand = "0.7" diff --git a/feather/old/core/loot/model/src/lib.rs b/feather/old/core/loot/model/src/lib.rs new file mode 100644 index 000000000..ae99bd32f --- /dev/null +++ b/feather/old/core/loot/model/src/lib.rs @@ -0,0 +1,259 @@ +//! Defines a Serde model for loot tables. Used as an intermediate +//! representation of the table. +//! +//! The build script for `feather-loot` requires this functionality, +//! which is why it has been split into another crate. This +//! may be alleviated in the future. + +use inlinable_string::InlinableString; +use rand::Rng; +use serde::{Deserialize, Serialize}; +use smallvec::SmallVec; +use std::collections::HashMap; + +/// The set of all loaded loot tables. +/// TODO: consider a typed API as opposed to a string-based one. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LootTableSet(pub HashMap<InlinableString, LootTable, ahash::RandomState>); + +impl Default for LootTableSet { + fn default() -> Self { + LootTableSet(HashMap::with_hasher(ahash::RandomState::new())) + } +} + +/// See https://minecraft.gamepedia.com/Loot_table +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LootTable { + #[serde(rename = "type")] + pub kind: Option<LootTableKind>, + #[serde(default)] + pub pools: SmallVec<[Pool; 2]>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Pool { + /// Conditions which must be satisfied for this pool + /// to be applied. + #[serde(default)] + pub conditions: SmallVec<[Condition; 1]>, + /// Functions to apply to the resulting item stack. + #[serde(default)] + pub functions: SmallVec<[Function; 2]>, + /// Number of times to take an item from the pool. + pub rolls: FixedOrRandom, + /// The entries in the pool. Each roll, one entry + /// is selected at random from the set of entries + /// whose conditions are satisfied. The item + /// from the entry is then yielded. + pub entries: SmallVec<[Entry; 2]>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Entry { + /// Conditions which must be satisfied for this entry + /// to apply. + #[serde(default)] + pub conditions: SmallVec<[Condition; 1]>, + /// The kind of this entry. Determines in what way + /// we should produce the resulting item. + #[serde(rename = "type")] + pub kind: EntryKind, + /// Value depends on `kind`. See [`EntryKind`](enum.EntryKind.html) + #[serde(default)] + pub name: InlinableString, + /// A list of child `Entry`s interpreted depending on the value of `kind`. + #[serde(default)] + pub children: Vec<Entry>, + /// If `kind == EntryKind::Tag`, determines how the item + /// is selected from the tag. + #[serde(default)] + pub expand: bool, + /// Functions to apply to the resulting items. + #[serde(default)] + pub functions: SmallVec<[Function; 2]>, + /// Weight of this entry as compared to others, + /// when there are multiple entries in a pool. + #[serde(default = "one")] + pub weight: u32, +} + +const fn one() -> u32 { + 1 +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum EntryKind { + /// An item type. The name field specifies + /// the identifier of the item. + #[serde(alias = "minecraft:item")] + Item, + /// Depending on the value of the `expand` + /// field: + /// * Gives a random item from the tag if set to `true`. + /// * Gives all items in the tag if set to `false`. + /// + /// The tag is chosen based on the `name` field. + #[serde(alias = "minecraft:tag")] + Tag, + /// Determine the item by evaluating another loot table. + /// Name field specifies path of the loot table. + #[serde(alias = "minecraft:loot_table")] + LootTable, + /// A set of multiple child entries, each of them applied. + /// Children field contains the entries. + #[serde(alias = "minecraft:group")] + Group, + /// Like `Group`, but only selects one entry from the sub-list: + /// the first one whose conditions are satisfied. + #[serde(alias = "minecraft:alternatives")] + Alternatives, + /// Like `Group`, but only applies entries until a condition + /// is not satisfied. + #[serde(alias = "minecraft:sequence")] + Sequence, + /// Dynamically determine result based on block entity. + /// For chests, the `name` field can be set to "contents". + /// For others, such as banners, skulls, etc., the name field + /// is set to "self." + #[serde(alias = "minecraft:dynamic")] + Dynamic, + /// No action (seems to be used to add dead weights) + #[serde(alias = "minecraft:empty")] + Empty, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum LootTableKind { + /// Loot table for block drops when block is broken, + #[serde(rename = "minecraft:block")] + Block, + #[serde(other)] + /// Unknown loot table (one we don't use yet) + Unknown, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "condition")] +#[serde(rename_all = "snake_case")] +pub enum Condition { + /// Tool used to break block must match this item. + #[serde(alias = "minecraft:match_tool")] + MatchTool { predicate: ItemPredicate }, + + #[serde(alias = "minecraft:random_chance")] + RandomChance { chance: f64 }, + + // TODO + #[serde(other)] + Unknown, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ItemPredicate { + /// Enchantments present on the item + #[serde(default)] + pub enchantments: SmallVec<[Enchantment; 2]>, + /// Item identifier of the held item + pub item: Option<InlinableString>, + // TODO: tag, count, durability, nbt, potion +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "enchantment")] +pub enum Enchantment { + // TODO (blocked on Feather enchantment support) + #[serde(other)] + Unknown, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Function { + /// Function will only be applied if conditions are satisfied. + #[serde(default)] + pub conditions: SmallVec<[Condition; 1]>, + /// Kind of this function. Determines what the function does. + #[serde(flatten)] + pub kind: FunctionKind, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "function")] +pub enum FunctionKind { + // TODO + // apply_bonus, copy_name, copy_nbt, copy_state, enchant_randomly, enchant_with_levels, exploration_map, + // explosion_decay, furnace_smelt, fill_player_head, set_attribute, set_contents, set_damage, set_lore, + // set_name, set_nbt, set_stew_effect + /// Sets the stack amount. + #[serde(alias = "minecraft:set_count")] + SetCount { count: SetCountValue }, + + #[serde(other)] + Unknown, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum SetCountValue { + Fixed(u32), + Random(SetCountRandom), +} + +impl SetCountValue { + pub fn sample(&self, rng: &mut impl Rng) -> u32 { + match self { + SetCountValue::Fixed(n) => *n, + SetCountValue::Random(random) => match random { + SetCountRandom::Uniform { min, max } => { + rng.gen_range(min.round() as u32, max.round() as u32 + 1) + } + SetCountRandom::Binomial { n, p } => { + let p = p.min(1.0).max(0.0); + debug_assert!(p <= 1.0); + debug_assert!(p >= 0.0); + (0..n.round() as u32) + .take(1000) + .map(|_| if rng.gen_bool(p) { 1 } else { 0 }) + .sum() + } + }, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum SetCountRandom { + Uniform { + min: f64, + max: f64, + }, + Binomial { + /// Number of rolls + n: f64, + /// Chance of each roll + p: f64, + }, +} + +/// A struct which may have either a fixed value +/// or an inclusive range of values, selected randomly. +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum FixedOrRandom { + Fixed(f64), + Random { min: f64, max: f64 }, +} + +impl FixedOrRandom { + /// Given an RNG, returns a value for this integer. + pub fn sample(&self, rng: &mut impl Rng) -> u32 { + match self { + FixedOrRandom::Fixed(n) => n.round() as u32, + FixedOrRandom::Random { min, max } => { + rng.gen_range(min.round() as u32, max.round() as u32 + 1) + } + } + } +} diff --git a/feather/old/core/loot/src/lib.rs b/feather/old/core/loot/src/lib.rs new file mode 100644 index 000000000..01d499330 --- /dev/null +++ b/feather/old/core/loot/src/lib.rs @@ -0,0 +1,332 @@ +//! Implements sampling of loot tables. + +use ahash::AHashMap; +use feather_items::{Item, ItemStack}; +use feather_loot_model as model; +use inlinable_string::InlinableString; +use itertools::Itertools; +use model::{Condition, Entry, EntryKind, Function, FunctionKind, LootTableSet, Pool}; +use once_cell::sync::Lazy; +use rand::Rng; +use smallvec::SmallVec; +use std::iter; +use thiserror::Error; + +/// The global loot table store, initialized at runtime from +/// the embedded loot table dump. (Generated by the build script) +static STORE: Lazy<AHashMap<InlinableString, LootTable>> = Lazy::new(|| { + static BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/dump.json")); + + serde_json::from_slice::<LootTableSet>(BYTES) + .expect("invalid loot table dump") + .0 + .into_iter() + .map(|(k, v)| (k, LootTable(v))) + .collect() +}); + +/// Returns the loot table with the given ID, if it exists. +/// IDs are the same as those used in MC data packs. For example, +/// the loot table for stone blocks has ID "blocks/stone." +pub fn loot_table(id: &str) -> Option<&'static LootTable> { + STORE.get(id) +} + +/// Condition context used to determine whether loot table conditions are satisfied. +#[derive(Debug, Default)] +pub struct Conditions { + /// The item used to break a block + pub item: Option<ItemStack>, +} + +/// Opaque wrapper over `model::LootTable`. +#[derive(Debug)] +pub struct LootTable(model::LootTable); + +/// Error returned when a loot table sample fails. +#[derive(Debug, Error)] +pub enum SampleError { + #[error("invalid item identifier {0}")] + InvalidItem(String), + #[error("missing loot table {0}")] + MissingLootTable(String), + /// Should be handled gracefully. + #[error("dynamic loot table {0:?}")] + IsDynamic(DynamicKind), +} + +/// Indicates that the yielded item should +/// be computed based on a block entity. +#[derive(Debug)] +pub enum DynamicKind { + /// Drop e.g. contents of chest + Contents, + /// Drop the block itself (e.g. player head, banner) + This, +} + +impl LootTable { + /// Samples a value from the table. + /// + /// The returned set of item stacks is the result of sampling, + /// i.e. the loot which should be yielded. May return multiple + /// item stacks. No guarantee is made about the ordering + /// or distinction of the returned vector. + pub fn sample( + &self, + rng: &mut impl Rng, + conditions: &Conditions, + ) -> Result<SmallVec<[ItemStack; 2]>, SampleError> { + let mut results = SmallVec::new(); + let pools = &self.0.pools; + + // Algorithm: sample each pool. + // For each pool, evaluate `rolls` entries based on `Entry.weight` + // and yield their results. + for pool in pools { + sample_pool(pool, rng, &mut results, conditions)?; + } + + Ok(results) + } +} + +fn sample_pool( + pool: &Pool, + rng: &mut impl Rng, + results: &mut SmallVec<[ItemStack; 2]>, + conditions: &Conditions, +) -> Result<(), SampleError> { + // `rolls` times, choose an entry at random based on weighting + // and yield its results. + + // Only select from entries with their conditions satisfied + let entries = pool + .entries + .iter() + .filter(|entry| satisfies_conditions(entry.conditions.iter(), conditions, rng)) + .collect::<SmallVec<[&Entry; 4]>>(); + + let weight_sum = entries.iter().map(|entry| entry.weight).sum::<u32>(); + for _ in 0..pool.rolls.sample(rng) { + // We choose an integer at random from [0, weight_sum) and + // determine which entry has a cumulative weight matching + // the result. This algorithm is O(n) computaitonally, but this is unlikely + // to matter in practice, because loot tables rarely + // have more than one or two entries per pool. + + let n = rng.gen_range(0, weight_sum); + let mut cumulative_weight = 0; + let entry = entries + .iter() + .find(|entry| { + if n >= cumulative_weight && n < cumulative_weight + entry.weight { + true + } else { + cumulative_weight += entry.weight; + false + } + }) + .expect("entry finding algorithm incorrect"); + + sample_entry(entry, rng, results, conditions)?; + } + + // apply functions to results + results + .iter_mut() + .try_for_each(|item| apply_functions(pool.functions.iter(), item, rng, conditions))?; + + Ok(()) +} + +fn sample_entry( + entry: &Entry, + rng: &mut impl Rng, + results: &mut SmallVec<[ItemStack; 2]>, + conditions: &Conditions, +) -> Result<(), SampleError> { + let mut single; + let mut none = iter::empty(); + let mut sampled; + + let items: &mut dyn Iterator<Item = ItemStack> = match &entry.kind { + EntryKind::Empty => &mut none, + EntryKind::Item => { + let item = Item::from_identifier(&entry.name) + .ok_or_else(|| SampleError::InvalidItem(entry.name.to_string()))?; + + single = iter::once(ItemStack::new(item, 1)); + &mut single + } + EntryKind::Tag => &mut none, // TODO + EntryKind::LootTable => { + let table = loot_table(&entry.name) + .ok_or_else(|| SampleError::MissingLootTable(entry.name.to_string()))?; + + sampled = table.sample(rng, conditions)?.into_iter(); + &mut sampled + } + EntryKind::Group => { + // Return an iterator over the child entries + let mut temp = SmallVec::new(); + let entries = entry + .children + .iter() + .filter(|entry| satisfies_conditions(entry.conditions.iter(), conditions, rng)) + .collect::<SmallVec<[&Entry; 4]>>(); + entries + .into_iter() + .try_for_each(|entry| sample_entry(entry, rng, &mut temp, conditions))?; + sampled = temp.into_iter(); + &mut sampled + } + EntryKind::Alternatives => { + // Only sample first entry whose conditions are satisfied, if any + let mut temp = SmallVec::new(); + if let Some(entry) = entry + .children + .iter() + .find(|entry| satisfies_conditions(entry.conditions.iter(), conditions, rng)) + { + sample_entry(entry, rng, &mut temp, conditions)?; + } + sampled = temp.into_iter(); + &mut sampled + } + EntryKind::Sequence => { + // Apply all entries until one does not satisfy conditions + let mut temp = SmallVec::new(); + let entries = entry + .children + .iter() + .map(|entry| { + if satisfies_conditions(entry.conditions.iter(), conditions, rng) { + Some(entry) + } else { + None + } + }) + .while_some() + .collect::<SmallVec<[&Entry; 4]>>(); + entries + .into_iter() + .try_for_each(|entry| sample_entry(entry, rng, &mut temp, conditions))?; + sampled = temp.into_iter(); + &mut sampled + } + EntryKind::Dynamic => { + let kind = if entry.name == "contents" || entry.name == "minecraft:contents" { + DynamicKind::Contents + } else { + DynamicKind::This + }; + + return Err(SampleError::IsDynamic(kind)); + } + }; + + results.extend( + items + .map(|mut item| { + apply_functions(entry.functions.iter(), &mut item, rng, conditions)?; + Ok(item) + }) + .filter_map(|item: Result<ItemStack, SampleError>| item.ok()), + ); + + Ok(()) +} + +fn apply_functions<'a>( + functions: impl Iterator<Item = &'a Function>, + item: &mut ItemStack, + rng: &mut impl Rng, + conditions: &Conditions, +) -> Result<(), SampleError> { + let functions = functions + .filter(|f| satisfies_conditions(f.conditions.iter(), conditions, rng)) + .collect::<SmallVec<[&Function; 4]>>(); + for function in functions { + match &function.kind { + FunctionKind::SetCount { count } => { + let count = count.sample(rng); + item.amount = count as u8; + } + FunctionKind::Unknown => (), + } + } + + Ok(()) +} + +fn satisfies_conditions<'a>( + mut conditions: impl Iterator<Item = &'a Condition>, + input: &Conditions, + rng: &mut impl Rng, +) -> bool { + conditions.all(|condition| match condition { + Condition::MatchTool { predicate } => { + if let Some(item) = &predicate.item { + match &input.item { + Some(stack) => { + if stack.ty.identifier() != item { + return false; + } + } + None => return false, + } + } + + // enchantments are not yet supported + if !predicate.enchantments.is_empty() { + return false; + } + + true + } + Condition::RandomChance { chance } => { + let chance = chance.max(0.0).min(1.0); + rng.gen_bool(chance) + } + Condition::Unknown => true, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::rngs::mock::StepRng; + + #[test] + fn store_deserializes_successfully() { + Lazy::force(&STORE); + } + + #[test] + fn sample_dirt() { + let table = loot_table("blocks/dirt").expect("missing loot table for dirt block"); + + let mut rng = StepRng::new(0, 1); + + let items = table.sample(&mut rng, &Conditions::default()).unwrap(); + + assert_eq!(items.as_slice(), &[ItemStack::new(Item::Dirt, 1)]); + } + + #[test] + fn grass_block_condition() { + let table = loot_table("blocks/grass_block").unwrap_or_else(|| { + panic!( + "missing loot table for grass block\nnote: loaded keys: {:?}", + STORE.keys() + ); + }); + + let mut rng = StepRng::new(0, 1); + + let items = table.sample(&mut rng, &Conditions { item: None }).unwrap(); + + assert_eq!(items.as_slice(), &[ItemStack::new(Item::Dirt, 1)]); + } +} diff --git a/feather/old/core/misc/Cargo.toml b/feather/old/core/misc/Cargo.toml new file mode 100644 index 000000000..f5c20aaa0 --- /dev/null +++ b/feather/old/core/misc/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "feather-misc" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-blocks = { path = "../blocks" } +feather-items = { path = "../items" } +ordinalizer = "0.1" diff --git a/feather/old/core/misc/src/lib.rs b/feather/old/core/misc/src/lib.rs new file mode 100644 index 000000000..538bbb269 --- /dev/null +++ b/feather/old/core/misc/src/lib.rs @@ -0,0 +1,89 @@ +use feather_blocks::BlockId; +use feather_items::ItemStack; +use ordinalizer::Ordinal; + +/// This is an enum over the kinds of particles +/// listed on [the Particle data type](https://wiki.vg/index.php?title=Protocol&diff=14889&oldid=14881#Particle). +#[derive(Copy, Clone, Debug, PartialEq, Ordinal)] +pub enum ParticleData { + AmbientEntityEffect, + AngryVillager, + Barrier, + /// Block break particles + Block(BlockId), + Bubble, + Cloud, + Crit, + DamageIndicator, + DragonBreath, + DrippingLava, + FallingLava, + LandingLava, + DrippingWater, + FallingWater, + Dust { + red: f32, + green: f32, + blue: f32, + /// Clamped between 0.01 and 4.0. + scale: f32, + }, + Effect, + ElderGuardian, + EnchantedHit, + Enchant, + EndRod, + EntityEffect, + ExplosionEmitter, + Explosion, + FallingDust(BlockId), + Firework, + Fishing, + Flame, + Flash, + HappyVillager, + Composter, + Heart, + InstantEffect, + Item(Option<ItemStack>), + ItemSlime, + ItemSnowball, + LargeSmoke, + Lava, + Mycelium, + Note, + Poof, + Portal, + Rain, + Smoke, + Sneeze, + Spit, + SquidInk, + SweepAttack, + TotemOfUndying, + Underwater, + Splash, + Witch, + BublePop, + CurrentDown, + BubbleColumnUp, + Nautilus, + Dolphin, + CampfireCosySmoke, + CampfireSignalSmoke, + DrippingHoney, + FallingHoney, + LandingHoney, + FallingNectar, +} + +impl Default for ParticleData { + fn default() -> Self { + ParticleData::Dust { + red: 1.0, + blue: 0.0, + green: 0.0, + scale: 1.0, + } + } +} diff --git a/feather/old/core/network/src/mctypes.rs b/feather/old/core/network/src/mctypes.rs new file mode 100644 index 000000000..727072b73 --- /dev/null +++ b/feather/old/core/network/src/mctypes.rs @@ -0,0 +1,418 @@ +use crate::bytes_ext::{BytesExt, BytesMutExt, TryGetError}; +use bytes::{Buf, BytesMut}; +use feather_anvil::entity::ItemNbt; +use feather_entity_metadata::{EntityMetadata, MetaEntry}; +use feather_items::{Item, ItemStack}; +use feather_util::BlockPosition; +use feather_util::Direction; +use num_traits::FromPrimitive; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::collections::BTreeMap; +use std::io::Read; +use uuid::Uuid; + +/// Identifies a type to which Minecraft-specific +/// types (`VarInt`, `VarLong`, etc.) can be written. +pub trait McTypeWrite { + /// Writes a `VarInt` to the object. See wiki.vg for + /// details on `VarInt`s and related types. + /// + /// Returns the number of bytes used to encode this integer. + fn push_var_int(&mut self, x: i32) -> usize; + /// Writes a string to the object. This method + /// will first write the length of the string in bytes + /// encodes as a `VarInt` and will then write + /// the UTF-8 bytes of the string. + fn push_string(&mut self, x: &str); + + fn push_position(&mut self, x: &BlockPosition); + + fn push_bool(&mut self, x: bool); + + fn push_uuid(&mut self, x: &Uuid); + + fn push_nbt<T: Serialize>(&mut self, x: &T); + + fn push_slot(&mut self, slot: Option<ItemStack>); +} + +/// Identifies a type from which Minecraft-specified +/// types can be read. +pub trait McTypeRead { + /// Reads a `VarInt` from this object, returning + /// `Some(x)` if successful or `None` if the object + /// does not contain a valid `VarInt`. + fn try_get_var_int(&mut self) -> Result<i32, TryGetError>; + /// Reads a string from the object. + fn try_get_string(&mut self) -> Result<String, TryGetError>; + + fn try_get_position(&mut self) -> Result<BlockPosition, TryGetError>; + + fn try_get_bool(&mut self) -> Result<bool, TryGetError>; + + fn try_get_uuid(&mut self) -> anyhow::Result<Uuid>; + + fn try_get_nbt<T: DeserializeOwned>(&mut self) -> Result<T, nbt::Error>; + + fn try_get_slot(&mut self) -> Result<Option<ItemStack>, TryGetError>; +} + +impl McTypeWrite for BytesMut { + fn push_var_int(&mut self, mut x: i32) -> usize { + let mut bytes_written = 0; + loop { + let mut temp = (x & 0b0111_1111) as u8; + x = (x >> 7) & (i32::max_value() >> 6); + if x != 0 { + temp |= 0b1000_0000; + } + self.push_u8(temp); + bytes_written += 1; + if x == 0 { + break; + } + } + + bytes_written + } + + /// Writes a string to the object. This method + /// will first write the length of the string in bytes + /// encodes as a `VarInt` and will then write + /// the UTF-8 bytes of the string. + fn push_string(&mut self, x: &str) { + let bytes = x.as_bytes(); + self.push_var_int(bytes.len() as i32); + + self.extend_from_slice(bytes); + } + + fn push_position(&mut self, x: &BlockPosition) { + let result: u64 = ((x.x as u64 & 0x03FF_FFFF) << 38) + | ((x.y as u64 & 0xFFF) << 26) + | (x.z as u64 & 0x03FF_FFFF); + + self.push_u64(result); + } + + fn push_bool(&mut self, x: bool) { + if x { + self.push_u8(1); + } else { + self.push_u8(0); + } + } + + fn push_uuid(&mut self, x: &Uuid) { + self.extend_from_slice(&x.as_bytes()[..]); + } + + fn push_nbt<T: Serialize>(&mut self, val: &T) { + // TODO: fix inefficient use of temp buf. + let mut temp = vec![]; + nbt::to_writer(&mut temp, val, None).unwrap(); // Unwrap is safe because writing would only fail if a struct couldn't be written + self.extend_from_slice(&temp); + } + + fn push_slot(&mut self, slot: Option<ItemStack>) { + self.push_bool(slot.is_some()); + + if let Some(slot) = slot.as_ref() { + self.push_var_int(slot.ty.vanilla_id() as i32); + self.push_i8(slot.amount as i8); + let tags: ItemNbt = slot.into(); + + if tags != Default::default() { + self.push_nbt(&tags); + } else { + self.push_i8(0x00); // TAG_End + } + } + } +} + +impl<B: Buf + Read> McTypeRead for B { + /// Reads a `VarInt` from this object, returning + /// `Some(x)` if successful or `None` if the object + /// does not contain a valid `VarInt`. + fn try_get_var_int(&mut self) -> Result<i32, TryGetError> { + let mut num_read = 0; + let mut result = 0; + loop { + if self.remaining() == 0 { + return Err(TryGetError::NotEnoughBytes); + } + let read = self.try_get_u8()?; + let value = i32::from(read & 0b0111_1111); + result |= value.overflowing_shl(7u32 * num_read).0; + + num_read += 1; + if num_read > 5 { + return Err(TryGetError::NotEnoughBytes); + } + if read & 0b1000_0000 == 0 { + break; + } + } + Ok(result) + } + + /// Reads a string from the object. + fn try_get_string(&mut self) -> Result<String, TryGetError> { + let len = self.try_get_var_int(); + if let Ok(len) = len { + // Check that the client isn't trying + // to make the server allocate ridiculous + // amounts of memory + if len > 32767 { + return Err(TryGetError::ValueTooLarge); + } + if self.remaining() < len as usize { + return Err(TryGetError::NotEnoughBytes); + } + + let mut result = String::with_capacity(len as usize); + self.take(len as u64) + .read_to_string(&mut result) + .map_err(|_| TryGetError::NotEnoughBytes)?; + + return Ok(result); + } + + Err(TryGetError::NotEnoughBytes) + } + + fn try_get_position(&mut self) -> Result<BlockPosition, TryGetError> { + let val = self.try_get_i64()?; + let x = val >> 38; + let y = (val >> 26) & 0xFFF; + let z = val << 38 >> 38; + + Ok(BlockPosition::new(x as i32, y as i32, z as i32)) + } + + fn try_get_bool(&mut self) -> Result<bool, TryGetError> { + let byte = self.try_get_i8()?; + match byte { + 0 => Ok(false), + 1 => Ok(true), + x => Err(TryGetError::InvalidValue(i32::from(x))), + } + } + + fn try_get_uuid(&mut self) -> anyhow::Result<Uuid> { + let mut bytes = [0u8; 16]; + self.read_exact(&mut bytes)?; + Ok(Uuid::from_bytes(bytes)) + } + + fn try_get_nbt<D: DeserializeOwned>(&mut self) -> Result<D, nbt::Error> { + nbt::from_reader(self) + } + + fn try_get_slot(&mut self) -> Result<Option<ItemStack>, TryGetError> { + let present = self.try_get_bool()?; + + if !present { + return Ok(None); + } + + let id = self.try_get_var_int()?; + let ty = Item::from_vanilla_id(id as u32).ok_or(TryGetError::InvalidValue(id))?; + let amount = self.try_get_i8()? as u8; + let nbt: Option<ItemNbt> = self.try_get_nbt().ok(); + + Ok(Some(ItemStack { + ty, + amount, + damage: nbt.map(|t| t.damage).flatten(), + })) + } +} + +pub trait EntityMetaWrite { + fn push_metadata(&mut self, meta: &EntityMetadata); +} + +pub trait EntityMetaRead { + fn try_get_metadata(&mut self) -> anyhow::Result<EntityMetadata>; +} + +impl<B> EntityMetaWrite for B + where + B: BytesMutExt + McTypeWrite, +{ + fn push_metadata(&mut self, meta: &EntityMetadata) { + for (index, entry) in meta.iter() { + self.push_u8(index); + self.push_var_int(entry.id()); + write_entry_to_buf(entry, self); + } + + self.push_u8(0xff); // End of metadata + } +} + +impl<B> EntityMetaRead for B + where + B: Buf + std::io::Read, +{ + fn try_get_metadata(&mut self) -> anyhow::Result<EntityMetadata> { + let mut values = BTreeMap::new(); + + while self.has_remaining() { + let index = self.try_get_u8()?; + + if index == 0xFF { + break; + } + + let entry = try_get_entry(self)?; + values.insert(index, entry); + } + + Ok(EntityMetadata { values }) + } +} + +fn write_entry_to_buf<B>(entry: &MetaEntry, buf: &mut B) + where + B: BytesMutExt + McTypeWrite, +{ + match entry { + MetaEntry::Byte(x) => buf.push_i8(*x), + MetaEntry::VarInt(x) => { + buf.push_var_int(*x); + } + MetaEntry::Float(x) => buf.push_f32(*x), + MetaEntry::String(x) => buf.push_string(x), + MetaEntry::Chat(x) => buf.push_string(x), + MetaEntry::OptChat(ox) => { + if let Some(x) = ox { + buf.push_bool(true); + buf.push_string(x); + } else { + buf.push_bool(false); + } + } + MetaEntry::Slot(slot) => { + buf.push_slot(*slot); + } + MetaEntry::Boolean(x) => buf.push_bool(*x), + MetaEntry::Rotation(x, y, z) => { + buf.push_f32(*x); + buf.push_f32(*y); + buf.push_f32(*z); + } + MetaEntry::Position(x) => buf.push_position(x), + MetaEntry::OptPosition(ox) => { + if let Some(x) = ox { + buf.push_bool(true); + buf.push_position(x); + } else { + buf.push_bool(false); + } + } + MetaEntry::Direction(x) => { + buf.push_var_int(x.id()); + } + MetaEntry::OptUuid(ox) => { + if let Some(x) = ox { + buf.push_bool(true); + buf.push_uuid(x); + } else { + buf.push_bool(false); + } + } + MetaEntry::OptBlockId(ox) => { + if let Some(x) = ox { + buf.push_var_int(*x); + } else { + buf.push_var_int(0); // No value implies air + } + } + MetaEntry::Nbt(val) => buf.push_nbt(val), + MetaEntry::Particle => unimplemented!(), + } +} + +fn try_get_entry<B>(buf: &mut B) -> anyhow::Result<MetaEntry> + where + B: Buf + McTypeRead, +{ + let id = buf.try_get_var_int()?; + + Ok(match id { + 0 => MetaEntry::Byte(buf.try_get_i8()?), + 1 => MetaEntry::VarInt(buf.try_get_var_int()?), + 2 => MetaEntry::Float(buf.try_get_f32()?), + 3 => MetaEntry::String(buf.try_get_string()?), + 4 => MetaEntry::Chat(buf.try_get_string()?), + 5 => MetaEntry::OptChat(if buf.try_get_bool()? { + Some(buf.try_get_string()?) + } else { + None + }), + 6 => MetaEntry::Slot(buf.try_get_slot()?), + 7 => MetaEntry::Boolean(buf.try_get_bool()?), + 8 => MetaEntry::Rotation(buf.try_get_f32()?, buf.try_get_f32()?, buf.try_get_f32()?), + 9 => MetaEntry::Position(buf.try_get_position()?), + 10 => MetaEntry::OptPosition(if buf.try_get_bool()? { + Some(buf.try_get_position()?) + } else { + None + }), + 11 => MetaEntry::Direction( + Direction::from_i32(buf.try_get_var_int()?).ok_or(TryGetError::InvalidValue(0))?, + ), + 12 => MetaEntry::OptUuid(if buf.try_get_bool()? { + Some(buf.try_get_uuid()?) + } else { + None + }), + 13 => MetaEntry::OptBlockId(if buf.try_get_bool()? { + Some(buf.try_get_var_int()?) + } else { + None + }), + 14 => MetaEntry::Nbt(buf.try_get_nbt()?), + x => return Err(TryGetError::InvalidValue(x).into()), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Cursor; + + macro_rules! test_var_int_rw { + ($([$($byte:literal),* $(,)?] => $result:literal)*) => { + $( + assert_eq!( + Cursor::new(bytes::Bytes::from(vec![$($byte),*])).try_get_var_int().unwrap(), + $result + ); + let mut bytes = BytesMut::new(); + bytes.push_var_int($result); + assert_eq!(bytes.as_ref(), [$($byte),*]); + )* + }; + } + + #[test] + fn test_var_int() { + test_var_int_rw! { + [0] => 0 + [1] => 1 + [2] => 2 + [127] => 127 + [128, 1] => 128 + [255, 1] => 255 + [255, 255, 127] => 2097151 + [255, 255, 255, 255, 7] => 2147483647 + [255, 255, 255, 255, 15] => -1 + [128, 128, 128, 128, 8] => -2147483648 + } + } +} diff --git a/feather/old/core/network/src/packet.rs b/feather/old/core/network/src/packet.rs new file mode 100644 index 000000000..2f490a2f0 --- /dev/null +++ b/feather/old/core/network/src/packet.rs @@ -0,0 +1,721 @@ +use bytes::BytesMut; +use std::any::Any; +use std::io::Cursor; + +use crate::packets::IMPL_MAP; +use ahash::AHashMap; +use num_derive::{FromPrimitive, ToPrimitive}; +use once_cell::sync::Lazy; +use strum_macros::*; + +pub trait AsAny { + fn as_any(&self) -> &dyn Any; +} + +pub trait IntoAny { + fn into_any(self: Box<Self>) -> Box<dyn Any>; +} + +impl<T> IntoAny for T +where + T: Any, +{ + fn into_any(self: Box<Self>) -> Box<dyn Any> { + self + } +} + +pub trait Packet: AsAny + IntoAny + Send + Sync + Any { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()>; + fn write_to(&self, buf: &mut BytesMut); + fn ty(&self) -> PacketType; + fn ty_sized() -> PacketType + where + Self: Sized; + + /// Returns a clone of this packet in a dynamic box. + fn box_clone(&self) -> Box<dyn Packet>; +} + +#[derive(Clone, Debug)] +pub struct PacketBuilder { + pub init_fn: fn() -> Box<dyn Packet>, +} + +impl PacketBuilder { + pub fn build(&self) -> Box<dyn Packet> { + let f = self.init_fn; + f() + } + + pub fn with(f: fn() -> Box<dyn Packet>) -> Self { + Self { init_fn: f } + } +} + +#[derive( + Debug, Hash, PartialEq, Eq, Copy, Clone, EnumCount, EnumIter, ToPrimitive, FromPrimitive, +)] +pub enum PacketType { + // Serverbound + + // Handshake + Handshake, + + // Login + LoginStart, + EncryptionResponse, + LoginPluginResponse, + + // Play + TeleportConfirm, + QueryBlockNBT, + ChatMessageServerbound, + ClientStatus, + ClientSettings, + TabCompleteServerbound, + ConfirmTransactionServerbound, + EnchantItem, + ClickWindow, + CloseWindowServerbound, + PluginMessageServerbound, + EditBook, + QueryEntityNBT, + UseEntity, + KeepAliveServerbound, + Player, + PlayerPosition, + PlayerPositionAndLookServerbound, + PlayerLook, + VehicleMoveServerbound, + SteerBoat, + PickItem, + CraftRecipeRequest, + PlayerAbilitiesServerbound, + PlayerDigging, + EntityAction, + SteerVehicle, + RecipeBookData, + NameItem, + ResourcePackStatus, + AdvancementTab, + SelectTrade, + SetBeaconEffect, + HeldItemChangeServerbound, + UpdateCommandBlock, + UpdateCommandBlockMinecart, + CreativeInventoryAction, + UpdateStructureBlock, + UpdateSign, + AnimationServerbound, + Spectate, + PlayerBlockPlacement, + UseItem, + + // Status + Request, + Ping, + + // Clientbound + + // Handshake + // (none) + + // Login + DisconnectLogin, + EncryptionRequest, + LoginSuccess, + SetCompression, + LoginPluginRequest, + + // Play + SpawnObject, + SpawnExperienceOrb, + SpawnGlobalOrb, + SpawnGlobalEntity, + SpawnMob, + SpawnPainting, + SpawnPlayer, + AnimationClientbound, + Statistics, + BlockBreakAnimation, + UpdateBlockEntity, + BlockAction, + BlockChange, + BossBar, + ServerDifficulty, + ChatMessageClientbound, + MultiBlockChange, + TabCompleteClientbound, + DeclareCommands, + ConfirmTransactionClientbound, + CloseWindowClientbound, + OpenWindow, + WindowItems, + WindowProperty, + SetSlot, + SetCooldown, + PluginMessageClientbound, + NamedSoundEffect, + DisconnectPlay, + EntityStatus, + NBTQueryResponse, + Explosion, + UnloadChunk, + ChangeGameState, + KeepAliveClientbound, + ChunkData, + Effect, + Particle, + JoinGame, + MapData, + Entity, + EntityRelativeMove, + EntityLookAndRelativeMove, + EntityLook, + VehicleMoveClientbound, + OpenSignEditor, + CraftRecipeResponse, + PlayerAbilitiesClientbound, + CombatEvent, + PlayerInfo, + FacePlayer, + PlayerPositionAndLookClientbound, + UseBed, + UnlockRecipes, + DestroyEntities, + RemoveEntityEffect, + ResourcePackSend, + Respawn, + EntityHeadLook, + SelectAdvancementTab, + WorldBorder, + Camera, + HeldItemChangeClientbound, + DisplayScoreboard, + EntityMetadata, + AttachEntity, + EntityVelocity, + EntityEquipment, + SetExperience, + UpdateHealth, + ScoreboardObjective, + SetPassengers, + Teams, + UpdateScore, + SpawnPosition, + TimeUpdate, + StopSound, + SoundEffect, + PlayerListHeaderAndFooter, + CollectItem, + EntityTeleport, + Advancements, + EntityProperties, + EntityEffect, + DeclareRecipes, + Tags, + + // Status + Response, + Pong, +} + +static PACKET_ID_MAPPINGS: Lazy<AHashMap<PacketId, PacketType>> = Lazy::new(|| { + let mut m = AHashMap::new(); + + m.insert( + PacketId(0x00, PacketDirection::Serverbound, PacketStage::Handshake), + PacketType::Handshake, + ); + + m.insert( + PacketId(0x00, PacketDirection::Serverbound, PacketStage::Login), + PacketType::LoginStart, + ); + m.insert( + PacketId(0x01, PacketDirection::Serverbound, PacketStage::Login), + PacketType::EncryptionResponse, + ); + m.insert( + PacketId(0x02, PacketDirection::Serverbound, PacketStage::Login), + PacketType::LoginPluginResponse, + ); + + m.insert( + PacketId(0x00, PacketDirection::Serverbound, PacketStage::Play), + PacketType::TeleportConfirm, + ); + m.insert( + PacketId(0x01, PacketDirection::Serverbound, PacketStage::Play), + PacketType::QueryBlockNBT, + ); + m.insert( + PacketId(0x02, PacketDirection::Serverbound, PacketStage::Play), + PacketType::ChatMessageServerbound, + ); + m.insert( + PacketId(0x03, PacketDirection::Serverbound, PacketStage::Play), + PacketType::ClientStatus, + ); + m.insert( + PacketId(0x04, PacketDirection::Serverbound, PacketStage::Play), + PacketType::ClientSettings, + ); + m.insert( + PacketId(0x05, PacketDirection::Serverbound, PacketStage::Play), + PacketType::TabCompleteServerbound, + ); + m.insert( + PacketId(0x06, PacketDirection::Serverbound, PacketStage::Play), + PacketType::ConfirmTransactionServerbound, + ); + m.insert( + PacketId(0x07, PacketDirection::Serverbound, PacketStage::Play), + PacketType::EnchantItem, + ); + m.insert( + PacketId(0x08, PacketDirection::Serverbound, PacketStage::Play), + PacketType::ClickWindow, + ); + m.insert( + PacketId(0x09, PacketDirection::Serverbound, PacketStage::Play), + PacketType::CloseWindowServerbound, + ); + m.insert( + PacketId(0x0A, PacketDirection::Serverbound, PacketStage::Play), + PacketType::PluginMessageServerbound, + ); + m.insert( + PacketId(0x0B, PacketDirection::Serverbound, PacketStage::Play), + PacketType::EditBook, + ); + m.insert( + PacketId(0x0C, PacketDirection::Serverbound, PacketStage::Play), + PacketType::QueryEntityNBT, + ); + m.insert( + PacketId(0x0D, PacketDirection::Serverbound, PacketStage::Play), + PacketType::UseEntity, + ); + m.insert( + PacketId(0x0E, PacketDirection::Serverbound, PacketStage::Play), + PacketType::KeepAliveServerbound, + ); + m.insert( + PacketId(0x0F, PacketDirection::Serverbound, PacketStage::Play), + PacketType::Player, + ); + m.insert( + PacketId(0x10, PacketDirection::Serverbound, PacketStage::Play), + PacketType::PlayerPosition, + ); + m.insert( + PacketId(0x11, PacketDirection::Serverbound, PacketStage::Play), + PacketType::PlayerPositionAndLookServerbound, + ); + m.insert( + PacketId(0x12, PacketDirection::Serverbound, PacketStage::Play), + PacketType::PlayerLook, + ); + m.insert( + PacketId(0x13, PacketDirection::Serverbound, PacketStage::Play), + PacketType::VehicleMoveServerbound, + ); + m.insert( + PacketId(0x14, PacketDirection::Serverbound, PacketStage::Play), + PacketType::SteerBoat, + ); + m.insert( + PacketId(0x15, PacketDirection::Serverbound, PacketStage::Play), + PacketType::PickItem, + ); + m.insert( + PacketId(0x16, PacketDirection::Serverbound, PacketStage::Play), + PacketType::CraftRecipeRequest, + ); + m.insert( + PacketId(0x17, PacketDirection::Serverbound, PacketStage::Play), + PacketType::PlayerAbilitiesServerbound, + ); + m.insert( + PacketId(0x18, PacketDirection::Serverbound, PacketStage::Play), + PacketType::PlayerDigging, + ); + m.insert( + PacketId(0x19, PacketDirection::Serverbound, PacketStage::Play), + PacketType::EntityAction, + ); + m.insert( + PacketId(0x1A, PacketDirection::Serverbound, PacketStage::Play), + PacketType::SteerVehicle, + ); + m.insert( + PacketId(0x1B, PacketDirection::Serverbound, PacketStage::Play), + PacketType::RecipeBookData, + ); + m.insert( + PacketId(0x1C, PacketDirection::Serverbound, PacketStage::Play), + PacketType::NameItem, + ); + m.insert( + PacketId(0x1D, PacketDirection::Serverbound, PacketStage::Play), + PacketType::ResourcePackStatus, + ); + m.insert( + PacketId(0x1E, PacketDirection::Serverbound, PacketStage::Play), + PacketType::AdvancementTab, + ); + m.insert( + PacketId(0x1F, PacketDirection::Serverbound, PacketStage::Play), + PacketType::SelectTrade, + ); + m.insert( + PacketId(0x20, PacketDirection::Serverbound, PacketStage::Play), + PacketType::SetBeaconEffect, + ); + m.insert( + PacketId(0x21, PacketDirection::Serverbound, PacketStage::Play), + PacketType::HeldItemChangeServerbound, + ); + m.insert( + PacketId(0x22, PacketDirection::Serverbound, PacketStage::Play), + PacketType::UpdateCommandBlock, + ); + m.insert( + PacketId(0x23, PacketDirection::Serverbound, PacketStage::Play), + PacketType::UpdateCommandBlockMinecart, + ); + m.insert( + PacketId(0x24, PacketDirection::Serverbound, PacketStage::Play), + PacketType::CreativeInventoryAction, + ); + m.insert( + PacketId(0x25, PacketDirection::Serverbound, PacketStage::Play), + PacketType::UpdateStructureBlock, + ); + m.insert( + PacketId(0x26, PacketDirection::Serverbound, PacketStage::Play), + PacketType::UpdateSign, + ); + m.insert( + PacketId(0x27, PacketDirection::Serverbound, PacketStage::Play), + PacketType::AnimationServerbound, + ); + m.insert( + PacketId(0x28, PacketDirection::Serverbound, PacketStage::Play), + PacketType::Spectate, + ); + m.insert( + PacketId(0x29, PacketDirection::Serverbound, PacketStage::Play), + PacketType::PlayerBlockPlacement, + ); + m.insert( + PacketId(0x2A, PacketDirection::Serverbound, PacketStage::Play), + PacketType::UseItem, + ); + + m.insert( + PacketId(0x00, PacketDirection::Serverbound, PacketStage::Status), + PacketType::Request, + ); + m.insert( + PacketId(0x01, PacketDirection::Serverbound, PacketStage::Status), + PacketType::Ping, + ); + + m.insert( + PacketId(0x00, PacketDirection::Clientbound, PacketStage::Login), + PacketType::DisconnectLogin, + ); + m.insert( + PacketId(0x01, PacketDirection::Clientbound, PacketStage::Login), + PacketType::EncryptionRequest, + ); + m.insert( + PacketId(0x02, PacketDirection::Clientbound, PacketStage::Login), + PacketType::LoginSuccess, + ); + m.insert( + PacketId(0x03, PacketDirection::Clientbound, PacketStage::Login), + PacketType::SetCompression, + ); + m.insert( + PacketId(0x04, PacketDirection::Clientbound, PacketStage::Login), + PacketType::LoginPluginRequest, + ); + + m.insert( + PacketId(0x00, PacketDirection::Clientbound, PacketStage::Status), + PacketType::Response, + ); + + m.insert( + PacketId(0x01, PacketDirection::Clientbound, PacketStage::Status), + PacketType::Pong, + ); + + m.insert( + PacketId(0x00, PacketDirection::Clientbound, PacketStage::Play), + PacketType::SpawnObject, + ); + + m.insert( + PacketId(0x02, PacketDirection::Clientbound, PacketStage::Play), + PacketType::SpawnGlobalEntity, + ); + + m.insert( + PacketId(0x03, PacketDirection::Clientbound, PacketStage::Play), + PacketType::SpawnMob, + ); + + m.insert( + PacketId(0x06, PacketDirection::Clientbound, PacketStage::Play), + PacketType::AnimationClientbound, + ); + + m.insert( + PacketId(0x09, PacketDirection::Clientbound, PacketStage::Play), + PacketType::UpdateBlockEntity, + ); + + m.insert( + PacketId(0x0A, PacketDirection::Clientbound, PacketStage::Play), + PacketType::BlockAction, + ); + + m.insert( + PacketId(0x12, PacketDirection::Clientbound, PacketStage::Play), + PacketType::ConfirmTransactionClientbound, + ); + m.insert( + PacketId(0x14, PacketDirection::Clientbound, PacketStage::Play), + PacketType::OpenWindow, + ); + m.insert( + PacketId(0x15, PacketDirection::Clientbound, PacketStage::Play), + PacketType::WindowItems, + ); + m.insert( + PacketId(0x0E, PacketDirection::Clientbound, PacketStage::Play), + PacketType::ChatMessageClientbound, + ); + + m.insert( + PacketId(0x17, PacketDirection::Clientbound, PacketStage::Play), + PacketType::SetSlot, + ); + + m.insert( + PacketId(0x1A, PacketDirection::Clientbound, PacketStage::Play), + PacketType::NamedSoundEffect, + ); + + m.insert( + PacketId(0x1B, PacketDirection::Clientbound, PacketStage::Play), + PacketType::DisconnectPlay, + ); + + m.insert( + PacketId(0x1C, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityStatus, + ); + + m.insert( + PacketId(0x1F, PacketDirection::Clientbound, PacketStage::Play), + PacketType::UnloadChunk, + ); + + m.insert( + PacketId(0x21, PacketDirection::Clientbound, PacketStage::Play), + PacketType::KeepAliveClientbound, + ); + + m.insert( + PacketId(0x05, PacketDirection::Clientbound, PacketStage::Play), + PacketType::SpawnPlayer, + ); + + m.insert( + PacketId(0x08, PacketDirection::Clientbound, PacketStage::Play), + PacketType::BlockBreakAnimation, + ); + + m.insert( + PacketId(0x0B, PacketDirection::Clientbound, PacketStage::Play), + PacketType::BlockChange, + ); + + m.insert( + PacketId(0x20, PacketDirection::Clientbound, PacketStage::Play), + PacketType::ChangeGameState, + ); + + m.insert( + PacketId(0x22, PacketDirection::Clientbound, PacketStage::Play), + PacketType::ChunkData, + ); + + m.insert( + PacketId(0x23, PacketDirection::Clientbound, PacketStage::Play), + PacketType::Effect, + ); + + m.insert( + PacketId(0x24, PacketDirection::Clientbound, PacketStage::Play), + PacketType::Particle, + ); + + m.insert( + PacketId(0x25, PacketDirection::Clientbound, PacketStage::Play), + PacketType::JoinGame, + ); + + m.insert( + PacketId(0x28, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityRelativeMove, + ); + + m.insert( + PacketId(0x29, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityLookAndRelativeMove, + ); + + m.insert( + PacketId(0x2A, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityLook, + ); + + m.insert( + PacketId(0x30, PacketDirection::Clientbound, PacketStage::Play), + PacketType::PlayerInfo, + ); + + m.insert( + PacketId(0x32, PacketDirection::Clientbound, PacketStage::Play), + PacketType::PlayerPositionAndLookClientbound, + ); + + m.insert( + PacketId(0x35, PacketDirection::Clientbound, PacketStage::Play), + PacketType::DestroyEntities, + ); + + m.insert( + PacketId(0x37, PacketDirection::Clientbound, PacketStage::Play), + PacketType::ResourcePackSend, + ); + + m.insert( + PacketId(0x38, PacketDirection::Clientbound, PacketStage::Play), + PacketType::Respawn, + ); + + m.insert( + PacketId(0x39, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityHeadLook, + ); + + m.insert( + PacketId(0x3D, PacketDirection::Clientbound, PacketStage::Play), + PacketType::HeldItemChangeClientbound, + ); + + m.insert( + PacketId(0x3F, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityMetadata, + ); + + m.insert( + PacketId(0x41, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityVelocity, + ); + + m.insert( + PacketId(0x42, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityEquipment, + ); + + m.insert( + PacketId(0x44, PacketDirection::Clientbound, PacketStage::Play), + PacketType::UpdateHealth, + ); + + m.insert( + PacketId(0x49, PacketDirection::Clientbound, PacketStage::Play), + PacketType::SpawnPosition, + ); + + m.insert( + PacketId(0x4A, PacketDirection::Clientbound, PacketStage::Play), + PacketType::TimeUpdate, + ); + + m.insert( + PacketId(0x4F, PacketDirection::Clientbound, PacketStage::Play), + PacketType::CollectItem, + ); + + m.insert( + PacketId(0x50, PacketDirection::Clientbound, PacketStage::Play), + PacketType::EntityTeleport, + ); + + m.insert( + PacketId(0x55, PacketDirection::Clientbound, PacketStage::Play), + PacketType::Tags, + ); + + m +}); + +static PACKET_TYPE_MAPPINGS: Lazy<AHashMap<PacketType, PacketId>> = Lazy::new(|| { + let mut m = AHashMap::new(); + + for (key, val) in PACKET_ID_MAPPINGS.clone().into_iter() { + m.insert(val, key); + } + + m +}); + +impl PacketType { + pub fn get_from_id(id: PacketId) -> Result<PacketType, ()> { + PACKET_ID_MAPPINGS.get(&id).copied().ok_or(()) + } + + pub fn get_id(self) -> PacketId { + *PACKET_TYPE_MAPPINGS.get(&self).unwrap_or_else(|| panic!("failed to find packet ID for packet type {:?} (try inserting it into the ID map in core/network/packet.rs)", self)) + } + + pub fn get_implementation(self) -> Box<dyn Packet> { + IMPL_MAP.get(&self).unwrap().build() + } + + /// Returns a unique ID, allocated + /// consecutively for each packet type. + pub fn ordinal(self) -> usize { + self as usize + } +} + +/// Certain packets have the same ID as +/// another packet during a different login stage (blame Mojang), +/// so this struct is used to differentiate between packets like that. +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +pub struct PacketId(pub u32, pub PacketDirection, pub PacketStage); + +#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] +pub enum PacketDirection { + Serverbound, + Clientbound, +} + +#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] +pub enum PacketStage { + Handshake, + Status, + Login, + Play, +} diff --git a/core/src/network/packet/implementation.rs b/feather/old/core/network/src/packets.rs similarity index 51% rename from core/src/network/packet/implementation.rs rename to feather/old/core/network/src/packets.rs index ed9261cfd..e5b26ddd1 100644 --- a/core/src/network/packet/implementation.rs +++ b/feather/old/core/network/src/packets.rs @@ -1,112 +1,361 @@ -use super::super::mctypes::{McTypeRead, McTypeWrite}; -use super::*; use crate::bytes_ext::{BytesExt, BytesMutExt}; -use crate::entitymeta::{EntityMetaIo, EntityMetadata}; -use crate::inventory::ItemStack; -use crate::network::packet::PacketStage::Play; -use crate::prelude::*; -use crate::world::chunk::Chunk; -use crate::{Biome, ClientboundAnimation, Hand}; -use bytes::{Buf, BufMut}; -use hashbrown::HashMap; +use crate::mctypes::{EntityMetaRead, EntityMetaWrite, McTypeRead, McTypeWrite}; +use crate::packet::{AsAny, PacketBuilder}; +use crate::{Packet, PacketType}; +use ahash::AHashMap; +use bytes::{Buf, BufMut, BytesMut}; +use feather_blocks::{FacingCardinal, FacingCardinalAndDown, FacingCubic}; +use feather_chunk::Chunk; +use feather_codegen::{AsAny, Packet}; +use feather_entity_metadata::EntityMetadata; +use feather_items::ItemStack; +use feather_misc::ParticleData; +use feather_util::{BlockPosition, ClientboundAnimation, Gamemode, Hand}; +use nbt::Blob; +use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive}; +use once_cell::sync::Lazy; +use parking_lot::RwLock; +use std::any::Any; +use std::convert::TryInto; use std::io::Cursor; use std::io::Read; -use std::io::Write; +use std::sync::Arc; +use thiserror::Error; +use uuid::Uuid; + +type BlockFace = feather_blocks::Face; type VarInt = i32; -type VarLong = i64; type Slot = Option<ItemStack>; -lazy_static! { - pub static ref IMPL_MAP: HashMap<PacketType, PacketBuilder> = { - let mut m = HashMap::new(); - - // Serverbound - m.insert(PacketType::Handshake, PacketBuilder::with(|| Box::new(Handshake::default()))); - m.insert(PacketType::LoginStart, PacketBuilder::with(|| Box::new(LoginStart::default()))); - m.insert(PacketType::EncryptionResponse, PacketBuilder::with(|| Box::new(EncryptionResponse::default()))); - - m.insert(PacketType::Request, PacketBuilder::with(|| Box::new(Request::default()))); - m.insert(PacketType::Ping, PacketBuilder::with(|| Box::new(Ping::default()))); - - // Play - m.insert(PacketType::JoinGame, PacketBuilder::with(|| Box::new(JoinGame::default()))); - m.insert(PacketType::TeleportConfirm, PacketBuilder::with(|| Box::new(TeleportConfirm::default()))); - m.insert(PacketType::QueryBlockNBT, PacketBuilder::with(|| Box::new(QueryBlockNBT::default()))); - m.insert(PacketType::ChatMessageServerbound, PacketBuilder::with(|| Box::new(ChatMessageServerbound::default()))); - m.insert(PacketType::ClientStatus, PacketBuilder::with(|| Box::new(ClientStatus::default()))); - m.insert(PacketType::ClientSettings, PacketBuilder::with(|| Box::new(ClientSettings::default()))); - m.insert(PacketType::TabCompleteServerbound, PacketBuilder::with(|| Box::new(TabCompleteServerbound::default()))); - m.insert(PacketType::ConfirmTransactionServerbound, PacketBuilder::with(|| Box::new(ConfirmTransactionServerbound::default()))); - m.insert(PacketType::EnchantItem, PacketBuilder::with(|| Box::new(EnchantItem::default()))); - m.insert(PacketType::ClickWindow, PacketBuilder::with(|| Box::new(ClickWindow::default()))); - m.insert(PacketType::CloseWindowServerbound, PacketBuilder::with(|| Box::new(CloseWindowServerbound::default()))); - m.insert(PacketType::PluginMessageServerbound, PacketBuilder::with(|| Box::new(PluginMessageServerbound::default()))); - m.insert(PacketType::EditBook, PacketBuilder::with(|| Box::new(EditBook::default()))); - m.insert(PacketType::QueryEntityNBT, PacketBuilder::with(|| Box::new(QueryEntityNBT::default()))); - m.insert(PacketType::UseEntity, PacketBuilder::with(|| Box::new(UseEntity::default()))); - m.insert(PacketType::KeepAliveServerbound, PacketBuilder::with(|| Box::new(KeepAliveServerbound::default()))); - m.insert(PacketType::Player, PacketBuilder::with(|| Box::new(Player::default()))); - m.insert(PacketType::PlayerPosition, PacketBuilder::with(|| Box::new(PlayerPosition::default()))); - m.insert(PacketType::PlayerPositionAndLookServerbound, PacketBuilder::with(|| Box::new(PlayerPositionAndLookServerbound::default()))); - m.insert(PacketType::PlayerLook, PacketBuilder::with(|| Box::new(PlayerLook::default()))); - m.insert(PacketType::VehicleMoveServerbound, PacketBuilder::with(|| Box::new(VehicleMoveServerbound::default()))); - m.insert(PacketType::SteerBoat, PacketBuilder::with(|| Box::new(SteerBoat::default()))); - m.insert(PacketType::PickItem, PacketBuilder::with(|| Box::new(PickItem::default()))); - m.insert(PacketType::CraftRecipeRequest, PacketBuilder::with(|| Box::new(CraftRecipeRequest::default()))); - m.insert(PacketType::PlayerAbilitiesServerbound, PacketBuilder::with(|| Box::new(PlayerAbilitiesServerbound::default()))); - m.insert(PacketType::PlayerDigging, PacketBuilder::with(|| Box::new(PlayerDigging::default()))); - m.insert(PacketType::EntityAction, PacketBuilder::with(|| Box::new(EntityAction::default()))); - m.insert(PacketType::SteerVehicle, PacketBuilder::with(|| Box::new(SteerVehicle::default()))); - m.insert(PacketType::RecipeBookData, PacketBuilder::with(|| Box::new(RecipeBookData::default()))); - m.insert(PacketType::NameItem, PacketBuilder::with(|| Box::new(NameItem::default()))); - m.insert(PacketType::ResourcePackStatus, PacketBuilder::with(|| Box::new(ResourcePackStatus::default()))); - m.insert(PacketType::AdvancementTab, PacketBuilder::with(|| Box::new(AdvancementTab::default()))); - m.insert(PacketType::SelectTrade, PacketBuilder::with(|| Box::new(SelectTrade::default()))); - m.insert(PacketType::SetBeaconEffect, PacketBuilder::with(|| Box::new(SetBeaconEffect::default()))); - m.insert(PacketType::HeldItemChangeServerbound, PacketBuilder::with(|| Box::new(HeldItemChangeServerbound::default()))); - m.insert(PacketType::UpdateCommandBlock, PacketBuilder::with(|| Box::new(UpdateCommandBlock::default()))); - m.insert(PacketType::UpdateCommandBlockMinecart, PacketBuilder::with(|| Box::new(UpdateCommandBlockMinecart::default()))); - m.insert(PacketType::CreativeInventoryAction, PacketBuilder::with(|| Box::new(CreativeInventoryAction::default()))); - m.insert(PacketType::UpdateStructureBlock, PacketBuilder::with(|| Box::new(UpdateStructureBlock::default()))); - m.insert(PacketType::UpdateSign, PacketBuilder::with(|| Box::new(UpdateSign::default()))); - m.insert(PacketType::AnimationServerbound, PacketBuilder::with(|| Box::new(AnimationServerbound::default()))); - m.insert(PacketType::Spectate, PacketBuilder::with(|| Box::new(Spectate::default()))); - m.insert(PacketType::PlayerBlockPlacement, PacketBuilder::with(|| Box::new(PlayerBlockPlacement::default()))); - m.insert(PacketType::UseItem, PacketBuilder::with(|| Box::new(UseItem::default()))); - - m +macro_rules! insert_packet { + ($map:ident, $ty:ident) => { + $map.insert( + PacketType::$ty, + PacketBuilder::with(|| Box::new($ty::default())), + ); }; } +macro_rules! insert_packets { + ($map:ident, $($ty:ident ,)+) => { + $(insert_packet!($map, $ty));+ + } +} + +pub static IMPL_MAP: Lazy<AHashMap<PacketType, PacketBuilder>> = Lazy::new(|| { + let mut m = AHashMap::new(); + + // Serverbound + m.insert( + PacketType::Handshake, + PacketBuilder::with(|| Box::new(Handshake::default())), + ); + m.insert( + PacketType::LoginStart, + PacketBuilder::with(|| Box::new(LoginStart::default())), + ); + m.insert( + PacketType::EncryptionResponse, + PacketBuilder::with(|| Box::new(EncryptionResponse::default())), + ); + + m.insert( + PacketType::Request, + PacketBuilder::with(|| Box::new(Request::default())), + ); + m.insert( + PacketType::Ping, + PacketBuilder::with(|| Box::new(Ping::default())), + ); + + // Play + m.insert( + PacketType::JoinGame, + PacketBuilder::with(|| Box::new(JoinGame::default())), + ); + m.insert( + PacketType::TeleportConfirm, + PacketBuilder::with(|| Box::new(TeleportConfirm::default())), + ); + m.insert( + PacketType::QueryBlockNBT, + PacketBuilder::with(|| Box::new(QueryBlockNBT::default())), + ); + m.insert( + PacketType::ChatMessageServerbound, + PacketBuilder::with(|| Box::new(ChatMessageServerbound::default())), + ); + m.insert( + PacketType::ClientStatus, + PacketBuilder::with(|| Box::new(ClientStatus::default())), + ); + m.insert( + PacketType::ClientSettings, + PacketBuilder::with(|| Box::new(ClientSettings::default())), + ); + m.insert( + PacketType::TabCompleteServerbound, + PacketBuilder::with(|| Box::new(TabCompleteServerbound::default())), + ); + m.insert( + PacketType::ConfirmTransactionServerbound, + PacketBuilder::with(|| Box::new(ConfirmTransactionServerbound::default())), + ); + m.insert( + PacketType::EnchantItem, + PacketBuilder::with(|| Box::new(EnchantItem::default())), + ); + m.insert( + PacketType::ClickWindow, + PacketBuilder::with(|| Box::new(ClickWindow::default())), + ); + m.insert( + PacketType::OpenWindow, + PacketBuilder::with(|| Box::new(OpenWindow::default())), + ); + m.insert( + PacketType::CloseWindowServerbound, + PacketBuilder::with(|| Box::new(CloseWindowServerbound::default())), + ); + m.insert( + PacketType::PluginMessageServerbound, + PacketBuilder::with(|| Box::new(PluginMessageServerbound::default())), + ); + m.insert( + PacketType::EditBook, + PacketBuilder::with(|| Box::new(EditBook::default())), + ); + m.insert( + PacketType::QueryEntityNBT, + PacketBuilder::with(|| Box::new(QueryEntityNBT::default())), + ); + m.insert( + PacketType::UseEntity, + PacketBuilder::with(|| Box::new(UseEntity::default())), + ); + m.insert( + PacketType::KeepAliveServerbound, + PacketBuilder::with(|| Box::new(KeepAliveServerbound::default())), + ); + m.insert( + PacketType::Player, + PacketBuilder::with(|| Box::new(Player::default())), + ); + m.insert( + PacketType::PlayerPosition, + PacketBuilder::with(|| Box::new(PlayerPosition::default())), + ); + m.insert( + PacketType::PlayerPositionAndLookServerbound, + PacketBuilder::with(|| Box::new(PlayerPositionAndLookServerbound::default())), + ); + m.insert( + PacketType::PlayerLook, + PacketBuilder::with(|| Box::new(PlayerLook::default())), + ); + m.insert( + PacketType::VehicleMoveServerbound, + PacketBuilder::with(|| Box::new(VehicleMoveServerbound::default())), + ); + m.insert( + PacketType::SteerBoat, + PacketBuilder::with(|| Box::new(SteerBoat::default())), + ); + m.insert( + PacketType::PickItem, + PacketBuilder::with(|| Box::new(PickItem::default())), + ); + m.insert( + PacketType::CraftRecipeRequest, + PacketBuilder::with(|| Box::new(CraftRecipeRequest::default())), + ); + m.insert( + PacketType::PlayerAbilitiesServerbound, + PacketBuilder::with(|| Box::new(PlayerAbilitiesServerbound::default())), + ); + m.insert( + PacketType::PlayerDigging, + PacketBuilder::with(|| Box::new(PlayerDigging::default())), + ); + m.insert( + PacketType::EntityAction, + PacketBuilder::with(|| Box::new(EntityAction::default())), + ); + m.insert( + PacketType::SteerVehicle, + PacketBuilder::with(|| Box::new(SteerVehicle::default())), + ); + m.insert( + PacketType::RecipeBookData, + PacketBuilder::with(|| Box::new(RecipeBookData::default())), + ); + m.insert( + PacketType::NameItem, + PacketBuilder::with(|| Box::new(NameItem::default())), + ); + m.insert( + PacketType::ResourcePackStatus, + PacketBuilder::with(|| Box::new(ResourcePackStatus::default())), + ); + m.insert( + PacketType::AdvancementTab, + PacketBuilder::with(|| Box::new(AdvancementTab::default())), + ); + m.insert( + PacketType::SelectTrade, + PacketBuilder::with(|| Box::new(SelectTrade::default())), + ); + m.insert( + PacketType::SetBeaconEffect, + PacketBuilder::with(|| Box::new(SetBeaconEffect::default())), + ); + m.insert( + PacketType::HeldItemChangeServerbound, + PacketBuilder::with(|| Box::new(HeldItemChangeServerbound::default())), + ); + m.insert( + PacketType::UpdateCommandBlock, + PacketBuilder::with(|| Box::new(UpdateCommandBlock::default())), + ); + m.insert( + PacketType::UpdateCommandBlockMinecart, + PacketBuilder::with(|| Box::new(UpdateCommandBlockMinecart::default())), + ); + m.insert( + PacketType::CreativeInventoryAction, + PacketBuilder::with(|| Box::new(CreativeInventoryAction::default())), + ); + m.insert( + PacketType::UpdateStructureBlock, + PacketBuilder::with(|| Box::new(UpdateStructureBlock::default())), + ); + m.insert( + PacketType::UpdateSign, + PacketBuilder::with(|| Box::new(UpdateSign::default())), + ); + m.insert( + PacketType::AnimationServerbound, + PacketBuilder::with(|| Box::new(AnimationServerbound::default())), + ); + m.insert( + PacketType::Spectate, + PacketBuilder::with(|| Box::new(Spectate::default())), + ); + m.insert( + PacketType::PlayerBlockPlacement, + PacketBuilder::with(|| Box::new(PlayerBlockPlacement::default())), + ); + m.insert( + PacketType::UseItem, + PacketBuilder::with(|| Box::new(UseItem::default())), + ); + + // Clientbound + + m.insert( + PacketType::EntityMetadata, + PacketBuilder::with(|| Box::new(PacketEntityMetadata::default())), + ); + + insert_packets!( + m, + DisconnectLogin, + EncryptionRequest, + LoginSuccess, + SetCompression, + SpawnObject, + SpawnExperienceOrb, + SpawnGlobalEntity, + SpawnMob, + SpawnPainting, + SpawnPlayer, + AnimationClientbound, + Statistics, + BlockBreakAnimation, + UpdateBlockEntity, + BlockAction, + BlockChange, + BossBar, + ServerDifficulty, + ChatMessageClientbound, + OpenWindow, + WindowItems, + WindowProperty, + SetSlot, + SetCooldown, + PluginMessageClientbound, + NamedSoundEffect, + DisconnectPlay, + EntityStatus, + NBTQueryResponse, + Explosion, + UnloadChunk, + ChangeGameState, + KeepAliveClientbound, + ChunkData, + Effect, + Particle, + JoinGame, + EntityRelativeMove, + EntityLookAndRelativeMove, + EntityLook, + VehicleMoveClientbound, + OpenSignEditor, + CraftRecipeResponse, + CombatEvent, + PlayerInfo, + PlayerPositionAndLookClientbound, + UseBed, + DestroyEntities, + RemoveEntityEffect, + ResourcePackSend, + Respawn, + EntityHeadLook, + EntityVelocity, + EntityEquipment, + HeldItemChangeClientbound, + UpdateHealth, + SpawnPosition, + TimeUpdate, + CollectItem, + EntityTeleport, + Tags, + Response, + Pong, + ); + + m +}); + macro_rules! box_clone_impl { ($this:ident) => { return Box::new((*$this).clone()); }; } -#[derive(Clone, Copy, Fail, Debug)] +#[derive(Clone, Copy, Error, Debug)] pub enum Error { - #[fail(display = "invalid face value {}", _0)] + #[error("invalid face value {0}")] InvalidFace(i32), - #[fail(display = "invalid hand value {}", _0)] + #[error("invalid hand value {0}")] InvalidHand(i32), - #[fail(display = "invalid entity action type {}", _0)] + #[error("invalid entity action type {0}")] InvalidEntityAction(i32), - #[fail(display = "invalid player digging status {}", _0)] + #[error("invalid player digging status {0}")] InvalidPlayerDiggingStatus(i32), - #[fail(display = "invalid use entity value {}", _0)] + #[error("invalid use entity value {0}")] InvalidUseEntity(i32), - #[fail(display = "insufficient array length")] + #[error("insufficient array length")] InsufficientArrayLength, - #[fail(display = "invalid handshake state {}", _0)] + #[error("invalid handshake next state {0}")] InvalidHandshakeState(i32), } // SERVERBOUND -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct Handshake { pub protocol_version: u32, pub server_address: String, @@ -115,7 +364,7 @@ pub struct Handshake { } impl Packet for Handshake { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { self.protocol_version = buf.try_get_var_int()? as u32; self.server_address = buf.try_get_string()?; self.server_port = buf.try_get_u16()?; @@ -130,14 +379,29 @@ impl Packet for Handshake { Ok(()) } - fn write_to(&self, mut buf: &mut BytesMut) { - unimplemented!() + fn write_to(&self, buf: &mut BytesMut) { + buf.push_var_int(self.protocol_version as i32); + buf.push_string(&self.server_address); + buf.push_u16(self.server_port); + + let state_id = match self.next_state { + HandshakeState::Status => 1, + HandshakeState::Login => 2, + }; + buf.push_var_int(state_id); } fn ty(&self) -> PacketType { PacketType::Handshake } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::Handshake + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } @@ -155,12 +419,12 @@ impl Default for HandshakeState { } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct LoginStart { pub username: String, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct EncryptionResponse { pub secret_length: VarInt, pub secret: Vec<u8>, @@ -169,7 +433,7 @@ pub struct EncryptionResponse { } impl Packet for EncryptionResponse { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { self.secret_length = buf.try_get_var_int()?; let mut secret = vec![]; @@ -189,50 +453,60 @@ impl Packet for EncryptionResponse { Ok(()) } - fn write_to(&self, mut buf: &mut BytesMut) { - unimplemented!() + fn write_to(&self, buf: &mut BytesMut) { + buf.push_var_int(self.secret.len() as i32); + buf.put(self.secret.as_slice()); + buf.push_var_int(self.verify_token.len() as i32); + buf.put(self.verify_token.as_slice()); } fn ty(&self) -> PacketType { PacketType::EncryptionResponse } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::EncryptionResponse + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct Request {} -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct Ping { pub payload: u64, } // PLAY -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct TeleportConfirm { pub teleport_id: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct QueryBlockNBT { pub transaction_id: VarInt, pub location: BlockPosition, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ChatMessageServerbound { pub message: String, // Raw string, not a chat component } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ClientStatus { pub action_id: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ClientSettings { pub locale: String, pub view_distance: u8, @@ -242,92 +516,101 @@ pub struct ClientSettings { pub main_hand: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct TabCompleteServerbound { pub transaction_id: VarInt, pub text: String, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ConfirmTransactionServerbound { pub window_id: u8, pub action_number: u16, pub accepted: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EnchantItem { pub window_id: u8, pub enchantment: u8, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ClickWindow { pub window_id: u8, - pub slot: u16, + pub slot: i16, pub button: u8, pub action_number: i16, pub mode: VarInt, pub clicked_item: Slot, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct CloseWindowServerbound { pub window_id: u8, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct PluginMessageServerbound { pub channel: String, pub data: Vec<u8>, } impl Packet for PluginMessageServerbound { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { self.channel = buf.try_get_string()?; let mut data = Vec::with_capacity(buf.remaining()); buf.read(&mut data) - .map_err(|_| Error::InsufficientArrayLength); + .map_err(|_| Error::InsufficientArrayLength)?; self.data = data; Ok(()) } fn write_to(&self, buf: &mut BytesMut) { - unimplemented!() + buf.push_string(&self.channel); + + buf.put(self.data.as_slice()); } fn ty(&self) -> PacketType { PacketType::PluginMessageServerbound } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::PluginMessageServerbound + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EditBook { pub new_book: Slot, pub is_signing: bool, pub hand: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct QueryEntityNBT { pub transaction_id: VarInt, pub entity_id: VarInt, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct UseEntity { pub target: VarInt, pub ty: UseEntityType, } impl Packet for UseEntity { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { self.target = buf.try_get_var_int()?; let ty_id = buf.try_get_var_int()?; @@ -348,19 +631,40 @@ impl Packet for UseEntity { } fn write_to(&self, buf: &mut BytesMut) { - unimplemented!() + buf.push_var_int(self.target); + + let ty_id = match self.ty { + UseEntityType::Interact => 0, + UseEntityType::Attack => 1, + UseEntityType::InteractAt(_, _, _, _) => 2, + }; + buf.push_var_int(ty_id); + + if let UseEntityType::InteractAt(x, y, z, hand) = self.ty { + buf.push_f32(x); + buf.push_f32(y); + buf.push_f32(z); + buf.push_var_int(hand); + } } fn ty(&self) -> PacketType { PacketType::UseEntity } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::UseEntity + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(AsAny, new, Clone)] +#[derive(AsAny, Clone)] pub enum UseEntityType { Interact, Attack, @@ -373,17 +677,17 @@ impl Default for UseEntityType { } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct KeepAliveServerbound { pub id: i64, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct Player { pub on_ground: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct PlayerPosition { pub x: f64, pub feet_y: f64, @@ -391,7 +695,7 @@ pub struct PlayerPosition { pub on_ground: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct PlayerPositionAndLookServerbound { pub x: f64, pub feet_y: f64, @@ -401,14 +705,14 @@ pub struct PlayerPositionAndLookServerbound { pub on_ground: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct PlayerLook { pub yaw: f32, pub pitch: f32, pub on_ground: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct VehicleMoveServerbound { pub x: f64, pub y: f64, @@ -417,32 +721,32 @@ pub struct VehicleMoveServerbound { pub pitch: f32, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SteerBoat { pub left_paddle_turning: bool, pub right_paddle_turning: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct PickItem { pub slot_to_use: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct CraftRecipeRequest { pub window_id: i8, pub recipe: String, pub make_all: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct PlayerAbilitiesServerbound { pub flags: u8, pub flying_speed: f32, pub walking_speed: f32, } -#[derive(AsAny, new, Clone, Default)] +#[derive(AsAny, Clone, Default)] pub struct PlayerDigging { pub status: PlayerDiggingStatus, pub location: BlockPosition, @@ -450,7 +754,7 @@ pub struct PlayerDigging { } impl Packet for PlayerDigging { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { self.status = { let id = buf.try_get_var_int()?; match id { @@ -472,13 +776,23 @@ impl Packet for PlayerDigging { } fn write_to(&self, buf: &mut BytesMut) { - unimplemented!() + let id = self.status as i32; + buf.push_var_int(id); + buf.push_position(&self.location); + buf.push_i8(self.face); } fn ty(&self) -> PacketType { PacketType::PlayerDigging } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::PlayerDigging + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } @@ -502,7 +816,7 @@ impl Default for PlayerDiggingStatus { } } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct EntityAction { pub entity_id: VarInt, pub action_id: EntityActionType, @@ -510,7 +824,7 @@ pub struct EntityAction { } impl Packet for EntityAction { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { self.entity_id = buf.try_get_var_int()?; let action_id = buf.try_get_var_int()?; self.action_id = @@ -521,13 +835,23 @@ impl Packet for EntityAction { } fn write_to(&self, buf: &mut BytesMut) { - unimplemented!() + buf.push_var_int(self.entity_id); + let action_id = self.action_id.to_i32().unwrap(); + buf.push_var_int(action_id); + buf.push_var_int(self.jump_boost); } fn ty(&self) -> PacketType { PacketType::EntityAction } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::EntityAction + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } @@ -552,52 +876,52 @@ impl Default for EntityActionType { } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SteerVehicle { pub sideways: f32, pub forward: f32, pub flags: u8, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct RecipeBookData { pub ty: VarInt, // TODO } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct NameItem { pub item_name: String, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ResourcePackStatus { pub result: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct AdvancementTab { pub action: VarInt, pub tab_id: String, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SelectTrade { pub selected_slot: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SetBeaconEffect { pub primary_effect: VarInt, pub secondary_effect: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct HeldItemChangeServerbound { pub slot: i16, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct UpdateCommandBlock { pub location: BlockPosition, pub command: String, @@ -605,21 +929,21 @@ pub struct UpdateCommandBlock { pub flags: u8, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct UpdateCommandBlockMinecart { pub entity_id: VarInt, pub command: String, pub track_output: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct CreativeInventoryAction { pub slot: i16, pub clicked_item: Slot, } #[allow(clippy::too_many_arguments)] -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct UpdateStructureBlock { pub location: BlockPosition, pub action: VarInt, @@ -639,7 +963,7 @@ pub struct UpdateStructureBlock { pub flags: u8, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct UpdateSign { pub location: BlockPosition, pub line_1: String, @@ -648,13 +972,13 @@ pub struct UpdateSign { pub line_4: String, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct AnimationServerbound { pub hand: Hand, } impl Packet for AnimationServerbound { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { let hand_id = buf.try_get_var_int()?; self.hand = match Hand::from_i32(hand_id) { Some(hand) => hand, @@ -665,24 +989,31 @@ impl Packet for AnimationServerbound { } fn write_to(&self, buf: &mut BytesMut) { - unimplemented!() + buf.push_var_int(self.hand.to_i32().unwrap()); } fn ty(&self) -> PacketType { PacketType::AnimationServerbound } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::AnimationServerbound + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct Spectate { pub target_player: Uuid, } -#[derive(Debug, Clone, Copy, FromPrimitive)] +#[derive(Debug, Clone, Copy, FromPrimitive, ToPrimitive, PartialEq)] pub enum Face { Bottom, Top, @@ -705,13 +1036,59 @@ impl Face { } } +impl Face { + pub fn face(self) -> BlockFace { + match self { + Face::Bottom => BlockFace::Ceiling, + Face::Top => BlockFace::Floor, + Face::North => BlockFace::Wall, + Face::South => BlockFace::Wall, + Face::West => BlockFace::Wall, + Face::East => BlockFace::Wall, + } + } + + pub fn facing_cardinal(self) -> FacingCardinal { + match self { + Face::North => FacingCardinal::North, + Face::South => FacingCardinal::South, + Face::West => FacingCardinal::West, + Face::East => FacingCardinal::East, + Face::Top => panic!("Face::Top cannot be converted to FacingCardinal"), + Face::Bottom => panic!("Face::Bottom cannot be converted to FacingCardinal"), + } + } + + pub fn facing_cardinal_and_down(self) -> FacingCardinalAndDown { + match self { + Face::North => FacingCardinalAndDown::North, + Face::South => FacingCardinalAndDown::South, + Face::West => FacingCardinalAndDown::West, + Face::East => FacingCardinalAndDown::East, + Face::Bottom => FacingCardinalAndDown::Down, + Face::Top => panic!("Face::Top cannot be converted to FacingCardinalAndDown"), + } + } + + pub fn facing_cubic(self) -> FacingCubic { + match self { + Face::North => FacingCubic::North, + Face::South => FacingCubic::South, + Face::West => FacingCubic::West, + Face::East => FacingCubic::East, + Face::Top => FacingCubic::Up, + Face::Bottom => FacingCubic::Down, + } + } +} + impl Default for Face { fn default() -> Self { Face::Bottom } } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct PlayerBlockPlacement { pub location: BlockPosition, pub face: Face, @@ -722,7 +1099,7 @@ pub struct PlayerBlockPlacement { } impl Packet for PlayerBlockPlacement { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { self.location = buf.try_get_position()?; let face_id = buf.try_get_var_int()?; self.face = Face::from_i32(face_id).ok_or(Error::InvalidFace(face_id))?; @@ -734,30 +1111,42 @@ impl Packet for PlayerBlockPlacement { } fn write_to(&self, buf: &mut BytesMut) { - unimplemented!() + buf.push_position(&self.location); + buf.push_var_int(self.face.to_i32().unwrap()); + buf.push_var_int(self.hand); + buf.push_f32(self.cursor_position_x); + buf.push_f32(self.cursor_position_y); + buf.push_f32(self.cursor_position_z); } fn ty(&self) -> PacketType { PacketType::PlayerBlockPlacement } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::PlayerBlockPlacement + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct UseItem { pub hand: VarInt, } // CLIENTBOUND -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct DisconnectLogin { pub reason: String, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct EncryptionRequest { pub server_id: String, pub public_key: Vec<u8>, @@ -765,11 +1154,23 @@ pub struct EncryptionRequest { } impl Packet for EncryptionRequest { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - unimplemented!() + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + self.server_id = buf.try_get_string()?; + + let pubkey_len = buf.try_get_var_int()?; + for _ in 0..pubkey_len { + self.public_key.push(buf.try_get_u8()?); + } + + let token_len = buf.try_get_var_int()?; + for _ in 0..token_len { + self.verify_token.push(buf.try_get_u8()?); + } + + Ok(()) } - fn write_to(&self, mut buf: &mut BytesMut) { + fn write_to(&self, buf: &mut BytesMut) { buf.push_string(self.server_id.as_str()); buf.push_var_int(self.public_key.len() as i32); @@ -783,35 +1184,42 @@ impl Packet for EncryptionRequest { PacketType::EncryptionRequest } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::EncryptionRequest + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct LoginSuccess { pub uuid: String, pub username: String, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SetCompression { pub threshold: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct Response { pub json_response: String, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct Pong { pub payload: u64, } // PLAY #[allow(clippy::too_many_arguments)] -#[derive(Default, AsAny, new, Packet, Clone, Debug)] +#[derive(Default, AsAny, Packet, Clone, Debug)] pub struct SpawnObject { pub entity_id: VarInt, pub object_uuid: Uuid, @@ -827,7 +1235,7 @@ pub struct SpawnObject { pub velocity_z: i16, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SpawnExperienceOrb { pub entity_id: VarInt, pub x: f64, @@ -836,7 +1244,7 @@ pub struct SpawnExperienceOrb { pub count: i16, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SpawnGlobalEntity { pub entity_id: VarInt, pub ty: u8, @@ -846,7 +1254,7 @@ pub struct SpawnGlobalEntity { } #[allow(clippy::too_many_arguments)] -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SpawnMob { pub entity_id: VarInt, pub entity_uuid: Uuid, @@ -863,7 +1271,7 @@ pub struct SpawnMob { pub meta: EntityMetadata, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SpawnPainting { pub entity_id: VarInt, pub entity_uuid: Uuid, @@ -873,7 +1281,7 @@ pub struct SpawnPainting { } #[allow(clippy::too_many_arguments)] -#[derive(AsAny, new, Clone)] +#[derive(AsAny, Clone, Default, Packet)] pub struct SpawnPlayer { pub entity_id: VarInt, pub player_uuid: Uuid, @@ -885,41 +1293,18 @@ pub struct SpawnPlayer { pub metadata: EntityMetadata, } -impl Packet for SpawnPlayer { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - unimplemented!() - } - - fn write_to(&self, buf: &mut BytesMut) { - buf.push_var_int(self.entity_id); - buf.push_uuid(&self.player_uuid); - buf.push_f64(self.x); - buf.push_f64(self.y); - buf.push_f64(self.z); - buf.push_u8(self.yaw); - buf.push_u8(self.pitch); - - buf.push_metadata(&self.metadata); - } - - fn ty(&self) -> PacketType { - PacketType::SpawnPlayer - } - - fn box_clone(&self) -> Box<dyn Packet> { - box_clone_impl!(self); - } -} - -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct AnimationClientbound { pub entity_id: VarInt, pub animation: ClientboundAnimation, } impl Packet for AnimationClientbound { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - unimplemented!() + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + self.entity_id = buf.try_get_var_int()?; + self.animation = + ClientboundAnimation::from_u8(buf.try_get_u8()?).ok_or(Error::InvalidUseEntity(0))?; + Ok(()) } fn write_to(&self, buf: &mut BytesMut) { @@ -931,20 +1316,38 @@ impl Packet for AnimationClientbound { PacketType::AnimationClientbound } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::AnimationClientbound + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct Statistics { pub statistics: Vec<(VarInt, VarInt)>, pub value: VarInt, } impl Packet for Statistics { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - unimplemented!() + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + let num_statistics = buf.try_get_var_int()?; + + if num_statistics > 255 { + return Err(Error::InsufficientArrayLength.into()); + } + + for _ in 0..num_statistics { + self.statistics + .push((buf.try_get_var_int()?, buf.try_get_var_int()?)); + } + self.value = buf.try_get_var_int()?; + Ok(()) } fn write_to(&self, buf: &mut BytesMut) { @@ -960,26 +1363,43 @@ impl Packet for Statistics { PacketType::Statistics } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::Statistics + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct BlockBreakAnimation { pub entity_id: VarInt, pub location: BlockPosition, pub destroy_stage: i8, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(AsAny, Packet, Clone)] pub struct UpdateBlockEntity { pub location: BlockPosition, pub action: u8, - // TODO pub data: NbtTag + pub data: Blob, } -#[derive(Default, AsAny, new, Packet, Clone)] +impl Default for UpdateBlockEntity { + fn default() -> Self { + Self { + location: BlockPosition::default(), + action: 0, + data: Blob::new(), + } + } +} + +#[derive(Default, AsAny, Packet, Clone)] pub struct BlockAction { pub location: BlockPosition, pub action_id: u8, @@ -987,20 +1407,20 @@ pub struct BlockAction { pub block_type: VarInt, // NOTE: block type ID, not the block state ID } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct BlockChange { pub location: BlockPosition, pub block_id: VarInt, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct BossBar { pub uuid: Uuid, pub action: BossBarAction, } impl Packet for BossBar { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, _buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { unimplemented!() } @@ -1037,6 +1457,13 @@ impl Packet for BossBar { PacketType::BossBar } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::BossBar + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } @@ -1103,12 +1530,12 @@ impl Default for BossBarDivision { } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ServerDifficulty { pub difficulty: u8, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ChatMessageClientbound { pub json_data: String, pub position: u8, @@ -1118,31 +1545,81 @@ pub struct ChatMessageClientbound { // TODO TabCompleteClientbound // TODO DeclareCommands -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ConfirmTransactionClientbound { pub window_id: i8, pub action_number: i16, pub accepted: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Clone)] pub struct OpenWindow { pub window_id: u8, pub window_type: String, pub window_title: String, // Chat pub number_of_slots: u8, - pub entity_id: i32, + pub entity_id: Option<i32>, +} + +impl Packet for OpenWindow { + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + self.window_id = buf.try_get_u8()?; + self.window_type = buf.try_get_string()?; + self.window_title = buf.try_get_string()?; + self.number_of_slots = buf.try_get_u8()?; + + self.entity_id = if self.window_type == "EntityHorse" { + Some(buf.try_get_i32()?) + } else { + None + }; + + Ok(()) + } + + fn write_to(&self, buf: &mut BytesMut) { + buf.push_u8(self.window_id); + buf.push_string(&self.window_type); + buf.push_string(&self.window_title); + buf.push_u8(self.number_of_slots); + + if self.window_type == "EntityHorse" { + buf.push_i32(self.entity_id.unwrap()); + } + } + + fn ty(&self) -> PacketType { + PacketType::OpenWindow + } + + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::OpenWindow + } + + fn box_clone(&self) -> Box<dyn Packet> { + box_clone_impl!(self); + } } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct WindowItems { pub window_id: u8, pub slots: Vec<Slot>, } impl Packet for WindowItems { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - unimplemented!() + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + self.window_id = buf.try_get_u8()?; + let num_slots = buf.try_get_i16()?; + + for _ in 0..num_slots { + self.slots.push(buf.try_get_slot()?); + } + + Ok(()) } fn write_to(&self, buf: &mut BytesMut) { @@ -1150,7 +1627,7 @@ impl Packet for WindowItems { buf.push_i16(self.slots.len() as i16); for slot in &self.slots { - buf.push_slot(slot); + buf.push_slot(*slot); } } @@ -1158,40 +1635,51 @@ impl Packet for WindowItems { PacketType::WindowItems } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::WindowItems + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct WindowProperty { pub window_id: u8, pub property: i16, pub value: i16, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SetSlot { pub window_id: i8, pub slot: i16, pub slot_data: Slot, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SetCooldown { pub item_id: VarInt, pub cooldown_ticks: VarInt, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct PluginMessageClientbound { pub channel: String, pub data: Vec<u8>, } impl Packet for PluginMessageClientbound { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - unimplemented!() + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + self.channel = buf.try_get_string()?; + + self.data.extend_from_slice(*buf.get_ref()); + + Ok(()) } fn write_to(&self, buf: &mut BytesMut) { @@ -1203,12 +1691,19 @@ impl Packet for PluginMessageClientbound { PacketType::PluginMessageClientbound } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::PluginMessageClientbound + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct NamedSoundEffect { pub sound_name: String, pub sound_category: VarInt, @@ -1219,25 +1714,39 @@ pub struct NamedSoundEffect { pub pitch: f32, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Clone, Copy)] +pub enum SoundCategory { + Master = 0, + Music = 1, + Records = 2, + Weather = 3, + Blocks = 4, + Hostile = 5, + Neutral = 6, + Players = 7, + Ambient = 8, + Voice = 9, +} + +#[derive(Default, AsAny, Packet, Clone)] pub struct DisconnectPlay { pub reason: String, // Chat } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EntityStatus { pub entity_id: i32, pub entity_status: i8, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct NBTQueryResponse { pub transaction_id: VarInt, // TODO pub nbt: NbtTag, } #[allow(clippy::too_many_arguments)] -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct Explosion { pub x: f32, pub y: f32, @@ -1250,7 +1759,7 @@ pub struct Explosion { } impl Packet for Explosion { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, _buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { unimplemented!() } @@ -1277,47 +1786,55 @@ impl Packet for Explosion { PacketType::Explosion } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::Explosion + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct UnloadChunk { pub chunk_x: i32, pub chunk_z: i32, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ChangeGameState { pub reason: u8, pub value: f32, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct KeepAliveClientbound { pub keep_alive_id: u64, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct ChunkData { - pub chunk: Chunk, + pub chunk: ChunkHandle, } impl Packet for ChunkData { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, _buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { unimplemented!() } fn write_to(&self, buf: &mut BytesMut) { - buf.push_i32(self.chunk.position().x); - buf.push_i32(self.chunk.position().z); + let chunk = self.chunk.read(); + buf.push_i32(chunk.position().x); + buf.push_i32(chunk.position().z); buf.push_bool(true); // Full chunk - assume true // Produce primary bit mask - let mut primary_mask = { + let primary_mask = { let mut r = 0; - for (i, section) in self.chunk.sections().iter().enumerate() { + for (i, section) in chunk.sections().iter().enumerate() { if section.is_some() { r |= 1 << i; } @@ -1330,15 +1847,15 @@ impl Packet for ChunkData { // TODO: approximate appropriate capacity let mut temp_buf = BytesMut::new(); - for section in self.chunk.sections() { + for section in chunk.sections() { if let Some(section) = section { temp_buf.push_u8(section.bits_per_block()); let palette = section.palette(); if let Some(palette) = palette { let mut palette_buf = BytesMut::with_capacity(palette.len() + 4); - for val in palette { - palette_buf.push_var_int(i32::from(*val)); + for block in palette { + palette_buf.push_var_int(i32::from(block.vanilla_id())); } temp_buf.push_var_int(palette.len() as i32); @@ -1371,7 +1888,7 @@ impl Packet for ChunkData { // Biomes temp_buf.reserve(256 * 4); - self.chunk + chunk .biomes() .iter() .map(|biome| biome.protocol_id()) @@ -1380,19 +1897,26 @@ impl Packet for ChunkData { buf.push_var_int(temp_buf.len() as i32); buf.extend_from_slice(&temp_buf); - buf.push_var_int(0); // Block entities — TODO + buf.push_var_int(0); // Block entities are sent separately } fn ty(&self) -> PacketType { PacketType::ChunkData } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::ChunkData + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct Effect { pub effect_id: i32, pub location: BlockPosition, @@ -1400,21 +1924,76 @@ pub struct Effect { pub disable_relative_volume: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Clone)] pub struct Particle { - pub particle_id: i32, pub long_distance: bool, pub x: f32, pub y: f32, pub z: f32, pub offset_x: f32, + pub offset_y: f32, pub offset_z: f32, pub particle_data: f32, pub particle_count: i32, - // TODO data + pub data: ParticleData, +} + +impl Packet for Particle { + fn read_from(&mut self, _buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + unimplemented!() + } + + fn write_to(&self, buf: &mut BytesMut) { + buf.push_i32(self.data.ordinal() as i32); + buf.push_bool(self.long_distance); + buf.push_f32(self.x); + buf.push_f32(self.y); + buf.push_f32(self.z); + buf.push_f32(self.offset_x); + buf.push_f32(self.offset_y); + buf.push_f32(self.offset_z); + buf.push_f32(self.particle_data); + buf.push_i32(self.particle_count); + match self.data { + ParticleData::Block(id) => { + buf.push_var_int(id.vanilla_id() as i32); + } + ParticleData::Dust { + red, + green, + blue, + scale, + } => { + buf.push_f32(red); + buf.push_f32(green); + buf.push_f32(blue); + buf.push_f32(scale); + } + ParticleData::FallingDust(id) => { + buf.push_var_int(id.vanilla_id() as i32); + } + ParticleData::Item(stack) => buf.push_slot(stack), + _ => (), + } + } + + fn ty(&self) -> PacketType { + PacketType::Particle + } + + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::Particle + } + + fn box_clone(&self) -> Box<dyn Packet> { + box_clone_impl!(self) + } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone, Debug)] pub struct JoinGame { pub entity_id: i32, pub gamemode: u8, @@ -1428,7 +2007,7 @@ pub struct JoinGame { // TODO MapData // TODO EntityPacket -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EntityRelativeMove { pub entity_id: VarInt, pub delta_x: i16, @@ -1437,7 +2016,7 @@ pub struct EntityRelativeMove { pub on_ground: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EntityLookAndRelativeMove { pub entity_id: VarInt, pub delta_x: i16, @@ -1448,7 +2027,7 @@ pub struct EntityLookAndRelativeMove { pub on_ground: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EntityLook { pub entity_id: VarInt, pub yaw: u8, @@ -1456,7 +2035,7 @@ pub struct EntityLook { pub on_ground: bool, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct VehicleMoveClientbound { pub x: f64, pub y: f64, @@ -1465,31 +2044,31 @@ pub struct VehicleMoveClientbound { pub pitch: f32, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct OpenSignEditor { pub location: BlockPosition, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct CraftRecipeResponse { pub window_id: i8, pub recipe: String, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct PlayerAbilitiesClientbound { flags: u8, flying_speed: f32, field_of_view_modifier: f32, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct CombatEvent { pub event: CombatEventType, } impl Packet for CombatEvent { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, _buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { unimplemented!() } @@ -1509,7 +2088,14 @@ impl Packet for CombatEvent { } fn ty(&self) -> PacketType { - unimplemented!() + PacketType::CombatEvent + } + + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::CombatEvent } fn box_clone(&self) -> Box<dyn Packet> { @@ -1517,7 +2103,7 @@ impl Packet for CombatEvent { } } -#[derive(new, Clone)] +#[derive(Clone)] pub enum CombatEventType { EnterCombat, EndCombat(VarInt, i32), @@ -1530,15 +2116,58 @@ impl Default for CombatEventType { } } -#[derive(AsAny, new, Clone)] +#[derive(AsAny, Clone, Default)] pub struct PlayerInfo { - action: PlayerInfoAction, - uuid: Uuid, + pub action: PlayerInfoAction, + pub uuid: Uuid, } impl Packet for PlayerInfo { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - unimplemented!() + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + let id = buf.try_get_var_int()?; + let _ = buf.try_get_var_int()?; + self.uuid = buf.try_get_uuid()?; + + self.action = match id { + 0 => { + let name = buf.try_get_string()?; + let num_props = buf.try_get_var_int()?; + + let mut props = vec![]; + for _ in 0..num_props { + let s0 = buf.try_get_string()?; + let s1 = buf.try_get_string()?; + let s2 = if buf.try_get_bool()? { + buf.try_get_string()? + } else { + String::default() + }; + props.push((s0, s1, s2)); + } + + let gamemode = Gamemode::from_id(buf.try_get_var_int()? as u8); + let ping = buf.try_get_var_int()?; + let display_name = if buf.try_get_bool()? { + buf.try_get_string()? + } else { + String::default() + }; + + PlayerInfoAction::AddPlayer(name, props, gamemode, ping, display_name) + } + 1 => PlayerInfoAction::UpdateGamemode(Gamemode::from_id(buf.try_get_u8()?)), + 2 => PlayerInfoAction::UpdateLatency(buf.try_get_var_int()?), + 3 => { + if buf.try_get_bool()? { + PlayerInfoAction::UpdateDisplayName(buf.try_get_string()?) + } else { + PlayerInfoAction::UpdateDisplayName(String::default()) + } + } + _ => PlayerInfoAction::RemovePlayer, + }; + + Ok(()) } fn write_to(&self, buf: &mut BytesMut) { @@ -1558,13 +2187,13 @@ impl Packet for PlayerInfo { buf.push_string(&prop.2); } - buf.push_var_int(i32::from(gamemode.get_id())); + buf.push_var_int(i32::from(gamemode.id())); buf.push_var_int(*ping); buf.push_bool(true); buf.push_string(display_name); } PlayerInfoAction::UpdateGamemode(gamemode) => { - buf.push_var_int(i32::from(gamemode.get_id())); + buf.push_var_int(i32::from(gamemode.id())); } PlayerInfoAction::UpdateLatency(ping) => { buf.push_var_int(*ping); @@ -1581,12 +2210,19 @@ impl Packet for PlayerInfo { PacketType::PlayerInfo } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::PlayerInfo + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum PlayerInfoAction { AddPlayer( String, @@ -1613,9 +2249,15 @@ impl PlayerInfoAction { } } +impl Default for PlayerInfoAction { + fn default() -> Self { + PlayerInfoAction::RemovePlayer + } +} + // TODO Face Player -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct PlayerPositionAndLookClientbound { pub x: f64, pub y: f64, @@ -1626,7 +2268,7 @@ pub struct PlayerPositionAndLookClientbound { pub teleport_id: VarInt, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct UseBed { pub entity_id: VarInt, pub location: BlockPosition, @@ -1634,13 +2276,13 @@ pub struct UseBed { // TODO Unlock Recipes -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone)] pub struct DestroyEntities { pub entity_ids: Vec<VarInt>, } impl Packet for DestroyEntities { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { + fn read_from(&mut self, _buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { unimplemented!() } @@ -1656,24 +2298,31 @@ impl Packet for DestroyEntities { PacketType::DestroyEntities } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::DestroyEntities + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct RemoveEntityEffect { pub entity_id: VarInt, pub effect_id: i8, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct ResourcePackSend { pub url: String, pub hash: String, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct Respawn { pub dimension: i32, pub difficulty: u8, @@ -1681,21 +2330,23 @@ pub struct Respawn { pub level_type: String, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EntityHeadLook { pub entity_id: VarInt, pub head_yaw: u8, } -#[derive(Default, AsAny, new, Clone)] +#[derive(Default, AsAny, Clone, Debug)] pub struct PacketEntityMetadata { pub entity_id: VarInt, pub metadata: EntityMetadata, } impl Packet for PacketEntityMetadata { - fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> Result<(), failure::Error> { - unimplemented!() + fn read_from(&mut self, buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + self.entity_id = buf.try_get_var_int()?; + self.metadata = buf.try_get_metadata()?; + Ok(()) } fn write_to(&self, buf: &mut BytesMut) { @@ -1707,12 +2358,19 @@ impl Packet for PacketEntityMetadata { PacketType::EntityMetadata } + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::EntityMetadata + } + fn box_clone(&self) -> Box<dyn Packet> { box_clone_impl!(self); } } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EntityVelocity { pub entity_id: VarInt, pub velocity_x: i16, @@ -1720,17 +2378,29 @@ pub struct EntityVelocity { pub velocity_z: i16, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct EntityEquipment { pub entity_id: VarInt, pub slot: VarInt, pub item: Slot, } +#[derive(Default, AsAny, Packet, Clone)] +pub struct HeldItemChangeClientbound { + pub slot: i8, +} + +#[derive(Default, AsAny, Packet, Clone)] +pub struct UpdateHealth { + pub health: f32, + pub food: VarInt, + pub saturation: f32, +} + // TODO Select Advancement Tab // TODO World Border -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct SpawnPosition { pub location: BlockPosition, } @@ -1741,9 +2411,61 @@ pub struct TimeUpdate { pub time_of_day: i64, } -#[derive(Default, AsAny, new, Packet, Clone)] +#[derive(Default, AsAny, Packet, Clone)] pub struct CollectItem { pub collected: VarInt, pub collector: VarInt, pub count: VarInt, } + +#[derive(Default, AsAny, Packet, Clone)] +pub struct EntityTeleport { + pub entity_id: VarInt, + pub x: f64, + pub y: f64, + pub z: f64, + pub yaw: u8, + pub pitch: u8, + pub on_ground: bool, +} + +#[derive(Default, AsAny, Clone)] +pub struct Tags { + pub block_tags: Vec<(String, Vec<VarInt>)>, + pub item_tags: Vec<(String, Vec<VarInt>)>, + pub fluid_tags: Vec<(String, Vec<VarInt>)>, +} + +impl Packet for Tags { + fn read_from(&mut self, _buf: &mut Cursor<&[u8]>) -> anyhow::Result<()> { + unimplemented!() + } + + fn write_to(&self, buf: &mut BytesMut) { + for field in [&self.block_tags, &self.item_tags, &self.fluid_tags].iter_mut() { + buf.push_var_int(field.len() as i32); + for (identifier, entries) in field.iter() { + buf.push_string(identifier.as_str()); + buf.push_var_int(entries.len().try_into().unwrap()); + for entry in entries { + buf.push_var_int(*entry); + } + } + } + } + + fn ty(&self) -> PacketType { + PacketType::Tags + } + + fn ty_sized() -> PacketType + where + Self: Sized, + { + PacketType::Tags + } + + fn box_clone(&self) -> Box<dyn Packet> { + box_clone_impl!(self); + } +} diff --git a/feather/old/core/src/lib.rs b/feather/old/core/src/lib.rs new file mode 100644 index 000000000..b057f03f6 --- /dev/null +++ b/feather/old/core/src/lib.rs @@ -0,0 +1,16 @@ +pub extern crate feather_anvil as anvil; +pub extern crate feather_biomes as biomes; +pub extern crate feather_blocks as blocks; +pub extern crate feather_chunk as chunk; +pub extern crate feather_chunk_map as chunk_map; +pub extern crate feather_entity_metadata as entitymeta; +pub extern crate feather_game_rules as game_rules; +pub extern crate feather_inventory as inventory; +pub extern crate feather_item_block as item_block; +pub extern crate feather_items as items; +pub extern crate feather_loot as loot; +pub extern crate feather_misc as misc; +pub extern crate feather_text as text; +pub extern crate feather_util as util; + +pub use util::position; diff --git a/feather/old/core/util/Cargo.toml b/feather/old/core/util/Cargo.toml new file mode 100644 index 000000000..1bbc5b866 --- /dev/null +++ b/feather/old/core/util/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "feather-util" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +vek = "0.10" +nalgebra-glm = "0.6" +num-traits = "0.2" +num-derive = "0.3" +hash32 = "0.1" +hash32-derive = "0.1" diff --git a/core/src/lib.rs b/feather/old/core/util/src/lib.rs similarity index 65% rename from core/src/lib.rs rename to feather/old/core/util/src/lib.rs index 52a3d6ee6..86a8d99b4 100644 --- a/core/src/lib.rs +++ b/feather/old/core/util/src/lib.rs @@ -1,50 +1,18 @@ -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate derive_new; -#[macro_use] -extern crate log; -#[macro_use] -extern crate serde; -#[macro_use] -extern crate feather_codegen; -#[macro_use] -extern crate num_derive; -#[macro_use] -extern crate smallvec; -#[macro_use] -extern crate hash32_derive; -#[macro_use] -extern crate strum_macros; -#[macro_use] -extern crate failure; +use num_derive::{FromPrimitive, ToPrimitive}; +use serde::{Deserialize, Serialize}; +use std::fmt; extern crate nalgebra_glm as glm; +mod math_types; #[macro_use] -pub mod world; -mod biomes; -pub mod bytes_ext; -pub mod entitymeta; -pub mod inventory; -pub mod network; -pub mod prelude; -mod save; - -pub use biomes::Biome; -pub use entitymeta::EntityMetadata; -pub use feather_items as item; -pub use inventory::{ItemStack, Slot}; -pub use item::{Item, ItemExt}; -pub use network::packet::{implementation as packet, Packet, PacketType}; -pub use save::{entity, level, player_data, region}; -pub use world::{ - block::{self, Block, BlockExt}, - chunk::{Chunk, ChunkSection}, - BlockPosition, ChunkPosition, Position, -}; +mod positions; + +pub use math_types::*; +pub use positions::{BlockPosition, ChunkPosition, Position}; #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[serde(rename_all = "lowercase")] pub enum Gamemode { Survival, Creative, @@ -53,7 +21,7 @@ pub enum Gamemode { } impl Gamemode { - pub fn get_id(self) -> u8 { + pub fn id(self) -> u8 { match self { Gamemode::Survival => 0, Gamemode::Creative => 1, @@ -83,6 +51,21 @@ impl Gamemode { } } +impl fmt::Display for Gamemode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Gamemode::Survival => "Survival", + Gamemode::Creative => "Creative", + Gamemode::Adventure => "Adventure", + Gamemode::Spectator => "Spectator", + } + ) + } +} + #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Difficulty { Peaceful, @@ -92,7 +75,7 @@ pub enum Difficulty { } impl Difficulty { - pub fn get_id(self) -> u8 { + pub fn id(self) -> u8 { match self { Difficulty::Peaceful => 0, Difficulty::Easy => 1, @@ -110,7 +93,7 @@ pub enum Dimension { } impl Dimension { - pub fn get_id(self) -> i32 { + pub fn id(self) -> i32 { match self { Dimension::Nether => -1, Dimension::Overwold => 0, @@ -155,3 +138,28 @@ impl Default for Hand { Hand::Main } } + +#[derive( + Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive, +)] +pub enum Direction { + Down, + Up, + North, + South, + West, + East, +} + +impl Direction { + pub fn id(self) -> i32 { + match self { + Direction::Down => 0, + Direction::Up => 1, + Direction::North => 2, + Direction::South => 3, + Direction::West => 4, + Direction::East => 5, + } + } +} diff --git a/feather/old/core/util/src/math_types.rs b/feather/old/core/util/src/math_types.rs new file mode 100644 index 000000000..8fbc87f49 --- /dev/null +++ b/feather/old/core/util/src/math_types.rs @@ -0,0 +1,31 @@ +pub type Vec2f = vek::Vec2<f32>; +pub type Vec3f = vek::Vec3<f32>; +pub type Vec4f = vek::Vec4<f32>; + +pub type Vec2d = vek::Vec2<f64>; +pub type Vec3d = vek::Vec3<f64>; +pub type Vec4d = vek::Vec4<f64>; + +pub type Vec2i = vek::Vec2<i32>; +pub type Vec3i = vek::Vec3<i32>; +pub type Vec4i = vek::Vec4<i32>; + +pub type Mat2f = vek::mat::column_major::Mat2<f32>; +pub type Mat3f = vek::mat::column_major::Mat3<f32>; +pub type Mat4f = vek::mat::column_major::Mat4<f32>; + +pub type Mat2d = vek::mat::column_major::Mat2<f64>; +pub type Mat3d = vek::mat::column_major::Mat3<f64>; +pub type Mat4d = vek::mat::column_major::Mat4<f64>; + +pub fn vec2<T>(x: T, y: T) -> vek::Vec2<T> { + vek::Vec2::new(x, y) +} + +pub fn vec3<T>(x: T, y: T, z: T) -> vek::Vec3<T> { + vek::Vec3::new(x, y, z) +} + +pub fn vek4<T>(x: T, y: T, z: T, w: T) -> vek::Vec4<T> { + vek::Vec4::new(x, y, z, w) +} diff --git a/feather/old/core/util/src/positions.rs b/feather/old/core/util/src/positions.rs new file mode 100644 index 000000000..c40373b44 --- /dev/null +++ b/feather/old/core/util/src/positions.rs @@ -0,0 +1,351 @@ +use crate::{vec3, Vec3d, Vec3i}; +use hash32_derive::Hash32; +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::ops::{Add, Sub}; + +#[macro_export] +macro_rules! position { + ($x:expr, $y:expr, $z:expr, $pitch:expr, $yaw:expr, $on_ground:expr $(,)?) => { + $crate::Position { + x: $x, + y: $y, + z: $z, + pitch: $pitch, + yaw: $yaw, + on_ground: $on_ground, + } + }; + ($x:expr, $y:expr, $z:expr, $pitch: expr, $yaw: expr $(,)?) => { + position!($x, $y, $z, $pitch, $yaw, true) + }; + ($x:expr, $y:expr, $z:expr $(,)?) => { + position!($x, $y, $z, 0.0, 0.0) + }; + ($x:expr, $y:expr, $z:expr, $on_ground: expr $(,)?) => { + position!($x, $y, $z, 0.0, 0.0, $on_ground) + }; +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Position { + pub x: f64, + pub y: f64, + pub z: f64, + pub pitch: f32, + pub yaw: f32, + pub on_ground: bool, +} + +impl Default for Position { + fn default() -> Self { + position!(0.0, 64.0, 0.0) + } +} + +impl Position { + pub fn distance_to(&self, other: Position) -> f64 { + self.distance_squared_to(other).sqrt() + } + + pub fn distance_squared_to(&self, other: Position) -> f64 { + square(self.x - other.x) + square(self.y - other.y) + square(self.z - other.z) + } + + /// Returns a unit vector representing + /// the direction of this position's pitch + /// and yaw. + pub fn direction(&self) -> Vec3d { + let rotation_x = f64::from(self.yaw.to_radians()); + let rotation_y = f64::from(self.pitch.to_radians()); + + let y = -rotation_y.sin(); + + let xz = rotation_y.cos(); + + let x = -xz * rotation_x.sin(); + let z = xz * rotation_x.cos(); + + vec3(x, y, z) + } + + pub fn chunk(self) -> ChunkPosition { + self.into() + } + + pub fn block(self) -> BlockPosition { + self.into() + } + + pub fn vec(&self) -> Vec3d { + (*self).into() + } +} + +impl Add<Vec3d> for Position { + type Output = Position; + + fn add(mut self, rhs: Vec3d) -> Self::Output { + self.x += rhs.x; + self.y += rhs.y; + self.z += rhs.z; + self + } +} + +impl Add<glm::DVec3> for Position { + type Output = Position; + + fn add(mut self, rhs: glm::DVec3) -> Self::Output { + self.x += rhs.x; + self.y += rhs.y; + self.z += rhs.z; + self + } +} + +impl Add<Position> for Position { + type Output = Position; + + fn add(mut self, rhs: Position) -> Self::Output { + self.x += rhs.x; + self.y += rhs.y; + self.z += rhs.z; + self.pitch += rhs.pitch; + self.yaw += rhs.yaw; + self + } +} + +impl Sub<Vec3d> for Position { + type Output = Position; + + fn sub(mut self, rhs: Vec3d) -> Self::Output { + self.x -= rhs.x; + self.y -= rhs.y; + self.z -= rhs.z; + self + } +} + +impl Sub<glm::DVec3> for Position { + type Output = Position; + + fn sub(mut self, rhs: glm::DVec3) -> Self::Output { + self.x -= rhs.x; + self.y -= rhs.y; + self.z -= rhs.z; + self + } +} + +impl Sub<Position> for Position { + type Output = Position; + + fn sub(mut self, rhs: Position) -> Self::Output { + self.x -= rhs.x; + self.y -= rhs.y; + self.z -= rhs.z; + self + } +} + +impl From<Position> for Vec3d { + fn from(pos: Position) -> Self { + vec3(pos.x, pos.y, pos.z) + } +} + +impl From<Position> for glm::DVec3 { + fn from(pos: Position) -> Self { + glm::vec3(pos.x, pos.y, pos.z) + } +} + +impl From<Vec3d> for Position { + fn from(vec: Vec3d) -> Self { + position!(vec.x, vec.y, vec.z) + } +} + +impl From<glm::DVec3> for Position { + fn from(vec: glm::DVec3) -> Self { + position!(vec.x, vec.y, vec.z) + } +} + +impl From<Position> for ChunkPosition { + fn from(pos: Position) -> Self { + Self { + x: (pos.x / 16.0).floor() as i32, + z: (pos.z / 16.0).floor() as i32, + } + } +} + +impl From<Position> for BlockPosition { + fn from(pos: Position) -> Self { + Self { + x: pos.x.floor() as i32, + y: pos.y.floor() as i32, + z: pos.z.floor() as i32, + } + } +} + +impl Display for Position { + fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { + write!(f, "({:.2}, {:.2}, {:.2})", self.x, self.y, self.z,) + } +} + +fn square(x: f64) -> f64 { + x * x +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] +pub struct ChunkPosition { + pub x: i32, + pub z: i32, +} + +impl ChunkPosition { + pub const fn new(x: i32, z: i32) -> Self { + Self { x, z } + } + + /// Computes the Manhattan distance from this chunk to another. + pub fn manhattan_distance_to(self, other: ChunkPosition) -> i32 { + (self.x - other.z).abs() + (self.z - other.z).abs() + } +} + +impl Display for ChunkPosition { + fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { + write!(f, "({}, {})", self.x, self.z) + } +} + +impl Add<ChunkPosition> for ChunkPosition { + type Output = ChunkPosition; + + fn add(self, rhs: ChunkPosition) -> Self::Output { + ChunkPosition { + x: self.x + rhs.x, + z: self.z + rhs.z, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Hash32)] +pub struct BlockPosition { + pub x: i32, + pub y: i32, + pub z: i32, +} + +impl BlockPosition { + pub const fn new(x: i32, y: i32, z: i32) -> Self { + Self { x, y, z } + } + + /// Returns the Manhattan distance from this position to another. + pub fn manhattan_distance(self, other: BlockPosition) -> i32 { + (self.x - other.x).abs() + (self.y - other.y).abs() + (self.z - other.z).abs() + } + + /// Converts this `BlockPosition` to a `Position`. + pub fn position(self) -> Position { + self.into() + } + + /// Converts into a `ChunkPosition`. + pub fn chunk(self) -> ChunkPosition { + self.into() + } + + pub fn up(self) -> BlockPosition { + Self { + x: self.x, + y: self.y + 1, + z: self.z, + } + } + + pub fn down(self) -> BlockPosition { + Self { + x: self.x, + y: self.y - 1, + z: self.z, + } + } +} + +impl Add<BlockPosition> for BlockPosition { + type Output = BlockPosition; + + fn add(mut self, rhs: BlockPosition) -> Self::Output { + self.x += rhs.x; + self.y += rhs.y; + self.z += rhs.z; + self + } +} + +impl Add<Vec3i> for BlockPosition { + type Output = Self; + + fn add(self, rhs: Vec3i) -> Self::Output { + self + BlockPosition::from(rhs) + } +} + +impl Sub<BlockPosition> for BlockPosition { + type Output = Self; + + fn sub(mut self, rhs: BlockPosition) -> Self::Output { + self.x -= rhs.x; + self.y -= rhs.y; + self.z -= rhs.z; + self + } +} + +impl Sub<Vec3i> for BlockPosition { + type Output = Self; + + fn sub(self, rhs: Vec3i) -> Self::Output { + self - BlockPosition::from(rhs) + } +} + +impl From<BlockPosition> for Vec3i { + fn from(pos: BlockPosition) -> Self { + vec3(pos.x, pos.y, pos.z) + } +} + +impl From<Vec3i> for BlockPosition { + fn from(vec: Vec3i) -> Self { + BlockPosition { + x: vec.x, + y: vec.y, + z: vec.z, + } + } +} + +impl From<BlockPosition> for Position { + fn from(pos: BlockPosition) -> Self { + position!(pos.x as f64 + 0.5, pos.y as f64 + 0.5, pos.z as f64 + 0.5) + } +} + +impl From<BlockPosition> for ChunkPosition { + fn from(pos: BlockPosition) -> Self { + Self { + x: pos.x >> 4, + z: pos.z >> 4, + } + } +} diff --git a/feather/old/data/Cargo.toml b/feather/old/data/Cargo.toml new file mode 100644 index 000000000..a28ca0dd1 --- /dev/null +++ b/feather/old/data/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "feather-data" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" +publish = false + +build = "build.rs" + +[dependencies] +feather-data-macro = { path = "macro" } + +[build-dependencies] +reqwest = { version = "0.10", features = ["blocking"] } +anyhow = "1.0" +zip = "0.5.8" \ No newline at end of file diff --git a/feather/old/data/build.rs b/feather/old/data/build.rs new file mode 100644 index 000000000..0c4853606 --- /dev/null +++ b/feather/old/data/build.rs @@ -0,0 +1,154 @@ +use anyhow::Context; +use std::env; +use std::fs; +use std::fs::File; +use std::io::{copy, Write}; +use std::path::Path; +use std::process::Command; +use zip::ZipArchive; + +fn main() { + match run() { + Ok(_) => (), + Err(e) => panic!("{:?}", e), + } +} + +fn run() -> anyhow::Result<()> { + let path = format!("{}/minecraft", env::var("OUT_DIR")?); + let path_1_15 = format!("{}/minecraft-1.15", env::var("OUT_DIR")?); + + download_version("https://launcher.mojang.com/v1/objects/3737db93722a9e39eeada7c27e7aca28b144ffa7/server.jar", &path, true).context("failed to download 1.13 data")?; + download_version("https://launcher.mojang.com/v1/objects/bb2b6b1aefcd70dfd1892149ac3a215f6c636b07/server.jar", &path_1_15, false).context("failed to download 1.15 data")?; + + clone_minecraft_data().context("failed to clone PrismarineJS/minecraft-data")?; + + println!( + "cargo:rerun-if-changed={}", + concat!(env!("CARGO_MANIFEST_DIR"), "/build.rs") + ); + Ok(()) +} + +fn download_version(url: &str, path: &str, do_generate: bool) -> anyhow::Result<()> { + let path = Path::new(&path); + let path_server = path.join("server.jar"); + + if data_exists(path).unwrap_or(false) { + println!("cargo:rerun-if-changed={}", &path.display()); + println!( + "cargo:rerun-if-changed={}", + concat!(env!("CARGO_MANIFEST_DIR"), "/build.rs") + ); + return Ok(()); + } + + let _ = fs::remove_dir_all(path); + fs::create_dir_all(path).context("failed to create target directory for downloaded data")?; + + download(url, &path_server).context("failed to download vanilla server JAR")?; + + println!( + "after download: {:?}", + std::fs::read_dir(path)?.collect::<Vec<_>>() + ); + + if do_generate { + generate(path).context("failed to generate vanilla server reports.")?; + } + + extract(path).context("failed to extract vanilla assets.")?; + println!( + "after extract: {:?}", + std::fs::read_dir(path)?.collect::<Vec<_>>() + ); + + Ok(()) +} + +fn data_exists(path: &Path) -> anyhow::Result<bool> { + Ok(File::open(path.join("server.jar")).is_ok() + && File::open(path.join("assets")).is_ok() + && File::open(path.join("data")).is_ok() + && File::open(path.join("generated")).is_ok()) +} + +fn download<P: AsRef<Path>>(url: &str, server: P) -> anyhow::Result<()> { + let mut response = reqwest::blocking::get(url)?; + let mut dest = File::create(server) + .context("failed to create destination file for server JAR download")?; + copy(&mut response, &mut dest)?; + dest.flush()?; + Ok(()) +} + +fn generate<P: AsRef<Path>>(working: P) -> anyhow::Result<()> { + let status = Command::new("java") + .current_dir(working.as_ref()) + .args(&["-cp", "server.jar", "net.minecraft.data.Main", "--reports"]) + .status()?; + if !status.success() { + anyhow::bail!( + "process to generate server reports was not successful (exit status {}, JAR path {})", + status, + working.as_ref().display(), + ) + } + Ok(()) +} + +fn extract<P: AsRef<Path>>(working: P) -> anyhow::Result<()> { + println!( + "{:?}", + std::fs::read_dir(working.as_ref())?.collect::<Vec<_>>() + ); + let server_jar = working.as_ref().join("server.jar"); + let mut archive = ZipArchive::new(std::fs::File::open(server_jar)?)?; + for i in 0..archive.len() { + let mut file = archive.by_index(i)?; + if !(file.name().starts_with("assets/") || file.name().starts_with("data/")) { + continue; + } + + let outpath_name = file.name().replace("..", "."); + let outpath = working.as_ref().join(outpath_name); + + if file.is_dir() { + println!("Directory \"{}\" was created", outpath.display()); + fs::create_dir_all(&outpath).unwrap(); + } else { + println!("Writing to \"{}\"", outpath.display(),); + if let Some(p) = outpath.parent() { + if !p.exists() { + fs::create_dir_all(&p).unwrap(); + } + } + let mut outfile = fs::File::create(&outpath).unwrap(); + std::io::copy(&mut file, &mut outfile).unwrap(); + } + } + + Ok(()) +} + +fn clone_minecraft_data() -> anyhow::Result<()> { + let path = format!("{}/minecraft-data", env::var("OUT_DIR")?); + if Path::new(&path).exists() { + // Already cloned - no need to do so again + return Ok(()); + } + + if !Command::new("git") + .arg("clone") + .arg("https://github.com/PrismarineJS/minecraft-data.git") + .arg(&path) + .status()? + .success() + { + Err(anyhow::anyhow!( + "failed to clone minecraft-data repository: please ensure git is installed" + )) + } else { + Ok(()) + } +} diff --git a/feather/old/data/lock b/feather/old/data/lock new file mode 100644 index 000000000..e69de29bb diff --git a/feather/old/data/macro/Cargo.toml b/feather/old/data/macro/Cargo.toml new file mode 100644 index 000000000..efa925691 --- /dev/null +++ b/feather/old/data/macro/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "feather-data-macro" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" +publish = false + +[lib] +proc-macro = true + +[dependencies] +quote = "= 1.0.1" +syn = "1.0" +proc-macro2 = "1.0" diff --git a/feather/old/data/macro/src/lib.rs b/feather/old/data/macro/src/lib.rs new file mode 100644 index 000000000..1fabecee4 --- /dev/null +++ b/feather/old/data/macro/src/lib.rs @@ -0,0 +1,117 @@ +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use std::env; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use syn::{parse_macro_input, Ident, LitStr}; + +#[proc_macro] +pub fn include_data(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input: LitStr = parse_macro_input!(input as LitStr); + let build_dir = env::var("OUT_DIR").unwrap(); + + let path = PathBuf::from(&build_dir).join(input.value()); + if !path.exists() { + panic!("Path \"{}\" does not exist.", path.display()); + } + let (dirs_files, _) = include_dirs_files(path); + + let tokens = quote! { + #[doc = "The path of downloaded feather-data files."] + pub const PATH: &str = #build_dir; + #dirs_files + }; + + tokens.into() +} + +fn include_dirs_files<P: AsRef<Path>>(path: P) -> (TokenStream, Vec<syn::Path>) { + let path = path.as_ref(); + let (files, dirs): (Vec<PathBuf>, Vec<PathBuf>) = path + .read_dir() + .expect("could not read dir.") + .map(|e| e.expect("Could not read entry.")) + .map(|e| e.path()) + .partition(|p| p.is_file()); + let (files_tokens, files_idents): (Vec<_>, Vec<_>) = files.iter().map(include_file).unzip(); + let (dirs_tokens, dirs_idents): (Vec<_>, Vec<_>) = dirs.iter().map(include_dir).unzip(); + let mut idents: Vec<syn::Path> = files_idents + .into_iter() + .map(|ident| { + let segments = std::iter::once(syn::PathSegment { + ident, + arguments: syn::PathArguments::None, + }) + .collect(); + syn::Path { + leading_colon: None, + segments, + } + }) + .collect(); + idents.extend(dirs_idents.into_iter().flatten()); + ( + quote! { + #(#files_tokens)* + #(#dirs_tokens)* + pub const ALL: &'static [&'static [u8]] = &[#(#idents,)*]; + }, + idents, + ) +} + +fn include_dir<P: AsRef<Path>>(path: P) -> (TokenStream, Vec<syn::Path>) { + let path = path.as_ref(); + let stem = path + .file_stem() + .and_then(OsStr::to_str) + .expect("Could not extract file stem."); + let name = format_ident!("{}", stem); + let (dirs_files, idents) = include_dirs_files(path); + let idents: Vec<syn::Path> = idents + .into_iter() + .map(|path| { + let segments = std::iter::once(syn::PathSegment { + ident: name.clone(), + arguments: syn::PathArguments::None, + }) + .chain(path.segments.into_iter()) + .collect(); + syn::Path { + leading_colon: None, + segments, + } + }) + .collect(); + ( + quote! { + pub mod #name { + #dirs_files + } + }, + idents, + ) +} + +fn include_file<P: AsRef<Path>>(path: P) -> (TokenStream, Ident) { + let path = path.as_ref(); + let stem = path + .file_stem() + .and_then(OsStr::to_str) + .expect("Could not extract file stem."); + let name = { + let stem = stem.to_uppercase(); + if stem.starts_with(char::is_numeric) { + format_ident!("_{}", stem) + } else { + format_ident!("{}", stem) + } + }; + let path = format!("{}", path.display()); + ( + quote! { + pub const #name: &'static [u8] = include_bytes!(#path); + }, + name, + ) +} diff --git a/feather/old/data/src/lib.rs b/feather/old/data/src/lib.rs new file mode 100644 index 000000000..8521c7874 --- /dev/null +++ b/feather/old/data/src/lib.rs @@ -0,0 +1,25 @@ +pub mod minecraft { + pub mod lang { + feather_data_macro::include_data!("minecraft/assets/minecraft/lang"); + } + pub mod advancements { + feather_data_macro::include_data!("minecraft/data/minecraft/advancements"); + } + pub mod loot_tables { + feather_data_macro::include_data!("minecraft/data/minecraft/loot_tables"); + } + pub mod recipes { + feather_data_macro::include_data!("minecraft/data/minecraft/recipes"); + } + pub mod structures { + feather_data_macro::include_data!("minecraft/data/minecraft/structures"); + } + pub mod tags { + feather_data_macro::include_data!("minecraft/data/minecraft/tags"); + } + feather_data_macro::include_data!("minecraft/generated/reports"); +} + +pub mod minecraft_data { + feather_data_macro::include_data!("minecraft-data/data/pc/1.13.2"); +} diff --git a/items/Cargo.toml b/feather/old/definitions/Cargo.toml similarity index 73% rename from items/Cargo.toml rename to feather/old/definitions/Cargo.toml index dc0a96b67..cf3b19e89 100644 --- a/items/Cargo.toml +++ b/feather/old/definitions/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "feather-items" -version = "0.5.0" +name = "feather-definitions" +version = "0.1.0" authors = ["caelunshun <caelunshun@gmail.com>"] edition = "2018" diff --git a/feather/old/definitions/README.md b/feather/old/definitions/README.md new file mode 100644 index 000000000..d0a75466f --- /dev/null +++ b/feather/old/definitions/README.md @@ -0,0 +1,4 @@ +`feather-definitions` provides a clean +way to define gameplay information, such +as block tags, item tags, and block/item associated +values. \ No newline at end of file diff --git a/feather/old/definitions/data/generated/block.ron b/feather/old/definitions/data/generated/block.ron new file mode 100644 index 000000000..7d8bc2b53 --- /dev/null +++ b/feather/old/definitions/data/generated/block.ron @@ -0,0 +1,5103 @@ +// This files is @generated +Multiple([ + + Enum( + name: "block_kind", + variants: [ + + "air", + "stone", + "granite", + "polished_granite", + "diorite", + "polished_diorite", + "andesite", + "polished_andesite", + "grass_block", + "dirt", + "coarse_dirt", + "podzol", + "cobblestone", + "oak_planks", + "spruce_planks", + "birch_planks", + "jungle_planks", + "acacia_planks", + "dark_oak_planks", + "oak_sapling", + "spruce_sapling", + "birch_sapling", + "jungle_sapling", + "acacia_sapling", + "dark_oak_sapling", + "bedrock", + "water", + "lava", + "sand", + "red_sand", + "gravel", + "gold_ore", + "iron_ore", + "coal_ore", + "oak_log", + "spruce_log", + "birch_log", + "jungle_log", + "acacia_log", + "dark_oak_log", + "stripped_spruce_log", + "stripped_birch_log", + "stripped_jungle_log", + "stripped_acacia_log", + "stripped_dark_oak_log", + "stripped_oak_log", + "oak_wood", + "spruce_wood", + "birch_wood", + "jungle_wood", + "acacia_wood", + "dark_oak_wood", + "stripped_oak_wood", + "stripped_spruce_wood", + "stripped_birch_wood", + "stripped_jungle_wood", + "stripped_acacia_wood", + "stripped_dark_oak_wood", + "oak_leaves", + "spruce_leaves", + "birch_leaves", + "jungle_leaves", + "acacia_leaves", + "dark_oak_leaves", + "sponge", + "wet_sponge", + "glass", + "lapis_ore", + "lapis_block", + "dispenser", + "sandstone", + "chiseled_sandstone", + "cut_sandstone", + "note_block", + "white_bed", + "orange_bed", + "magenta_bed", + "light_blue_bed", + "yellow_bed", + "lime_bed", + "pink_bed", + "gray_bed", + "light_gray_bed", + "cyan_bed", + "purple_bed", + "blue_bed", + "brown_bed", + "green_bed", + "red_bed", + "black_bed", + "powered_rail", + "detector_rail", + "sticky_piston", + "cobweb", + "grass", + "fern", + "dead_bush", + "seagrass", + "tall_seagrass", + "piston", + "piston_head", + "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", + "moving_piston", + "dandelion", + "poppy", + "blue_orchid", + "allium", + "azure_bluet", + "red_tulip", + "orange_tulip", + "white_tulip", + "pink_tulip", + "oxeye_daisy", + "brown_mushroom", + "red_mushroom", + "gold_block", + "iron_block", + "bricks", + "tnt", + "bookshelf", + "mossy_cobblestone", + "obsidian", + "torch", + "wall_torch", + "fire", + "spawner", + "oak_stairs", + "chest", + "redstone_wire", + "diamond_ore", + "diamond_block", + "crafting_table", + "wheat", + "farmland", + "furnace", + "sign", + "oak_door", + "ladder", + "rail", + "cobblestone_stairs", + "wall_sign", + "lever", + "stone_pressure_plate", + "iron_door", + "oak_pressure_plate", + "spruce_pressure_plate", + "birch_pressure_plate", + "jungle_pressure_plate", + "acacia_pressure_plate", + "dark_oak_pressure_plate", + "redstone_ore", + "redstone_torch", + "redstone_wall_torch", + "stone_button", + "snow", + "ice", + "snow_block", + "cactus", + "clay", + "sugar_cane", + "jukebox", + "oak_fence", + "pumpkin", + "netherrack", + "soul_sand", + "glowstone", + "nether_portal", + "carved_pumpkin", + "jack_o_lantern", + "cake", + "repeater", + "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", + "oak_trapdoor", + "spruce_trapdoor", + "birch_trapdoor", + "jungle_trapdoor", + "acacia_trapdoor", + "dark_oak_trapdoor", + "infested_stone", + "infested_cobblestone", + "infested_stone_bricks", + "infested_mossy_stone_bricks", + "infested_cracked_stone_bricks", + "infested_chiseled_stone_bricks", + "stone_bricks", + "mossy_stone_bricks", + "cracked_stone_bricks", + "chiseled_stone_bricks", + "brown_mushroom_block", + "red_mushroom_block", + "mushroom_stem", + "iron_bars", + "glass_pane", + "melon", + "attached_pumpkin_stem", + "attached_melon_stem", + "pumpkin_stem", + "melon_stem", + "vine", + "oak_fence_gate", + "brick_stairs", + "stone_brick_stairs", + "mycelium", + "lily_pad", + "nether_bricks", + "nether_brick_fence", + "nether_brick_stairs", + "nether_wart", + "enchanting_table", + "brewing_stand", + "cauldron", + "end_portal", + "end_portal_frame", + "end_stone", + "dragon_egg", + "redstone_lamp", + "cocoa", + "sandstone_stairs", + "emerald_ore", + "ender_chest", + "tripwire_hook", + "tripwire", + "emerald_block", + "spruce_stairs", + "birch_stairs", + "jungle_stairs", + "command_block", + "beacon", + "cobblestone_wall", + "mossy_cobblestone_wall", + "flower_pot", + "potted_oak_sapling", + "potted_spruce_sapling", + "potted_birch_sapling", + "potted_jungle_sapling", + "potted_acacia_sapling", + "potted_dark_oak_sapling", + "potted_fern", + "potted_dandelion", + "potted_poppy", + "potted_blue_orchid", + "potted_allium", + "potted_azure_bluet", + "potted_red_tulip", + "potted_orange_tulip", + "potted_white_tulip", + "potted_pink_tulip", + "potted_oxeye_daisy", + "potted_red_mushroom", + "potted_brown_mushroom", + "potted_dead_bush", + "potted_cactus", + "carrots", + "potatoes", + "oak_button", + "spruce_button", + "birch_button", + "jungle_button", + "acacia_button", + "dark_oak_button", + "skeleton_wall_skull", + "skeleton_skull", + "wither_skeleton_wall_skull", + "wither_skeleton_skull", + "zombie_wall_head", + "zombie_head", + "player_wall_head", + "player_head", + "creeper_wall_head", + "creeper_head", + "dragon_wall_head", + "dragon_head", + "anvil", + "chipped_anvil", + "damaged_anvil", + "trapped_chest", + "light_weighted_pressure_plate", + "heavy_weighted_pressure_plate", + "comparator", + "daylight_detector", + "redstone_block", + "nether_quartz_ore", + "hopper", + "quartz_block", + "chiseled_quartz_block", + "quartz_pillar", + "quartz_stairs", + "activator_rail", + "dropper", + "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", + "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", + "acacia_stairs", + "dark_oak_stairs", + "slime_block", + "barrier", + "iron_trapdoor", + "prismarine", + "prismarine_bricks", + "dark_prismarine", + "prismarine_stairs", + "prismarine_brick_stairs", + "dark_prismarine_stairs", + "prismarine_slab", + "prismarine_brick_slab", + "dark_prismarine_slab", + "sea_lantern", + "hay_block", + "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", + "terracotta", + "coal_block", + "packed_ice", + "sunflower", + "lilac", + "rose_bush", + "peony", + "tall_grass", + "large_fern", + "white_banner", + "orange_banner", + "magenta_banner", + "light_blue_banner", + "yellow_banner", + "lime_banner", + "pink_banner", + "gray_banner", + "light_gray_banner", + "cyan_banner", + "purple_banner", + "blue_banner", + "brown_banner", + "green_banner", + "red_banner", + "black_banner", + "white_wall_banner", + "orange_wall_banner", + "magenta_wall_banner", + "light_blue_wall_banner", + "yellow_wall_banner", + "lime_wall_banner", + "pink_wall_banner", + "gray_wall_banner", + "light_gray_wall_banner", + "cyan_wall_banner", + "purple_wall_banner", + "blue_wall_banner", + "brown_wall_banner", + "green_wall_banner", + "red_wall_banner", + "black_wall_banner", + "red_sandstone", + "chiseled_red_sandstone", + "cut_red_sandstone", + "red_sandstone_stairs", + "oak_slab", + "spruce_slab", + "birch_slab", + "jungle_slab", + "acacia_slab", + "dark_oak_slab", + "stone_slab", + "sandstone_slab", + "petrified_oak_slab", + "cobblestone_slab", + "brick_slab", + "stone_brick_slab", + "nether_brick_slab", + "quartz_slab", + "red_sandstone_slab", + "purpur_slab", + "smooth_stone", + "smooth_sandstone", + "smooth_quartz", + "smooth_red_sandstone", + "spruce_fence_gate", + "birch_fence_gate", + "jungle_fence_gate", + "acacia_fence_gate", + "dark_oak_fence_gate", + "spruce_fence", + "birch_fence", + "jungle_fence", + "acacia_fence", + "dark_oak_fence", + "spruce_door", + "birch_door", + "jungle_door", + "acacia_door", + "dark_oak_door", + "end_rod", + "chorus_plant", + "chorus_flower", + "purpur_block", + "purpur_pillar", + "purpur_stairs", + "end_stone_bricks", + "beetroots", + "grass_path", + "end_gateway", + "repeating_command_block", + "chain_command_block", + "frosted_ice", + "magma_block", + "nether_wart_block", + "red_nether_bricks", + "bone_block", + "structure_void", + "observer", + "shulker_box", + "white_shulker_box", + "orange_shulker_box", + "magenta_shulker_box", + "light_blue_shulker_box", + "yellow_shulker_box", + "lime_shulker_box", + "pink_shulker_box", + "gray_shulker_box", + "light_gray_shulker_box", + "cyan_shulker_box", + "purple_shulker_box", + "blue_shulker_box", + "brown_shulker_box", + "green_shulker_box", + "red_shulker_box", + "black_shulker_box", + "white_glazed_terracotta", + "orange_glazed_terracotta", + "magenta_glazed_terracotta", + "light_blue_glazed_terracotta", + "yellow_glazed_terracotta", + "lime_glazed_terracotta", + "pink_glazed_terracotta", + "gray_glazed_terracotta", + "light_gray_glazed_terracotta", + "cyan_glazed_terracotta", + "purple_glazed_terracotta", + "blue_glazed_terracotta", + "brown_glazed_terracotta", + "green_glazed_terracotta", + "red_glazed_terracotta", + "black_glazed_terracotta", + "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", + "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", + "kelp", + "kelp_plant", + "dried_kelp_block", + "turtle_egg", + "dead_tube_coral_block", + "dead_brain_coral_block", + "dead_bubble_coral_block", + "dead_fire_coral_block", + "dead_horn_coral_block", + "tube_coral_block", + "brain_coral_block", + "bubble_coral_block", + "fire_coral_block", + "horn_coral_block", + "dead_tube_coral", + "dead_brain_coral", + "dead_bubble_coral", + "dead_fire_coral", + "dead_horn_coral", + "tube_coral", + "brain_coral", + "bubble_coral", + "fire_coral", + "horn_coral", + "dead_tube_coral_wall_fan", + "dead_brain_coral_wall_fan", + "dead_bubble_coral_wall_fan", + "dead_fire_coral_wall_fan", + "dead_horn_coral_wall_fan", + "tube_coral_wall_fan", + "brain_coral_wall_fan", + "bubble_coral_wall_fan", + "fire_coral_wall_fan", + "horn_coral_wall_fan", + "dead_tube_coral_fan", + "dead_brain_coral_fan", + "dead_bubble_coral_fan", + "dead_fire_coral_fan", + "dead_horn_coral_fan", + "tube_coral_fan", + "brain_coral_fan", + "bubble_coral_fan", + "fire_coral_fan", + "horn_coral_fan", + "sea_pickle", + "blue_ice", + "conduit", + "void_air", + "cave_air", + "bubble_column", + "structure_block", ], + ), + Enum( + name: "block_bounding_box", + variants: [ + + "block", + "empty", ], + ), + Property( + on: "block_kind", + name: "display_name", + reverse: true, + type: string, + mapping: { + "air": "Air", + "stone": "Stone", + "granite": "Granite", + "polished_granite": "Polished Granite", + "diorite": "Diorite", + "polished_diorite": "Polished Diorite", + "andesite": "Andesite", + "polished_andesite": "Polished Andesite", + "grass_block": "Grass Block", + "dirt": "Dirt", + "coarse_dirt": "Coarse Dirt", + "podzol": "Podzol", + "cobblestone": "Cobblestone", + "oak_planks": "Oak Planks", + "spruce_planks": "Spruce Planks", + "birch_planks": "Birch Planks", + "jungle_planks": "Jungle Planks", + "acacia_planks": "Acacia Planks", + "dark_oak_planks": "Dark Oak Planks", + "oak_sapling": "Oak Sapling", + "spruce_sapling": "Spruce Sapling", + "birch_sapling": "Birch Sapling", + "jungle_sapling": "Jungle Sapling", + "acacia_sapling": "Acacia Sapling", + "dark_oak_sapling": "Dark Oak Sapling", + "bedrock": "Bedrock", + "water": "Water", + "lava": "Lava", + "sand": "Sand", + "red_sand": "Red Sand", + "gravel": "Gravel", + "gold_ore": "Gold Ore", + "iron_ore": "Iron Ore", + "coal_ore": "Coal Ore", + "oak_log": "Oak Log", + "spruce_log": "Spruce Log", + "birch_log": "Birch Log", + "jungle_log": "Jungle Log", + "acacia_log": "Acacia Log", + "dark_oak_log": "Dark Oak Log", + "stripped_spruce_log": "Stripped Spruce Log", + "stripped_birch_log": "Stripped Birch Log", + "stripped_jungle_log": "Stripped Jungle Log", + "stripped_acacia_log": "Stripped Acacia Log", + "stripped_dark_oak_log": "Stripped Dark Oak Log", + "stripped_oak_log": "Stripped Oak Log", + "oak_wood": "Oak Wood", + "spruce_wood": "Spruce Wood", + "birch_wood": "Birch Wood", + "jungle_wood": "Jungle Wood", + "acacia_wood": "Acacia Wood", + "dark_oak_wood": "Dark Oak Wood", + "stripped_oak_wood": "Stripped Oak Wood", + "stripped_spruce_wood": "Stripped Spruce Wood", + "stripped_birch_wood": "Stripped Birch Wood", + "stripped_jungle_wood": "Stripped Jungle Wood", + "stripped_acacia_wood": "Stripped Acacia Wood", + "stripped_dark_oak_wood": "Stripped Dark Oak Wood", + "oak_leaves": "Oak Leaves", + "spruce_leaves": "Spruce Leaves", + "birch_leaves": "Birch Leaves", + "jungle_leaves": "Jungle Leaves", + "acacia_leaves": "Acacia Leaves", + "dark_oak_leaves": "Dark Oak Leaves", + "sponge": "Sponge", + "wet_sponge": "Wet Sponge", + "glass": "Glass", + "lapis_ore": "Lapis Lazuli Ore", + "lapis_block": "Lapis Lazuli Block", + "dispenser": "Dispenser", + "sandstone": "Sandstone", + "chiseled_sandstone": "Chiseled Sandstone", + "cut_sandstone": "Cut Sandstone", + "note_block": "Note Block", + "white_bed": "White Bed", + "orange_bed": "Orange Bed", + "magenta_bed": "Magenta Bed", + "light_blue_bed": "Light Blue Bed", + "yellow_bed": "Yellow Bed", + "lime_bed": "Lime Bed", + "pink_bed": "Pink Bed", + "gray_bed": "Gray Bed", + "light_gray_bed": "Light Gray Bed", + "cyan_bed": "Cyan Bed", + "purple_bed": "Purple Bed", + "blue_bed": "Blue Bed", + "brown_bed": "Brown Bed", + "green_bed": "Green Bed", + "red_bed": "Red Bed", + "black_bed": "Black Bed", + "powered_rail": "Powered Rail", + "detector_rail": "Detector Rail", + "sticky_piston": "Sticky Piston", + "cobweb": "Cobweb", + "grass": "Grass", + "fern": "Fern", + "dead_bush": "Dead Bush", + "seagrass": "Seagrass", + "tall_seagrass": "Tall Seagrass", + "piston": "Piston", + "piston_head": "Piston Head", + "white_wool": "White Wool", + "orange_wool": "Orange Wool", + "magenta_wool": "Magenta Wool", + "light_blue_wool": "Light Blue Wool", + "yellow_wool": "Yellow Wool", + "lime_wool": "Lime Wool", + "pink_wool": "Pink Wool", + "gray_wool": "Gray Wool", + "light_gray_wool": "Light Gray Wool", + "cyan_wool": "Cyan Wool", + "purple_wool": "Purple Wool", + "blue_wool": "Blue Wool", + "brown_wool": "Brown Wool", + "green_wool": "Green Wool", + "red_wool": "Red Wool", + "black_wool": "Black Wool", + "moving_piston": "Moving Piston", + "dandelion": "Dandelion", + "poppy": "Poppy", + "blue_orchid": "Blue Orchid", + "allium": "Allium", + "azure_bluet": "Azure Bluet", + "red_tulip": "Red Tulip", + "orange_tulip": "Orange Tulip", + "white_tulip": "White Tulip", + "pink_tulip": "Pink Tulip", + "oxeye_daisy": "Oxeye Daisy", + "brown_mushroom": "Brown Mushroom", + "red_mushroom": "Red Mushroom", + "gold_block": "Block of Gold", + "iron_block": "Block of Iron", + "bricks": "Bricks", + "tnt": "TNT", + "bookshelf": "Bookshelf", + "mossy_cobblestone": "Mossy Cobblestone", + "obsidian": "Obsidian", + "torch": "Torch", + "wall_torch": "Wall Torch", + "fire": "Fire", + "spawner": "Spawner", + "oak_stairs": "Oak Stairs", + "chest": "Chest", + "redstone_wire": "Redstone Dust", + "diamond_ore": "Diamond Ore", + "diamond_block": "Block of Diamond", + "crafting_table": "Crafting Table", + "wheat": "Wheat Crops", + "farmland": "Farmland", + "furnace": "Furnace", + "sign": "Sign", + "oak_door": "Oak Door", + "ladder": "Ladder", + "rail": "Rail", + "cobblestone_stairs": "Cobblestone Stairs", + "wall_sign": "Wall Sign", + "lever": "Lever", + "stone_pressure_plate": "Stone Pressure Plate", + "iron_door": "Iron Door", + "oak_pressure_plate": "Oak Pressure Plate", + "spruce_pressure_plate": "Spruce Pressure Plate", + "birch_pressure_plate": "Birch Pressure Plate", + "jungle_pressure_plate": "Jungle Pressure Plate", + "acacia_pressure_plate": "Acacia Pressure Plate", + "dark_oak_pressure_plate": "Dark Oak Pressure Plate", + "redstone_ore": "Redstone Ore", + "redstone_torch": "Redstone Torch", + "redstone_wall_torch": "Redstone Wall Torch", + "stone_button": "Stone Button", + "snow": "Snow", + "ice": "Ice", + "snow_block": "Snow Block", + "cactus": "Cactus", + "clay": "Clay", + "sugar_cane": "Sugar Cane", + "jukebox": "Jukebox", + "oak_fence": "Oak Fence", + "pumpkin": "Pumpkin", + "netherrack": "Netherrack", + "soul_sand": "Soul Sand", + "glowstone": "Glowstone", + "nether_portal": "Nether Portal", + "carved_pumpkin": "Carved Pumpkin", + "jack_o_lantern": "Jack o\'Lantern", + "cake": "Cake", + "repeater": "Redstone Repeater", + "white_stained_glass": "White Stained Glass", + "orange_stained_glass": "Orange Stained Glass", + "magenta_stained_glass": "Magenta Stained Glass", + "light_blue_stained_glass": "Light Blue Stained Glass", + "yellow_stained_glass": "Yellow Stained Glass", + "lime_stained_glass": "Lime Stained Glass", + "pink_stained_glass": "Pink Stained Glass", + "gray_stained_glass": "Gray Stained Glass", + "light_gray_stained_glass": "Light Gray Stained Glass", + "cyan_stained_glass": "Cyan Stained Glass", + "purple_stained_glass": "Purple Stained Glass", + "blue_stained_glass": "Blue Stained Glass", + "brown_stained_glass": "Brown Stained Glass", + "green_stained_glass": "Green Stained Glass", + "red_stained_glass": "Red Stained Glass", + "black_stained_glass": "Black Stained Glass", + "oak_trapdoor": "Oak Trapdoor", + "spruce_trapdoor": "Spruce Trapdoor", + "birch_trapdoor": "Birch Trapdoor", + "jungle_trapdoor": "Jungle Trapdoor", + "acacia_trapdoor": "Acacia Trapdoor", + "dark_oak_trapdoor": "Dark Oak Trapdoor", + "infested_stone": "Infested Stone", + "infested_cobblestone": "Infested Cobblestone", + "infested_stone_bricks": "Infested Stone Bricks", + "infested_mossy_stone_bricks": "Infested Mossy Stone Bricks", + "infested_cracked_stone_bricks": "Infested Cracked Stone Bricks", + "infested_chiseled_stone_bricks": "Infested Chiseled Stone Bricks", + "stone_bricks": "Stone Bricks", + "mossy_stone_bricks": "Mossy Stone Bricks", + "cracked_stone_bricks": "Cracked Stone Bricks", + "chiseled_stone_bricks": "Chiseled Stone Bricks", + "brown_mushroom_block": "Brown Mushroom Block", + "red_mushroom_block": "Red Mushroom Block", + "mushroom_stem": "Mushroom Stem", + "iron_bars": "Iron Bars", + "glass_pane": "Glass Pane", + "melon": "Melon", + "attached_pumpkin_stem": "Attached Pumpkin Stem", + "attached_melon_stem": "Attached Melon Stem", + "pumpkin_stem": "Pumpkin Stem", + "melon_stem": "Melon Stem", + "vine": "Vines", + "oak_fence_gate": "Oak Fence Gate", + "brick_stairs": "Brick Stairs", + "stone_brick_stairs": "Stone Brick Stairs", + "mycelium": "Mycelium", + "lily_pad": "Lily Pad", + "nether_bricks": "Nether Bricks", + "nether_brick_fence": "Nether Brick Fence", + "nether_brick_stairs": "Nether Brick Stairs", + "nether_wart": "Nether Wart", + "enchanting_table": "Enchanting Table", + "brewing_stand": "Brewing Stand", + "cauldron": "Cauldron", + "end_portal": "End Portal", + "end_portal_frame": "End Portal Frame", + "end_stone": "End Stone", + "dragon_egg": "Dragon Egg", + "redstone_lamp": "Redstone Lamp", + "cocoa": "Cocoa", + "sandstone_stairs": "Sandstone Stairs", + "emerald_ore": "Emerald Ore", + "ender_chest": "Ender Chest", + "tripwire_hook": "Tripwire Hook", + "tripwire": "Tripwire", + "emerald_block": "Block of Emerald", + "spruce_stairs": "Spruce Stairs", + "birch_stairs": "Birch Stairs", + "jungle_stairs": "Jungle Stairs", + "command_block": "Command Block", + "beacon": "Beacon", + "cobblestone_wall": "Cobblestone Wall", + "mossy_cobblestone_wall": "Mossy Cobblestone Wall", + "flower_pot": "Flower Pot", + "potted_oak_sapling": "Potted Oak Sapling", + "potted_spruce_sapling": "Potted Spruce Sapling", + "potted_birch_sapling": "Potted Birch Sapling", + "potted_jungle_sapling": "Potted Jungle Sapling", + "potted_acacia_sapling": "Potted Acacia Sapling", + "potted_dark_oak_sapling": "Potted Dark Oak Sapling", + "potted_fern": "Potted Fern", + "potted_dandelion": "Potted Dandelion", + "potted_poppy": "Potted Poppy", + "potted_blue_orchid": "Potted Blue Orchid", + "potted_allium": "Potted Allium", + "potted_azure_bluet": "Potted Azure Bluet", + "potted_red_tulip": "Potted Red Tulip", + "potted_orange_tulip": "Potted Orange Tulip", + "potted_white_tulip": "Potted White Tulip", + "potted_pink_tulip": "Potted Pink Tulip", + "potted_oxeye_daisy": "Potted Oxeye Daisy", + "potted_red_mushroom": "Potted Red Mushroom", + "potted_brown_mushroom": "Potted Brown Mushroom", + "potted_dead_bush": "Potted Dead Bush", + "potted_cactus": "Potted Cactus", + "carrots": "Carrots", + "potatoes": "Potatoes", + "oak_button": "Oak Button", + "spruce_button": "Spruce Button", + "birch_button": "Birch Button", + "jungle_button": "Jungle Button", + "acacia_button": "Acacia Button", + "dark_oak_button": "Dark Oak Button", + "skeleton_wall_skull": "Skeleton Wall Skull", + "skeleton_skull": "Skeleton Skull", + "wither_skeleton_wall_skull": "Wither Skeleton Wall Skull", + "wither_skeleton_skull": "Wither Skeleton Skull", + "zombie_wall_head": "Zombie Wall Head", + "zombie_head": "Zombie Head", + "player_wall_head": "Player Wall Head", + "player_head": "Player Head", + "creeper_wall_head": "Creeper Wall Head", + "creeper_head": "Creeper Head", + "dragon_wall_head": "Dragon Wall Head", + "dragon_head": "Dragon Head", + "anvil": "Anvil", + "chipped_anvil": "Chipped Anvil", + "damaged_anvil": "Damaged Anvil", + "trapped_chest": "Trapped Chest", + "light_weighted_pressure_plate": "Light Weighted Pressure Plate", + "heavy_weighted_pressure_plate": "Heavy Weighted Pressure Plate", + "comparator": "Redstone Comparator", + "daylight_detector": "Daylight Detector", + "redstone_block": "Block of Redstone", + "nether_quartz_ore": "Nether Quartz Ore", + "hopper": "Hopper", + "quartz_block": "Block of Quartz", + "chiseled_quartz_block": "Chiseled Quartz Block", + "quartz_pillar": "Quartz Pillar", + "quartz_stairs": "Quartz Stairs", + "activator_rail": "Activator Rail", + "dropper": "Dropper", + "white_terracotta": "White Terracotta", + "orange_terracotta": "Orange Terracotta", + "magenta_terracotta": "Magenta Terracotta", + "light_blue_terracotta": "Light Blue Terracotta", + "yellow_terracotta": "Yellow Terracotta", + "lime_terracotta": "Lime Terracotta", + "pink_terracotta": "Pink Terracotta", + "gray_terracotta": "Gray Terracotta", + "light_gray_terracotta": "Light Gray Terracotta", + "cyan_terracotta": "Cyan Terracotta", + "purple_terracotta": "Purple Terracotta", + "blue_terracotta": "Blue Terracotta", + "brown_terracotta": "Brown Terracotta", + "green_terracotta": "Green Terracotta", + "red_terracotta": "Red Terracotta", + "black_terracotta": "Black Terracotta", + "white_stained_glass_pane": "White Stained Glass Pane", + "orange_stained_glass_pane": "Orange Stained Glass Pane", + "magenta_stained_glass_pane": "Magenta Stained Glass Pane", + "light_blue_stained_glass_pane": "Light Blue Stained Glass Pane", + "yellow_stained_glass_pane": "Yellow Stained Glass Pane", + "lime_stained_glass_pane": "Lime Stained Glass Pane", + "pink_stained_glass_pane": "Pink Stained Glass Pane", + "gray_stained_glass_pane": "Gray Stained Glass Pane", + "light_gray_stained_glass_pane": "Light Gray Stained Glass Pane", + "cyan_stained_glass_pane": "Cyan Stained Glass Pane", + "purple_stained_glass_pane": "Purple Stained Glass Pane", + "blue_stained_glass_pane": "Blue Stained Glass Pane", + "brown_stained_glass_pane": "Brown Stained Glass Pane", + "green_stained_glass_pane": "Green Stained Glass Pane", + "red_stained_glass_pane": "Red Stained Glass Pane", + "black_stained_glass_pane": "Black Stained Glass Pane", + "acacia_stairs": "Acacia Stairs", + "dark_oak_stairs": "Dark Oak Stairs", + "slime_block": "Slime Block", + "barrier": "Barrier", + "iron_trapdoor": "Iron Trapdoor", + "prismarine": "Prismarine", + "prismarine_bricks": "Prismarine Bricks", + "dark_prismarine": "Dark Prismarine", + "prismarine_stairs": "Prismarine Stairs", + "prismarine_brick_stairs": "Prismarine Brick Stairs", + "dark_prismarine_stairs": "Dark Prismarine Stairs", + "prismarine_slab": "Prismarine Slab", + "prismarine_brick_slab": "Prismarine Brick Slab", + "dark_prismarine_slab": "Dark Prismarine Slab", + "sea_lantern": "Sea Lantern", + "hay_block": "Hay Bale", + "white_carpet": "White Carpet", + "orange_carpet": "Orange Carpet", + "magenta_carpet": "Magenta Carpet", + "light_blue_carpet": "Light Blue Carpet", + "yellow_carpet": "Yellow Carpet", + "lime_carpet": "Lime Carpet", + "pink_carpet": "Pink Carpet", + "gray_carpet": "Gray Carpet", + "light_gray_carpet": "Light Gray Carpet", + "cyan_carpet": "Cyan Carpet", + "purple_carpet": "Purple Carpet", + "blue_carpet": "Blue Carpet", + "brown_carpet": "Brown Carpet", + "green_carpet": "Green Carpet", + "red_carpet": "Red Carpet", + "black_carpet": "Black Carpet", + "terracotta": "Terracotta", + "coal_block": "Block of Coal", + "packed_ice": "Packed Ice", + "sunflower": "Sunflower", + "lilac": "Lilac", + "rose_bush": "Rose Bush", + "peony": "Peony", + "tall_grass": "Tall Grass", + "large_fern": "Large Fern", + "white_banner": "White Banner", + "orange_banner": "Orange Banner", + "magenta_banner": "Magenta Banner", + "light_blue_banner": "Light Blue Banner", + "yellow_banner": "Yellow Banner", + "lime_banner": "Lime Banner", + "pink_banner": "Pink Banner", + "gray_banner": "Gray Banner", + "light_gray_banner": "Light Gray Banner", + "cyan_banner": "Cyan Banner", + "purple_banner": "Purple Banner", + "blue_banner": "Blue Banner", + "brown_banner": "Brown Banner", + "green_banner": "Green Banner", + "red_banner": "Red Banner", + "black_banner": "Black Banner", + "white_wall_banner": "White wall banner", + "orange_wall_banner": "Orange wall banner", + "magenta_wall_banner": "Magenta wall banner", + "light_blue_wall_banner": "Light blue wall banner", + "yellow_wall_banner": "Yellow wall banner", + "lime_wall_banner": "Lime wall banner", + "pink_wall_banner": "Pink wall banner", + "gray_wall_banner": "Gray wall banner", + "light_gray_wall_banner": "Light gray wall banner", + "cyan_wall_banner": "Cyan wall banner", + "purple_wall_banner": "Purple wall banner", + "blue_wall_banner": "Blue wall banner", + "brown_wall_banner": "Brown wall banner", + "green_wall_banner": "Green wall banner", + "red_wall_banner": "Red wall banner", + "black_wall_banner": "Black wall banner", + "red_sandstone": "Red Sandstone", + "chiseled_red_sandstone": "Chiseled Red Sandstone", + "cut_red_sandstone": "Cut Red Sandstone", + "red_sandstone_stairs": "Red Sandstone Stairs", + "oak_slab": "Oak Slab", + "spruce_slab": "Spruce Slab", + "birch_slab": "Birch Slab", + "jungle_slab": "Jungle Slab", + "acacia_slab": "Acacia Slab", + "dark_oak_slab": "Dark Oak Slab", + "stone_slab": "Stone Slab", + "sandstone_slab": "Sandstone Slab", + "petrified_oak_slab": "Petrified Oak Slab", + "cobblestone_slab": "Cobblestone Slab", + "brick_slab": "Brick Slab", + "stone_brick_slab": "Stone Brick Slab", + "nether_brick_slab": "Nether Brick Slab", + "quartz_slab": "Quartz Slab", + "red_sandstone_slab": "Red Sandstone Slab", + "purpur_slab": "Purpur Slab", + "smooth_stone": "Smooth Stone", + "smooth_sandstone": "Smooth Sandstone", + "smooth_quartz": "Smooth Quartz", + "smooth_red_sandstone": "Smooth Red Sandstone", + "spruce_fence_gate": "Spruce Fence Gate", + "birch_fence_gate": "Birch Fence Gate", + "jungle_fence_gate": "Jungle Fence Gate", + "acacia_fence_gate": "Acacia Fence Gate", + "dark_oak_fence_gate": "Dark Oak Fence Gate", + "spruce_fence": "Spruce Fence", + "birch_fence": "Birch Fence", + "jungle_fence": "Jungle Fence", + "acacia_fence": "Acacia Fence", + "dark_oak_fence": "Dark Oak Fence", + "spruce_door": "Spruce Door", + "birch_door": "Birch Door", + "jungle_door": "Jungle Door", + "acacia_door": "Acacia Door", + "dark_oak_door": "Dark Oak Door", + "end_rod": "End Rod", + "chorus_plant": "Chorus Plant", + "chorus_flower": "Chorus Flower", + "purpur_block": "Purpur Block", + "purpur_pillar": "Purpur Pillar", + "purpur_stairs": "Purpur Stairs", + "end_stone_bricks": "End Stone Bricks", + "beetroots": "Beetroots", + "grass_path": "Grass Path", + "end_gateway": "End Gateway", + "repeating_command_block": "Repeating Command Block", + "chain_command_block": "Chain Command Block", + "frosted_ice": "Frosted Ice", + "magma_block": "Magma Block", + "nether_wart_block": "Nether Wart Block", + "red_nether_bricks": "Red Nether Bricks", + "bone_block": "Bone Block", + "structure_void": "Structure Void", + "observer": "Observer", + "shulker_box": "Shulker Box", + "white_shulker_box": "White Shulker Box", + "orange_shulker_box": "Orange Shulker Box", + "magenta_shulker_box": "Magenta Shulker Box", + "light_blue_shulker_box": "Light Blue Shulker Box", + "yellow_shulker_box": "Yellow Shulker Box", + "lime_shulker_box": "Lime Shulker Box", + "pink_shulker_box": "Pink Shulker Box", + "gray_shulker_box": "Gray Shulker Box", + "light_gray_shulker_box": "Light Gray Shulker Box", + "cyan_shulker_box": "Cyan Shulker Box", + "purple_shulker_box": "Purple Shulker Box", + "blue_shulker_box": "Blue Shulker Box", + "brown_shulker_box": "Brown Shulker Box", + "green_shulker_box": "Green Shulker Box", + "red_shulker_box": "Red Shulker Box", + "black_shulker_box": "Black Shulker Box", + "white_glazed_terracotta": "White Glazed Terracotta", + "orange_glazed_terracotta": "Orange Glazed Terracotta", + "magenta_glazed_terracotta": "Magenta Glazed Terracotta", + "light_blue_glazed_terracotta": "Light Blue Glazed Terracotta", + "yellow_glazed_terracotta": "Yellow Glazed Terracotta", + "lime_glazed_terracotta": "Lime Glazed Terracotta", + "pink_glazed_terracotta": "Pink Glazed Terracotta", + "gray_glazed_terracotta": "Gray Glazed Terracotta", + "light_gray_glazed_terracotta": "Light Gray Glazed Terracotta", + "cyan_glazed_terracotta": "Cyan Glazed Terracotta", + "purple_glazed_terracotta": "Purple Glazed Terracotta", + "blue_glazed_terracotta": "Blue Glazed Terracotta", + "brown_glazed_terracotta": "Brown Glazed Terracotta", + "green_glazed_terracotta": "Green Glazed Terracotta", + "red_glazed_terracotta": "Red Glazed Terracotta", + "black_glazed_terracotta": "Black Glazed Terracotta", + "white_concrete": "White Concrete", + "orange_concrete": "Orange Concrete", + "magenta_concrete": "Magenta Concrete", + "light_blue_concrete": "Light Blue Concrete", + "yellow_concrete": "Yellow Concrete", + "lime_concrete": "Lime Concrete", + "pink_concrete": "Pink Concrete", + "gray_concrete": "Gray Concrete", + "light_gray_concrete": "Light Gray Concrete", + "cyan_concrete": "Cyan Concrete", + "purple_concrete": "Purple Concrete", + "blue_concrete": "Blue Concrete", + "brown_concrete": "Brown Concrete", + "green_concrete": "Green Concrete", + "red_concrete": "Red Concrete", + "black_concrete": "Black Concrete", + "white_concrete_powder": "White Concrete Powder", + "orange_concrete_powder": "Orange Concrete Powder", + "magenta_concrete_powder": "Magenta Concrete Powder", + "light_blue_concrete_powder": "Light Blue Concrete Powder", + "yellow_concrete_powder": "Yellow Concrete Powder", + "lime_concrete_powder": "Lime Concrete Powder", + "pink_concrete_powder": "Pink Concrete Powder", + "gray_concrete_powder": "Gray Concrete Powder", + "light_gray_concrete_powder": "Light Gray Concrete Powder", + "cyan_concrete_powder": "Cyan Concrete Powder", + "purple_concrete_powder": "Purple Concrete Powder", + "blue_concrete_powder": "Blue Concrete Powder", + "brown_concrete_powder": "Brown Concrete Powder", + "green_concrete_powder": "Green Concrete Powder", + "red_concrete_powder": "Red Concrete Powder", + "black_concrete_powder": "Black Concrete Powder", + "kelp": "Kelp", + "kelp_plant": "Kelp Plant", + "dried_kelp_block": "Dried Kelp Block", + "turtle_egg": "Turtle Egg", + "dead_tube_coral_block": "Dead Tube Coral Block", + "dead_brain_coral_block": "Dead Brain Coral Block", + "dead_bubble_coral_block": "Dead Bubble Coral Block", + "dead_fire_coral_block": "Dead Fire Coral Block", + "dead_horn_coral_block": "Dead Horn Coral Block", + "tube_coral_block": "Tube Coral Block", + "brain_coral_block": "Brain Coral Block", + "bubble_coral_block": "Bubble Coral Block", + "fire_coral_block": "Fire Coral Block", + "horn_coral_block": "Horn Coral Block", + "dead_tube_coral": "Dead Tube Coral", + "dead_brain_coral": "Dead Brain Coral", + "dead_bubble_coral": "Dead Bubble Coral", + "dead_fire_coral": "Dead Fire Coral", + "dead_horn_coral": "Dead Horn Coral", + "tube_coral": "Tube Coral", + "brain_coral": "Brain Coral", + "bubble_coral": "Bubble Coral", + "fire_coral": "Fire Coral", + "horn_coral": "Horn Coral", + "dead_tube_coral_wall_fan": "Dead Tube Coral Wall Fan", + "dead_brain_coral_wall_fan": "Dead Brain Coral Wall Fan", + "dead_bubble_coral_wall_fan": "Dead Bubble Coral Wall Fan", + "dead_fire_coral_wall_fan": "Dead Fire Coral Wall Fan", + "dead_horn_coral_wall_fan": "Dead Horn Coral Wall Fan", + "tube_coral_wall_fan": "Tube Coral Wall Fan", + "brain_coral_wall_fan": "Brain Coral Wall Fan", + "bubble_coral_wall_fan": "Bubble Coral Wall Fan", + "fire_coral_wall_fan": "Fire Coral Wall Fan", + "horn_coral_wall_fan": "Horn Coral Wall Fan", + "dead_tube_coral_fan": "Dead Tube Coral Fan", + "dead_brain_coral_fan": "Dead Brain Coral Fan", + "dead_bubble_coral_fan": "Dead Bubble Coral Fan", + "dead_fire_coral_fan": "Dead Fire Coral Fan", + "dead_horn_coral_fan": "Dead Horn Coral Fan", + "tube_coral_fan": "Tube Coral Fan", + "brain_coral_fan": "Brain Coral Fan", + "bubble_coral_fan": "Bubble Coral Fan", + "fire_coral_fan": "Fire Coral Fan", + "horn_coral_fan": "Horn Coral Fan", + "sea_pickle": "Sea Pickle", + "blue_ice": "Blue Ice", + "conduit": "Conduit", + "void_air": "Void Air", + "cave_air": "Cave Air", + "bubble_column": "Bubble Column", + "structure_block": "Structure Block", + }, + ), + Property( + on: "block_kind", + name: "diggable", + reverse: false, + type: bool, + mapping: { + "air": true, + "stone": true, + "granite": true, + "polished_granite": true, + "diorite": true, + "polished_diorite": true, + "andesite": true, + "polished_andesite": true, + "grass_block": true, + "dirt": true, + "coarse_dirt": true, + "podzol": true, + "cobblestone": true, + "oak_planks": true, + "spruce_planks": true, + "birch_planks": true, + "jungle_planks": true, + "acacia_planks": true, + "dark_oak_planks": true, + "oak_sapling": true, + "spruce_sapling": true, + "birch_sapling": true, + "jungle_sapling": true, + "acacia_sapling": true, + "dark_oak_sapling": true, + "bedrock": false, + "water": false, + "lava": false, + "sand": true, + "red_sand": true, + "gravel": true, + "gold_ore": true, + "iron_ore": true, + "coal_ore": true, + "oak_log": true, + "spruce_log": true, + "birch_log": true, + "jungle_log": true, + "acacia_log": true, + "dark_oak_log": true, + "stripped_spruce_log": true, + "stripped_birch_log": true, + "stripped_jungle_log": true, + "stripped_acacia_log": true, + "stripped_dark_oak_log": true, + "stripped_oak_log": true, + "oak_wood": true, + "spruce_wood": true, + "birch_wood": true, + "jungle_wood": true, + "acacia_wood": true, + "dark_oak_wood": true, + "stripped_oak_wood": true, + "stripped_spruce_wood": true, + "stripped_birch_wood": true, + "stripped_jungle_wood": true, + "stripped_acacia_wood": true, + "stripped_dark_oak_wood": true, + "oak_leaves": true, + "spruce_leaves": true, + "birch_leaves": true, + "jungle_leaves": true, + "acacia_leaves": true, + "dark_oak_leaves": true, + "sponge": true, + "wet_sponge": true, + "glass": true, + "lapis_ore": true, + "lapis_block": true, + "dispenser": true, + "sandstone": true, + "chiseled_sandstone": true, + "cut_sandstone": true, + "note_block": true, + "white_bed": true, + "orange_bed": true, + "magenta_bed": true, + "light_blue_bed": true, + "yellow_bed": true, + "lime_bed": true, + "pink_bed": true, + "gray_bed": true, + "light_gray_bed": true, + "cyan_bed": true, + "purple_bed": true, + "blue_bed": true, + "brown_bed": true, + "green_bed": true, + "red_bed": true, + "black_bed": true, + "powered_rail": true, + "detector_rail": true, + "sticky_piston": true, + "cobweb": true, + "grass": true, + "fern": true, + "dead_bush": true, + "seagrass": true, + "tall_seagrass": true, + "piston": true, + "piston_head": true, + "white_wool": true, + "orange_wool": true, + "magenta_wool": true, + "light_blue_wool": true, + "yellow_wool": true, + "lime_wool": true, + "pink_wool": true, + "gray_wool": true, + "light_gray_wool": true, + "cyan_wool": true, + "purple_wool": true, + "blue_wool": true, + "brown_wool": true, + "green_wool": true, + "red_wool": true, + "black_wool": true, + "moving_piston": false, + "dandelion": true, + "poppy": true, + "blue_orchid": true, + "allium": true, + "azure_bluet": true, + "red_tulip": true, + "orange_tulip": true, + "white_tulip": true, + "pink_tulip": true, + "oxeye_daisy": true, + "brown_mushroom": true, + "red_mushroom": true, + "gold_block": true, + "iron_block": true, + "bricks": true, + "tnt": true, + "bookshelf": true, + "mossy_cobblestone": true, + "obsidian": true, + "torch": true, + "wall_torch": true, + "fire": true, + "spawner": true, + "oak_stairs": true, + "chest": true, + "redstone_wire": true, + "diamond_ore": true, + "diamond_block": true, + "crafting_table": true, + "wheat": true, + "farmland": true, + "furnace": true, + "sign": true, + "oak_door": true, + "ladder": true, + "rail": true, + "cobblestone_stairs": true, + "wall_sign": true, + "lever": true, + "stone_pressure_plate": true, + "iron_door": true, + "oak_pressure_plate": true, + "spruce_pressure_plate": true, + "birch_pressure_plate": true, + "jungle_pressure_plate": true, + "acacia_pressure_plate": true, + "dark_oak_pressure_plate": true, + "redstone_ore": true, + "redstone_torch": true, + "redstone_wall_torch": true, + "stone_button": true, + "snow": true, + "ice": true, + "snow_block": true, + "cactus": true, + "clay": true, + "sugar_cane": true, + "jukebox": true, + "oak_fence": true, + "pumpkin": true, + "netherrack": true, + "soul_sand": true, + "glowstone": true, + "nether_portal": false, + "carved_pumpkin": true, + "jack_o_lantern": true, + "cake": true, + "repeater": true, + "white_stained_glass": true, + "orange_stained_glass": true, + "magenta_stained_glass": true, + "light_blue_stained_glass": true, + "yellow_stained_glass": true, + "lime_stained_glass": true, + "pink_stained_glass": true, + "gray_stained_glass": true, + "light_gray_stained_glass": true, + "cyan_stained_glass": true, + "purple_stained_glass": true, + "blue_stained_glass": true, + "brown_stained_glass": true, + "green_stained_glass": true, + "red_stained_glass": true, + "black_stained_glass": true, + "oak_trapdoor": true, + "spruce_trapdoor": true, + "birch_trapdoor": true, + "jungle_trapdoor": true, + "acacia_trapdoor": true, + "dark_oak_trapdoor": true, + "infested_stone": true, + "infested_cobblestone": true, + "infested_stone_bricks": true, + "infested_mossy_stone_bricks": true, + "infested_cracked_stone_bricks": true, + "infested_chiseled_stone_bricks": true, + "stone_bricks": true, + "mossy_stone_bricks": true, + "cracked_stone_bricks": true, + "chiseled_stone_bricks": true, + "brown_mushroom_block": true, + "red_mushroom_block": true, + "mushroom_stem": true, + "iron_bars": true, + "glass_pane": true, + "melon": true, + "attached_pumpkin_stem": true, + "attached_melon_stem": true, + "pumpkin_stem": true, + "melon_stem": true, + "vine": true, + "oak_fence_gate": true, + "brick_stairs": true, + "stone_brick_stairs": true, + "mycelium": true, + "lily_pad": true, + "nether_bricks": true, + "nether_brick_fence": true, + "nether_brick_stairs": true, + "nether_wart": true, + "enchanting_table": true, + "brewing_stand": true, + "cauldron": true, + "end_portal": false, + "end_portal_frame": false, + "end_stone": true, + "dragon_egg": true, + "redstone_lamp": true, + "cocoa": true, + "sandstone_stairs": true, + "emerald_ore": true, + "ender_chest": true, + "tripwire_hook": true, + "tripwire": true, + "emerald_block": true, + "spruce_stairs": true, + "birch_stairs": true, + "jungle_stairs": true, + "command_block": false, + "beacon": true, + "cobblestone_wall": true, + "mossy_cobblestone_wall": true, + "flower_pot": true, + "potted_oak_sapling": true, + "potted_spruce_sapling": true, + "potted_birch_sapling": true, + "potted_jungle_sapling": true, + "potted_acacia_sapling": true, + "potted_dark_oak_sapling": true, + "potted_fern": true, + "potted_dandelion": true, + "potted_poppy": true, + "potted_blue_orchid": true, + "potted_allium": true, + "potted_azure_bluet": true, + "potted_red_tulip": true, + "potted_orange_tulip": true, + "potted_white_tulip": true, + "potted_pink_tulip": true, + "potted_oxeye_daisy": true, + "potted_red_mushroom": true, + "potted_brown_mushroom": true, + "potted_dead_bush": true, + "potted_cactus": true, + "carrots": true, + "potatoes": true, + "oak_button": true, + "spruce_button": true, + "birch_button": true, + "jungle_button": true, + "acacia_button": true, + "dark_oak_button": true, + "skeleton_wall_skull": true, + "skeleton_skull": true, + "wither_skeleton_wall_skull": true, + "wither_skeleton_skull": true, + "zombie_wall_head": true, + "zombie_head": true, + "player_wall_head": true, + "player_head": true, + "creeper_wall_head": true, + "creeper_head": true, + "dragon_wall_head": true, + "dragon_head": true, + "anvil": true, + "chipped_anvil": true, + "damaged_anvil": true, + "trapped_chest": true, + "light_weighted_pressure_plate": true, + "heavy_weighted_pressure_plate": true, + "comparator": true, + "daylight_detector": true, + "redstone_block": true, + "nether_quartz_ore": true, + "hopper": true, + "quartz_block": true, + "chiseled_quartz_block": true, + "quartz_pillar": true, + "quartz_stairs": true, + "activator_rail": true, + "dropper": true, + "white_terracotta": true, + "orange_terracotta": true, + "magenta_terracotta": true, + "light_blue_terracotta": true, + "yellow_terracotta": true, + "lime_terracotta": true, + "pink_terracotta": true, + "gray_terracotta": true, + "light_gray_terracotta": true, + "cyan_terracotta": true, + "purple_terracotta": true, + "blue_terracotta": true, + "brown_terracotta": true, + "green_terracotta": true, + "red_terracotta": true, + "black_terracotta": true, + "white_stained_glass_pane": true, + "orange_stained_glass_pane": true, + "magenta_stained_glass_pane": true, + "light_blue_stained_glass_pane": true, + "yellow_stained_glass_pane": true, + "lime_stained_glass_pane": true, + "pink_stained_glass_pane": true, + "gray_stained_glass_pane": true, + "light_gray_stained_glass_pane": true, + "cyan_stained_glass_pane": true, + "purple_stained_glass_pane": true, + "blue_stained_glass_pane": true, + "brown_stained_glass_pane": true, + "green_stained_glass_pane": true, + "red_stained_glass_pane": true, + "black_stained_glass_pane": true, + "acacia_stairs": true, + "dark_oak_stairs": true, + "slime_block": true, + "barrier": false, + "iron_trapdoor": true, + "prismarine": true, + "prismarine_bricks": true, + "dark_prismarine": true, + "prismarine_stairs": true, + "prismarine_brick_stairs": true, + "dark_prismarine_stairs": true, + "prismarine_slab": true, + "prismarine_brick_slab": true, + "dark_prismarine_slab": true, + "sea_lantern": true, + "hay_block": true, + "white_carpet": true, + "orange_carpet": true, + "magenta_carpet": true, + "light_blue_carpet": true, + "yellow_carpet": true, + "lime_carpet": true, + "pink_carpet": true, + "gray_carpet": true, + "light_gray_carpet": true, + "cyan_carpet": true, + "purple_carpet": true, + "blue_carpet": true, + "brown_carpet": true, + "green_carpet": true, + "red_carpet": true, + "black_carpet": true, + "terracotta": true, + "coal_block": true, + "packed_ice": true, + "sunflower": true, + "lilac": true, + "rose_bush": true, + "peony": true, + "tall_grass": true, + "large_fern": true, + "white_banner": true, + "orange_banner": true, + "magenta_banner": true, + "light_blue_banner": true, + "yellow_banner": true, + "lime_banner": true, + "pink_banner": true, + "gray_banner": true, + "light_gray_banner": true, + "cyan_banner": true, + "purple_banner": true, + "blue_banner": true, + "brown_banner": true, + "green_banner": true, + "red_banner": true, + "black_banner": true, + "white_wall_banner": true, + "orange_wall_banner": true, + "magenta_wall_banner": true, + "light_blue_wall_banner": true, + "yellow_wall_banner": true, + "lime_wall_banner": true, + "pink_wall_banner": true, + "gray_wall_banner": true, + "light_gray_wall_banner": true, + "cyan_wall_banner": true, + "purple_wall_banner": true, + "blue_wall_banner": true, + "brown_wall_banner": true, + "green_wall_banner": true, + "red_wall_banner": true, + "black_wall_banner": true, + "red_sandstone": true, + "chiseled_red_sandstone": true, + "cut_red_sandstone": true, + "red_sandstone_stairs": true, + "oak_slab": true, + "spruce_slab": true, + "birch_slab": true, + "jungle_slab": true, + "acacia_slab": true, + "dark_oak_slab": true, + "stone_slab": true, + "sandstone_slab": true, + "petrified_oak_slab": true, + "cobblestone_slab": true, + "brick_slab": true, + "stone_brick_slab": true, + "nether_brick_slab": true, + "quartz_slab": true, + "red_sandstone_slab": true, + "purpur_slab": true, + "smooth_stone": true, + "smooth_sandstone": true, + "smooth_quartz": true, + "smooth_red_sandstone": true, + "spruce_fence_gate": true, + "birch_fence_gate": true, + "jungle_fence_gate": true, + "acacia_fence_gate": true, + "dark_oak_fence_gate": true, + "spruce_fence": true, + "birch_fence": true, + "jungle_fence": true, + "acacia_fence": true, + "dark_oak_fence": true, + "spruce_door": true, + "birch_door": true, + "jungle_door": true, + "acacia_door": true, + "dark_oak_door": true, + "end_rod": true, + "chorus_plant": true, + "chorus_flower": true, + "purpur_block": true, + "purpur_pillar": true, + "purpur_stairs": true, + "end_stone_bricks": true, + "beetroots": true, + "grass_path": true, + "end_gateway": false, + "repeating_command_block": false, + "chain_command_block": false, + "frosted_ice": true, + "magma_block": true, + "nether_wart_block": true, + "red_nether_bricks": true, + "bone_block": true, + "structure_void": true, + "observer": true, + "shulker_box": true, + "white_shulker_box": true, + "orange_shulker_box": true, + "magenta_shulker_box": true, + "light_blue_shulker_box": true, + "yellow_shulker_box": true, + "lime_shulker_box": true, + "pink_shulker_box": true, + "gray_shulker_box": true, + "light_gray_shulker_box": true, + "cyan_shulker_box": true, + "purple_shulker_box": true, + "blue_shulker_box": true, + "brown_shulker_box": true, + "green_shulker_box": true, + "red_shulker_box": true, + "black_shulker_box": true, + "white_glazed_terracotta": true, + "orange_glazed_terracotta": true, + "magenta_glazed_terracotta": true, + "light_blue_glazed_terracotta": true, + "yellow_glazed_terracotta": true, + "lime_glazed_terracotta": true, + "pink_glazed_terracotta": true, + "gray_glazed_terracotta": true, + "light_gray_glazed_terracotta": true, + "cyan_glazed_terracotta": true, + "purple_glazed_terracotta": true, + "blue_glazed_terracotta": true, + "brown_glazed_terracotta": true, + "green_glazed_terracotta": true, + "red_glazed_terracotta": true, + "black_glazed_terracotta": true, + "white_concrete": true, + "orange_concrete": true, + "magenta_concrete": true, + "light_blue_concrete": true, + "yellow_concrete": true, + "lime_concrete": true, + "pink_concrete": true, + "gray_concrete": true, + "light_gray_concrete": true, + "cyan_concrete": true, + "purple_concrete": true, + "blue_concrete": true, + "brown_concrete": true, + "green_concrete": true, + "red_concrete": true, + "black_concrete": true, + "white_concrete_powder": true, + "orange_concrete_powder": true, + "magenta_concrete_powder": true, + "light_blue_concrete_powder": true, + "yellow_concrete_powder": true, + "lime_concrete_powder": true, + "pink_concrete_powder": true, + "gray_concrete_powder": true, + "light_gray_concrete_powder": true, + "cyan_concrete_powder": true, + "purple_concrete_powder": true, + "blue_concrete_powder": true, + "brown_concrete_powder": true, + "green_concrete_powder": true, + "red_concrete_powder": true, + "black_concrete_powder": true, + "kelp": true, + "kelp_plant": true, + "dried_kelp_block": true, + "turtle_egg": true, + "dead_tube_coral_block": true, + "dead_brain_coral_block": true, + "dead_bubble_coral_block": true, + "dead_fire_coral_block": true, + "dead_horn_coral_block": true, + "tube_coral_block": true, + "brain_coral_block": true, + "bubble_coral_block": true, + "fire_coral_block": true, + "horn_coral_block": true, + "dead_tube_coral": true, + "dead_brain_coral": true, + "dead_bubble_coral": true, + "dead_fire_coral": true, + "dead_horn_coral": true, + "tube_coral": true, + "brain_coral": true, + "bubble_coral": true, + "fire_coral": true, + "horn_coral": true, + "dead_tube_coral_wall_fan": true, + "dead_brain_coral_wall_fan": true, + "dead_bubble_coral_wall_fan": true, + "dead_fire_coral_wall_fan": true, + "dead_horn_coral_wall_fan": true, + "tube_coral_wall_fan": true, + "brain_coral_wall_fan": true, + "bubble_coral_wall_fan": true, + "fire_coral_wall_fan": true, + "horn_coral_wall_fan": true, + "dead_tube_coral_fan": true, + "dead_brain_coral_fan": true, + "dead_bubble_coral_fan": true, + "dead_fire_coral_fan": true, + "dead_horn_coral_fan": true, + "tube_coral_fan": true, + "brain_coral_fan": true, + "bubble_coral_fan": true, + "fire_coral_fan": true, + "horn_coral_fan": true, + "sea_pickle": true, + "blue_ice": true, + "conduit": true, + "void_air": true, + "cave_air": true, + "bubble_column": true, + "structure_block": false, + }, + ), + Property( + on: "block_kind", + name: "hardness", + reverse: false, + type: f64, + mapping: { + "air": 0, + "stone": 1.5, + "granite": 1.5, + "polished_granite": 1.5, + "diorite": 1.5, + "polished_diorite": 1.5, + "andesite": 1.5, + "polished_andesite": 1.5, + "grass_block": 0.6, + "dirt": 0.5, + "coarse_dirt": 0.5, + "podzol": 0.5, + "cobblestone": 2, + "oak_planks": 2, + "spruce_planks": 2, + "birch_planks": 2, + "jungle_planks": 2, + "acacia_planks": 2, + "dark_oak_planks": 2, + "oak_sapling": 0, + "spruce_sapling": 0, + "birch_sapling": 0, + "jungle_sapling": 0, + "acacia_sapling": 0, + "dark_oak_sapling": 0, + "bedrock": 0, + "water": 100, + "lava": 100, + "sand": 0.5, + "red_sand": 0.5, + "gravel": 0.6, + "gold_ore": 3, + "iron_ore": 3, + "coal_ore": 3, + "oak_log": 2, + "spruce_log": 2, + "birch_log": 2, + "jungle_log": 2, + "acacia_log": 2, + "dark_oak_log": 2, + "stripped_spruce_log": 2, + "stripped_birch_log": 2, + "stripped_jungle_log": 2, + "stripped_acacia_log": 2, + "stripped_dark_oak_log": 2, + "stripped_oak_log": 2, + "oak_wood": 2, + "spruce_wood": 2, + "birch_wood": 2, + "jungle_wood": 2, + "acacia_wood": 2, + "dark_oak_wood": 2, + "stripped_oak_wood": 2, + "stripped_spruce_wood": 2, + "stripped_birch_wood": 2, + "stripped_jungle_wood": 2, + "stripped_acacia_wood": 2, + "stripped_dark_oak_wood": 2, + "oak_leaves": 0.2, + "spruce_leaves": 0.2, + "birch_leaves": 0.2, + "jungle_leaves": 0.2, + "acacia_leaves": 0.2, + "dark_oak_leaves": 0.2, + "sponge": 0.6, + "wet_sponge": 0.6, + "glass": 0.3, + "lapis_ore": 3, + "lapis_block": 3, + "dispenser": 3.5, + "sandstone": 0.8, + "chiseled_sandstone": 0.8, + "cut_sandstone": 0.8, + "note_block": 0.8, + "white_bed": 0.2, + "orange_bed": 0.2, + "magenta_bed": 0.2, + "light_blue_bed": 0.2, + "yellow_bed": 0.2, + "lime_bed": 0.2, + "pink_bed": 0.2, + "gray_bed": 0.2, + "light_gray_bed": 0.2, + "cyan_bed": 0.2, + "purple_bed": 0.2, + "blue_bed": 0.2, + "brown_bed": 0.2, + "green_bed": 0.2, + "red_bed": 0.2, + "black_bed": 0.2, + "powered_rail": 0.7, + "detector_rail": 0.7, + "sticky_piston": 0.5, + "cobweb": 4, + "grass": 0, + "fern": 0, + "dead_bush": 0, + "seagrass": 0, + "tall_seagrass": 0, + "piston": 0.5, + "piston_head": 0.5, + "white_wool": 0.8, + "orange_wool": 0.8, + "magenta_wool": 0.8, + "light_blue_wool": 0.8, + "yellow_wool": 0.8, + "lime_wool": 0.8, + "pink_wool": 0.8, + "gray_wool": 0.8, + "light_gray_wool": 0.8, + "cyan_wool": 0.8, + "purple_wool": 0.8, + "blue_wool": 0.8, + "brown_wool": 0.8, + "green_wool": 0.8, + "red_wool": 0.8, + "black_wool": 0.8, + "moving_piston": 0, + "dandelion": 0, + "poppy": 0, + "blue_orchid": 0, + "allium": 0, + "azure_bluet": 0, + "red_tulip": 0, + "orange_tulip": 0, + "white_tulip": 0, + "pink_tulip": 0, + "oxeye_daisy": 0, + "brown_mushroom": 0, + "red_mushroom": 0, + "gold_block": 3, + "iron_block": 5, + "bricks": 2, + "tnt": 0, + "bookshelf": 1.5, + "mossy_cobblestone": 2, + "obsidian": 50, + "torch": 0, + "wall_torch": 0, + "fire": 0, + "spawner": 5, + "oak_stairs": 2, + "chest": 2.5, + "redstone_wire": 0, + "diamond_ore": 3, + "diamond_block": 5, + "crafting_table": 2.5, + "wheat": 0, + "farmland": 0.6, + "furnace": 3.5, + "sign": 1, + "oak_door": 3, + "ladder": 0.4, + "rail": 0.7, + "cobblestone_stairs": 2, + "wall_sign": 1, + "lever": 0.5, + "stone_pressure_plate": 0.5, + "iron_door": 5, + "oak_pressure_plate": 0.5, + "spruce_pressure_plate": 0.5, + "birch_pressure_plate": 0.5, + "jungle_pressure_plate": 0.5, + "acacia_pressure_plate": 0.5, + "dark_oak_pressure_plate": 0.5, + "redstone_ore": 3, + "redstone_torch": 0, + "redstone_wall_torch": 0, + "stone_button": 0.5, + "snow": 0.1, + "ice": 0.5, + "snow_block": 0.2, + "cactus": 0.4, + "clay": 0.6, + "sugar_cane": 0, + "jukebox": 2, + "oak_fence": 2, + "pumpkin": 1, + "netherrack": 0.4, + "soul_sand": 0.5, + "glowstone": 0.3, + "nether_portal": 0, + "carved_pumpkin": 1, + "jack_o_lantern": 1, + "cake": 0.5, + "repeater": 0, + "white_stained_glass": 0.3, + "orange_stained_glass": 0.3, + "magenta_stained_glass": 0.3, + "light_blue_stained_glass": 0.3, + "yellow_stained_glass": 0.3, + "lime_stained_glass": 0.3, + "pink_stained_glass": 0.3, + "gray_stained_glass": 0.3, + "light_gray_stained_glass": 0.3, + "cyan_stained_glass": 0.3, + "purple_stained_glass": 0.3, + "blue_stained_glass": 0.3, + "brown_stained_glass": 0.3, + "green_stained_glass": 0.3, + "red_stained_glass": 0.3, + "black_stained_glass": 0.3, + "oak_trapdoor": 3, + "spruce_trapdoor": 3, + "birch_trapdoor": 3, + "jungle_trapdoor": 3, + "acacia_trapdoor": 3, + "dark_oak_trapdoor": 3, + "infested_stone": 0, + "infested_cobblestone": 0, + "infested_stone_bricks": 0, + "infested_mossy_stone_bricks": 0, + "infested_cracked_stone_bricks": 0, + "infested_chiseled_stone_bricks": 0, + "stone_bricks": 1.5, + "mossy_stone_bricks": 1.5, + "cracked_stone_bricks": 1.5, + "chiseled_stone_bricks": 1.5, + "brown_mushroom_block": 0.2, + "red_mushroom_block": 0.2, + "mushroom_stem": 0.2, + "iron_bars": 5, + "glass_pane": 0.3, + "melon": 1, + "attached_pumpkin_stem": 0, + "attached_melon_stem": 0, + "pumpkin_stem": 0, + "melon_stem": 0, + "vine": 0.2, + "oak_fence_gate": 2, + "brick_stairs": 2, + "stone_brick_stairs": 1.5, + "mycelium": 0.6, + "lily_pad": 0, + "nether_bricks": 2, + "nether_brick_fence": 2, + "nether_brick_stairs": 2, + "nether_wart": 0, + "enchanting_table": 5, + "brewing_stand": 0.5, + "cauldron": 2, + "end_portal": 0, + "end_portal_frame": 0, + "end_stone": 3, + "dragon_egg": 3, + "redstone_lamp": 0.3, + "cocoa": 0.2, + "sandstone_stairs": 0.8, + "emerald_ore": 3, + "ender_chest": 22.5, + "tripwire_hook": 0, + "tripwire": 0, + "emerald_block": 5, + "spruce_stairs": 2, + "birch_stairs": 2, + "jungle_stairs": 2, + "command_block": 0, + "beacon": 3, + "cobblestone_wall": 2, + "mossy_cobblestone_wall": 2, + "flower_pot": 0, + "potted_oak_sapling": 0, + "potted_spruce_sapling": 0, + "potted_birch_sapling": 0, + "potted_jungle_sapling": 0, + "potted_acacia_sapling": 0, + "potted_dark_oak_sapling": 0, + "potted_fern": 0, + "potted_dandelion": 0, + "potted_poppy": 0, + "potted_blue_orchid": 0, + "potted_allium": 0, + "potted_azure_bluet": 0, + "potted_red_tulip": 0, + "potted_orange_tulip": 0, + "potted_white_tulip": 0, + "potted_pink_tulip": 0, + "potted_oxeye_daisy": 0, + "potted_red_mushroom": 0, + "potted_brown_mushroom": 0, + "potted_dead_bush": 0, + "potted_cactus": 0, + "carrots": 0, + "potatoes": 0, + "oak_button": 0.5, + "spruce_button": 0.5, + "birch_button": 0.5, + "jungle_button": 0.5, + "acacia_button": 0.5, + "dark_oak_button": 0.5, + "skeleton_wall_skull": 1, + "skeleton_skull": 1, + "wither_skeleton_wall_skull": 1, + "wither_skeleton_skull": 1, + "zombie_wall_head": 1, + "zombie_head": 1, + "player_wall_head": 1, + "player_head": 1, + "creeper_wall_head": 1, + "creeper_head": 1, + "dragon_wall_head": 1, + "dragon_head": 1, + "anvil": 5, + "chipped_anvil": 5, + "damaged_anvil": 5, + "trapped_chest": 2.5, + "light_weighted_pressure_plate": 0.5, + "heavy_weighted_pressure_plate": 0.5, + "comparator": 0, + "daylight_detector": 0.2, + "redstone_block": 5, + "nether_quartz_ore": 3, + "hopper": 3, + "quartz_block": 0.8, + "chiseled_quartz_block": 0.8, + "quartz_pillar": 0.8, + "quartz_stairs": 0.8, + "activator_rail": 0.7, + "dropper": 3.5, + "white_terracotta": 1.25, + "orange_terracotta": 1.25, + "magenta_terracotta": 1.25, + "light_blue_terracotta": 1.25, + "yellow_terracotta": 1.25, + "lime_terracotta": 1.25, + "pink_terracotta": 1.25, + "gray_terracotta": 1.25, + "light_gray_terracotta": 1.25, + "cyan_terracotta": 1.25, + "purple_terracotta": 1.25, + "blue_terracotta": 1.25, + "brown_terracotta": 1.25, + "green_terracotta": 1.25, + "red_terracotta": 1.25, + "black_terracotta": 1.25, + "white_stained_glass_pane": 0.3, + "orange_stained_glass_pane": 0.3, + "magenta_stained_glass_pane": 0.3, + "light_blue_stained_glass_pane": 0.3, + "yellow_stained_glass_pane": 0.3, + "lime_stained_glass_pane": 0.3, + "pink_stained_glass_pane": 0.3, + "gray_stained_glass_pane": 0.3, + "light_gray_stained_glass_pane": 0.3, + "cyan_stained_glass_pane": 0.3, + "purple_stained_glass_pane": 0.3, + "blue_stained_glass_pane": 0.3, + "brown_stained_glass_pane": 0.3, + "green_stained_glass_pane": 0.3, + "red_stained_glass_pane": 0.3, + "black_stained_glass_pane": 0.3, + "acacia_stairs": 2, + "dark_oak_stairs": 2, + "slime_block": 0, + "barrier": 0, + "iron_trapdoor": 5, + "prismarine": 1.5, + "prismarine_bricks": 1.5, + "dark_prismarine": 1.5, + "prismarine_stairs": 1.5, + "prismarine_brick_stairs": 1.5, + "dark_prismarine_stairs": 1.5, + "prismarine_slab": 1.5, + "prismarine_brick_slab": 1.5, + "dark_prismarine_slab": 1.5, + "sea_lantern": 0.3, + "hay_block": 0.5, + "white_carpet": 0.1, + "orange_carpet": 0.1, + "magenta_carpet": 0.1, + "light_blue_carpet": 0.1, + "yellow_carpet": 0.1, + "lime_carpet": 0.1, + "pink_carpet": 0.1, + "gray_carpet": 0.1, + "light_gray_carpet": 0.1, + "cyan_carpet": 0.1, + "purple_carpet": 0.1, + "blue_carpet": 0.1, + "brown_carpet": 0.1, + "green_carpet": 0.1, + "red_carpet": 0.1, + "black_carpet": 0.1, + "terracotta": 1.25, + "coal_block": 5, + "packed_ice": 0.5, + "sunflower": 0, + "lilac": 0, + "rose_bush": 0, + "peony": 0, + "tall_grass": 0, + "large_fern": 0, + "white_banner": 1, + "orange_banner": 1, + "magenta_banner": 1, + "light_blue_banner": 1, + "yellow_banner": 1, + "lime_banner": 1, + "pink_banner": 1, + "gray_banner": 1, + "light_gray_banner": 1, + "cyan_banner": 1, + "purple_banner": 1, + "blue_banner": 1, + "brown_banner": 1, + "green_banner": 1, + "red_banner": 1, + "black_banner": 1, + "white_wall_banner": 1, + "orange_wall_banner": 1, + "magenta_wall_banner": 1, + "light_blue_wall_banner": 1, + "yellow_wall_banner": 1, + "lime_wall_banner": 1, + "pink_wall_banner": 1, + "gray_wall_banner": 1, + "light_gray_wall_banner": 1, + "cyan_wall_banner": 1, + "purple_wall_banner": 1, + "blue_wall_banner": 1, + "brown_wall_banner": 1, + "green_wall_banner": 1, + "red_wall_banner": 1, + "black_wall_banner": 1, + "red_sandstone": 0.8, + "chiseled_red_sandstone": 0.8, + "cut_red_sandstone": 0.8, + "red_sandstone_stairs": 0.8, + "oak_slab": 2, + "spruce_slab": 2, + "birch_slab": 2, + "jungle_slab": 2, + "acacia_slab": 2, + "dark_oak_slab": 2, + "stone_slab": 2, + "sandstone_slab": 2, + "petrified_oak_slab": 2, + "cobblestone_slab": 2, + "brick_slab": 2, + "stone_brick_slab": 2, + "nether_brick_slab": 2, + "quartz_slab": 2, + "red_sandstone_slab": 2, + "purpur_slab": 2, + "smooth_stone": 2, + "smooth_sandstone": 2, + "smooth_quartz": 2, + "smooth_red_sandstone": 2, + "spruce_fence_gate": 2, + "birch_fence_gate": 2, + "jungle_fence_gate": 2, + "acacia_fence_gate": 2, + "dark_oak_fence_gate": 2, + "spruce_fence": 2, + "birch_fence": 2, + "jungle_fence": 2, + "acacia_fence": 2, + "dark_oak_fence": 2, + "spruce_door": 3, + "birch_door": 3, + "jungle_door": 3, + "acacia_door": 3, + "dark_oak_door": 3, + "end_rod": 0, + "chorus_plant": 0.4, + "chorus_flower": 0.4, + "purpur_block": 1.5, + "purpur_pillar": 1.5, + "purpur_stairs": 1.5, + "end_stone_bricks": 0.8, + "beetroots": 0, + "grass_path": 0.65, + "end_gateway": 0, + "repeating_command_block": 0, + "chain_command_block": 0, + "frosted_ice": 0.5, + "magma_block": 0.5, + "nether_wart_block": 1, + "red_nether_bricks": 2, + "bone_block": 2, + "structure_void": 0, + "observer": 3, + "shulker_box": 2, + "white_shulker_box": 2, + "orange_shulker_box": 2, + "magenta_shulker_box": 2, + "light_blue_shulker_box": 2, + "yellow_shulker_box": 2, + "lime_shulker_box": 2, + "pink_shulker_box": 2, + "gray_shulker_box": 2, + "light_gray_shulker_box": 2, + "cyan_shulker_box": 2, + "purple_shulker_box": 2, + "blue_shulker_box": 2, + "brown_shulker_box": 2, + "green_shulker_box": 2, + "red_shulker_box": 2, + "black_shulker_box": 2, + "white_glazed_terracotta": 1.4, + "orange_glazed_terracotta": 1.4, + "magenta_glazed_terracotta": 1.4, + "light_blue_glazed_terracotta": 1.4, + "yellow_glazed_terracotta": 1.4, + "lime_glazed_terracotta": 1.4, + "pink_glazed_terracotta": 1.4, + "gray_glazed_terracotta": 1.4, + "light_gray_glazed_terracotta": 1.4, + "cyan_glazed_terracotta": 1.4, + "purple_glazed_terracotta": 1.4, + "blue_glazed_terracotta": 1.4, + "brown_glazed_terracotta": 1.4, + "green_glazed_terracotta": 1.4, + "red_glazed_terracotta": 1.4, + "black_glazed_terracotta": 1.4, + "white_concrete": 1.8, + "orange_concrete": 1.8, + "magenta_concrete": 1.8, + "light_blue_concrete": 1.8, + "yellow_concrete": 1.8, + "lime_concrete": 1.8, + "pink_concrete": 1.8, + "gray_concrete": 1.8, + "light_gray_concrete": 1.8, + "cyan_concrete": 1.8, + "purple_concrete": 1.8, + "blue_concrete": 1.8, + "brown_concrete": 1.8, + "green_concrete": 1.8, + "red_concrete": 1.8, + "black_concrete": 1.8, + "white_concrete_powder": 0.5, + "orange_concrete_powder": 0.5, + "magenta_concrete_powder": 0.5, + "light_blue_concrete_powder": 0.5, + "yellow_concrete_powder": 0.5, + "lime_concrete_powder": 0.5, + "pink_concrete_powder": 0.5, + "gray_concrete_powder": 0.5, + "light_gray_concrete_powder": 0.5, + "cyan_concrete_powder": 0.5, + "purple_concrete_powder": 0.5, + "blue_concrete_powder": 0.5, + "brown_concrete_powder": 0.5, + "green_concrete_powder": 0.5, + "red_concrete_powder": 0.5, + "black_concrete_powder": 0.5, + "kelp": 0, + "kelp_plant": 0, + "dried_kelp_block": 0.5, + "turtle_egg": 0.5, + "dead_tube_coral_block": 1.5, + "dead_brain_coral_block": 1.5, + "dead_bubble_coral_block": 1.5, + "dead_fire_coral_block": 1.5, + "dead_horn_coral_block": 1.5, + "tube_coral_block": 1.5, + "brain_coral_block": 1.5, + "bubble_coral_block": 1.5, + "fire_coral_block": 1.5, + "horn_coral_block": 1.5, + "dead_tube_coral": 0, + "dead_brain_coral": 0, + "dead_bubble_coral": 0, + "dead_fire_coral": 0, + "dead_horn_coral": 0, + "tube_coral": 0, + "brain_coral": 0, + "bubble_coral": 0, + "fire_coral": 0, + "horn_coral": 0, + "dead_tube_coral_wall_fan": 0, + "dead_brain_coral_wall_fan": 0, + "dead_bubble_coral_wall_fan": 0, + "dead_fire_coral_wall_fan": 0, + "dead_horn_coral_wall_fan": 0, + "tube_coral_wall_fan": 0, + "brain_coral_wall_fan": 0, + "bubble_coral_wall_fan": 0, + "fire_coral_wall_fan": 0, + "horn_coral_wall_fan": 0, + "dead_tube_coral_fan": 0, + "dead_brain_coral_fan": 0, + "dead_bubble_coral_fan": 0, + "dead_fire_coral_fan": 0, + "dead_horn_coral_fan": 0, + "tube_coral_fan": 0, + "brain_coral_fan": 0, + "bubble_coral_fan": 0, + "fire_coral_fan": 0, + "horn_coral_fan": 0, + "sea_pickle": 0, + "blue_ice": 2.8, + "conduit": 3, + "void_air": 0, + "cave_air": 0, + "bubble_column": 0, + "structure_block": 0, + }, + ), + Property( + on: "block_kind", + name: "opaque", + reverse: false, + type: bool, + mapping: { + "air": false, + "stone": true, + "granite": true, + "polished_granite": true, + "diorite": true, + "polished_diorite": true, + "andesite": true, + "polished_andesite": true, + "grass_block": true, + "dirt": true, + "coarse_dirt": true, + "podzol": true, + "cobblestone": true, + "oak_planks": true, + "spruce_planks": true, + "birch_planks": true, + "jungle_planks": true, + "acacia_planks": true, + "dark_oak_planks": true, + "oak_sapling": false, + "spruce_sapling": false, + "birch_sapling": false, + "jungle_sapling": false, + "acacia_sapling": false, + "dark_oak_sapling": false, + "bedrock": true, + "water": false, + "lava": false, + "sand": true, + "red_sand": true, + "gravel": true, + "gold_ore": true, + "iron_ore": true, + "coal_ore": true, + "oak_log": true, + "spruce_log": true, + "birch_log": true, + "jungle_log": true, + "acacia_log": true, + "dark_oak_log": true, + "stripped_spruce_log": true, + "stripped_birch_log": true, + "stripped_jungle_log": true, + "stripped_acacia_log": true, + "stripped_dark_oak_log": true, + "stripped_oak_log": true, + "oak_wood": true, + "spruce_wood": true, + "birch_wood": true, + "jungle_wood": true, + "acacia_wood": true, + "dark_oak_wood": true, + "stripped_oak_wood": true, + "stripped_spruce_wood": true, + "stripped_birch_wood": true, + "stripped_jungle_wood": true, + "stripped_acacia_wood": true, + "stripped_dark_oak_wood": true, + "oak_leaves": false, + "spruce_leaves": false, + "birch_leaves": false, + "jungle_leaves": false, + "acacia_leaves": false, + "dark_oak_leaves": false, + "sponge": true, + "wet_sponge": true, + "glass": false, + "lapis_ore": true, + "lapis_block": true, + "dispenser": true, + "sandstone": true, + "chiseled_sandstone": true, + "cut_sandstone": true, + "note_block": true, + "white_bed": false, + "orange_bed": false, + "magenta_bed": false, + "light_blue_bed": false, + "yellow_bed": false, + "lime_bed": false, + "pink_bed": false, + "gray_bed": false, + "light_gray_bed": false, + "cyan_bed": false, + "purple_bed": false, + "blue_bed": false, + "brown_bed": false, + "green_bed": false, + "red_bed": false, + "black_bed": false, + "powered_rail": false, + "detector_rail": false, + "sticky_piston": false, + "cobweb": false, + "grass": true, + "fern": false, + "dead_bush": false, + "seagrass": false, + "tall_seagrass": false, + "piston": false, + "piston_head": false, + "white_wool": true, + "orange_wool": true, + "magenta_wool": true, + "light_blue_wool": true, + "yellow_wool": true, + "lime_wool": true, + "pink_wool": true, + "gray_wool": true, + "light_gray_wool": true, + "cyan_wool": true, + "purple_wool": true, + "blue_wool": true, + "brown_wool": true, + "green_wool": true, + "red_wool": true, + "black_wool": true, + "moving_piston": false, + "dandelion": true, + "poppy": true, + "blue_orchid": false, + "allium": true, + "azure_bluet": true, + "red_tulip": false, + "orange_tulip": false, + "white_tulip": false, + "pink_tulip": false, + "oxeye_daisy": true, + "brown_mushroom": true, + "red_mushroom": true, + "gold_block": true, + "iron_block": true, + "bricks": true, + "tnt": false, + "bookshelf": true, + "mossy_cobblestone": true, + "obsidian": true, + "torch": false, + "wall_torch": false, + "fire": false, + "spawner": false, + "oak_stairs": false, + "chest": false, + "redstone_wire": false, + "diamond_ore": true, + "diamond_block": true, + "crafting_table": true, + "wheat": false, + "farmland": false, + "furnace": false, + "sign": false, + "oak_door": false, + "ladder": false, + "rail": false, + "cobblestone_stairs": false, + "wall_sign": false, + "lever": false, + "stone_pressure_plate": false, + "iron_door": false, + "oak_pressure_plate": false, + "spruce_pressure_plate": false, + "birch_pressure_plate": false, + "jungle_pressure_plate": false, + "acacia_pressure_plate": false, + "dark_oak_pressure_plate": false, + "redstone_ore": false, + "redstone_torch": false, + "redstone_wall_torch": false, + "stone_button": false, + "snow": true, + "ice": false, + "snow_block": true, + "cactus": false, + "clay": true, + "sugar_cane": false, + "jukebox": true, + "oak_fence": false, + "pumpkin": false, + "netherrack": true, + "soul_sand": true, + "glowstone": false, + "nether_portal": false, + "carved_pumpkin": false, + "jack_o_lantern": false, + "cake": false, + "repeater": false, + "white_stained_glass": false, + "orange_stained_glass": false, + "magenta_stained_glass": false, + "light_blue_stained_glass": false, + "yellow_stained_glass": false, + "lime_stained_glass": false, + "pink_stained_glass": false, + "gray_stained_glass": false, + "light_gray_stained_glass": false, + "cyan_stained_glass": false, + "purple_stained_glass": false, + "blue_stained_glass": false, + "brown_stained_glass": false, + "green_stained_glass": false, + "red_stained_glass": false, + "black_stained_glass": false, + "oak_trapdoor": false, + "spruce_trapdoor": false, + "birch_trapdoor": false, + "jungle_trapdoor": false, + "acacia_trapdoor": false, + "dark_oak_trapdoor": false, + "infested_stone": true, + "infested_cobblestone": true, + "infested_stone_bricks": true, + "infested_mossy_stone_bricks": true, + "infested_cracked_stone_bricks": true, + "infested_chiseled_stone_bricks": true, + "stone_bricks": true, + "mossy_stone_bricks": true, + "cracked_stone_bricks": true, + "chiseled_stone_bricks": true, + "brown_mushroom_block": true, + "red_mushroom_block": true, + "mushroom_stem": true, + "iron_bars": false, + "glass_pane": false, + "melon": false, + "attached_pumpkin_stem": false, + "attached_melon_stem": false, + "pumpkin_stem": false, + "melon_stem": false, + "vine": false, + "oak_fence_gate": false, + "brick_stairs": false, + "stone_brick_stairs": false, + "mycelium": true, + "lily_pad": false, + "nether_bricks": true, + "nether_brick_fence": false, + "nether_brick_stairs": false, + "nether_wart": false, + "enchanting_table": false, + "brewing_stand": false, + "cauldron": false, + "end_portal": false, + "end_portal_frame": false, + "end_stone": true, + "dragon_egg": false, + "redstone_lamp": false, + "cocoa": false, + "sandstone_stairs": false, + "emerald_ore": true, + "ender_chest": false, + "tripwire_hook": false, + "tripwire": false, + "emerald_block": true, + "spruce_stairs": false, + "birch_stairs": false, + "jungle_stairs": false, + "command_block": true, + "beacon": false, + "cobblestone_wall": false, + "mossy_cobblestone_wall": false, + "flower_pot": false, + "potted_oak_sapling": false, + "potted_spruce_sapling": false, + "potted_birch_sapling": false, + "potted_jungle_sapling": false, + "potted_acacia_sapling": false, + "potted_dark_oak_sapling": false, + "potted_fern": false, + "potted_dandelion": false, + "potted_poppy": false, + "potted_blue_orchid": false, + "potted_allium": false, + "potted_azure_bluet": false, + "potted_red_tulip": false, + "potted_orange_tulip": false, + "potted_white_tulip": false, + "potted_pink_tulip": false, + "potted_oxeye_daisy": false, + "potted_red_mushroom": false, + "potted_brown_mushroom": false, + "potted_dead_bush": false, + "potted_cactus": false, + "carrots": true, + "potatoes": true, + "oak_button": false, + "spruce_button": false, + "birch_button": false, + "jungle_button": false, + "acacia_button": false, + "dark_oak_button": false, + "skeleton_wall_skull": false, + "skeleton_skull": false, + "wither_skeleton_wall_skull": false, + "wither_skeleton_skull": false, + "zombie_wall_head": false, + "zombie_head": false, + "player_wall_head": false, + "player_head": false, + "creeper_wall_head": false, + "creeper_head": false, + "dragon_wall_head": false, + "dragon_head": false, + "anvil": false, + "chipped_anvil": false, + "damaged_anvil": false, + "trapped_chest": false, + "light_weighted_pressure_plate": false, + "heavy_weighted_pressure_plate": false, + "comparator": false, + "daylight_detector": false, + "redstone_block": false, + "nether_quartz_ore": true, + "hopper": false, + "quartz_block": true, + "chiseled_quartz_block": true, + "quartz_pillar": true, + "quartz_stairs": false, + "activator_rail": false, + "dropper": true, + "white_terracotta": true, + "orange_terracotta": true, + "magenta_terracotta": true, + "light_blue_terracotta": true, + "yellow_terracotta": true, + "lime_terracotta": true, + "pink_terracotta": true, + "gray_terracotta": true, + "light_gray_terracotta": true, + "cyan_terracotta": true, + "purple_terracotta": true, + "blue_terracotta": true, + "brown_terracotta": true, + "green_terracotta": true, + "red_terracotta": true, + "black_terracotta": true, + "white_stained_glass_pane": false, + "orange_stained_glass_pane": false, + "magenta_stained_glass_pane": false, + "light_blue_stained_glass_pane": false, + "yellow_stained_glass_pane": false, + "lime_stained_glass_pane": false, + "pink_stained_glass_pane": false, + "gray_stained_glass_pane": false, + "light_gray_stained_glass_pane": false, + "cyan_stained_glass_pane": false, + "purple_stained_glass_pane": false, + "blue_stained_glass_pane": false, + "brown_stained_glass_pane": false, + "green_stained_glass_pane": false, + "red_stained_glass_pane": false, + "black_stained_glass_pane": false, + "acacia_stairs": false, + "dark_oak_stairs": false, + "slime_block": false, + "barrier": false, + "iron_trapdoor": false, + "prismarine": true, + "prismarine_bricks": true, + "dark_prismarine": true, + "prismarine_stairs": false, + "prismarine_brick_stairs": false, + "dark_prismarine_stairs": false, + "prismarine_slab": false, + "prismarine_brick_slab": false, + "dark_prismarine_slab": false, + "sea_lantern": false, + "hay_block": true, + "white_carpet": false, + "orange_carpet": false, + "magenta_carpet": false, + "light_blue_carpet": false, + "yellow_carpet": false, + "lime_carpet": false, + "pink_carpet": false, + "gray_carpet": false, + "light_gray_carpet": false, + "cyan_carpet": false, + "purple_carpet": false, + "blue_carpet": false, + "brown_carpet": false, + "green_carpet": false, + "red_carpet": false, + "black_carpet": false, + "terracotta": true, + "coal_block": true, + "packed_ice": true, + "sunflower": false, + "lilac": false, + "rose_bush": false, + "peony": true, + "tall_grass": false, + "large_fern": false, + "white_banner": false, + "orange_banner": false, + "magenta_banner": false, + "light_blue_banner": false, + "yellow_banner": false, + "lime_banner": false, + "pink_banner": false, + "gray_banner": false, + "light_gray_banner": false, + "cyan_banner": false, + "purple_banner": false, + "blue_banner": false, + "brown_banner": false, + "green_banner": false, + "red_banner": false, + "black_banner": false, + "white_wall_banner": false, + "orange_wall_banner": false, + "magenta_wall_banner": false, + "light_blue_wall_banner": false, + "yellow_wall_banner": false, + "lime_wall_banner": false, + "pink_wall_banner": false, + "gray_wall_banner": false, + "light_gray_wall_banner": false, + "cyan_wall_banner": false, + "purple_wall_banner": false, + "blue_wall_banner": false, + "brown_wall_banner": false, + "green_wall_banner": false, + "red_wall_banner": false, + "black_wall_banner": false, + "red_sandstone": true, + "chiseled_red_sandstone": true, + "cut_red_sandstone": true, + "red_sandstone_stairs": false, + "oak_slab": false, + "spruce_slab": false, + "birch_slab": false, + "jungle_slab": false, + "acacia_slab": false, + "dark_oak_slab": false, + "stone_slab": false, + "sandstone_slab": false, + "petrified_oak_slab": false, + "cobblestone_slab": false, + "brick_slab": false, + "stone_brick_slab": false, + "nether_brick_slab": false, + "quartz_slab": false, + "red_sandstone_slab": false, + "purpur_slab": false, + "smooth_stone": true, + "smooth_sandstone": true, + "smooth_quartz": true, + "smooth_red_sandstone": true, + "spruce_fence_gate": false, + "birch_fence_gate": false, + "jungle_fence_gate": false, + "acacia_fence_gate": false, + "dark_oak_fence_gate": false, + "spruce_fence": false, + "birch_fence": false, + "jungle_fence": false, + "acacia_fence": false, + "dark_oak_fence": false, + "spruce_door": false, + "birch_door": false, + "jungle_door": false, + "acacia_door": false, + "dark_oak_door": false, + "end_rod": true, + "chorus_plant": false, + "chorus_flower": false, + "purpur_block": true, + "purpur_pillar": true, + "purpur_stairs": false, + "end_stone_bricks": true, + "beetroots": false, + "grass_path": false, + "end_gateway": true, + "repeating_command_block": true, + "chain_command_block": true, + "frosted_ice": false, + "magma_block": true, + "nether_wart_block": true, + "red_nether_bricks": true, + "bone_block": true, + "structure_void": true, + "observer": false, + "shulker_box": false, + "white_shulker_box": false, + "orange_shulker_box": false, + "magenta_shulker_box": false, + "light_blue_shulker_box": false, + "yellow_shulker_box": false, + "lime_shulker_box": false, + "pink_shulker_box": false, + "gray_shulker_box": false, + "light_gray_shulker_box": false, + "cyan_shulker_box": false, + "purple_shulker_box": false, + "blue_shulker_box": false, + "brown_shulker_box": false, + "green_shulker_box": false, + "red_shulker_box": false, + "black_shulker_box": false, + "white_glazed_terracotta": true, + "orange_glazed_terracotta": true, + "magenta_glazed_terracotta": true, + "light_blue_glazed_terracotta": true, + "yellow_glazed_terracotta": true, + "lime_glazed_terracotta": true, + "pink_glazed_terracotta": true, + "gray_glazed_terracotta": true, + "light_gray_glazed_terracotta": true, + "cyan_glazed_terracotta": true, + "purple_glazed_terracotta": true, + "blue_glazed_terracotta": true, + "brown_glazed_terracotta": true, + "green_glazed_terracotta": true, + "red_glazed_terracotta": true, + "black_glazed_terracotta": true, + "white_concrete": true, + "orange_concrete": true, + "magenta_concrete": true, + "light_blue_concrete": true, + "yellow_concrete": true, + "lime_concrete": true, + "pink_concrete": true, + "gray_concrete": true, + "light_gray_concrete": true, + "cyan_concrete": true, + "purple_concrete": true, + "blue_concrete": true, + "brown_concrete": true, + "green_concrete": true, + "red_concrete": true, + "black_concrete": true, + "white_concrete_powder": true, + "orange_concrete_powder": true, + "magenta_concrete_powder": true, + "light_blue_concrete_powder": true, + "yellow_concrete_powder": true, + "lime_concrete_powder": true, + "pink_concrete_powder": true, + "gray_concrete_powder": true, + "light_gray_concrete_powder": true, + "cyan_concrete_powder": true, + "purple_concrete_powder": true, + "blue_concrete_powder": true, + "brown_concrete_powder": true, + "green_concrete_powder": true, + "red_concrete_powder": true, + "black_concrete_powder": true, + "kelp": false, + "kelp_plant": false, + "dried_kelp_block": true, + "turtle_egg": true, + "dead_tube_coral_block": true, + "dead_brain_coral_block": true, + "dead_bubble_coral_block": true, + "dead_fire_coral_block": true, + "dead_horn_coral_block": true, + "tube_coral_block": true, + "brain_coral_block": true, + "bubble_coral_block": true, + "fire_coral_block": true, + "horn_coral_block": true, + "dead_tube_coral": false, + "dead_brain_coral": false, + "dead_bubble_coral": false, + "dead_fire_coral": false, + "dead_horn_coral": false, + "tube_coral": false, + "brain_coral": false, + "bubble_coral": false, + "fire_coral": false, + "horn_coral": false, + "dead_tube_coral_wall_fan": false, + "dead_brain_coral_wall_fan": false, + "dead_bubble_coral_wall_fan": false, + "dead_fire_coral_wall_fan": false, + "dead_horn_coral_wall_fan": false, + "tube_coral_wall_fan": false, + "brain_coral_wall_fan": false, + "bubble_coral_wall_fan": false, + "fire_coral_wall_fan": false, + "horn_coral_wall_fan": false, + "dead_tube_coral_fan": false, + "dead_brain_coral_fan": false, + "dead_bubble_coral_fan": false, + "dead_fire_coral_fan": false, + "dead_horn_coral_fan": false, + "tube_coral_fan": false, + "brain_coral_fan": false, + "bubble_coral_fan": false, + "fire_coral_fan": false, + "horn_coral_fan": false, + "sea_pickle": true, + "blue_ice": true, + "conduit": true, + "void_air": false, + "cave_air": false, + "bubble_column": false, + "structure_block": true, + }, + ), + Property( + on: "block_kind", + name: "solid", + reverse: false, + type: bool, + mapping: { + "air": false, + "stone": true, + "granite": true, + "polished_granite": true, + "diorite": true, + "polished_diorite": true, + "andesite": true, + "polished_andesite": true, + "grass_block": true, + "dirt": true, + "coarse_dirt": true, + "podzol": true, + "cobblestone": true, + "oak_planks": true, + "spruce_planks": true, + "birch_planks": true, + "jungle_planks": true, + "acacia_planks": true, + "dark_oak_planks": true, + "oak_sapling": false, + "spruce_sapling": false, + "birch_sapling": false, + "jungle_sapling": false, + "acacia_sapling": false, + "dark_oak_sapling": false, + "bedrock": true, + "water": false, + "lava": false, + "sand": true, + "red_sand": true, + "gravel": true, + "gold_ore": true, + "iron_ore": true, + "coal_ore": true, + "oak_log": true, + "spruce_log": true, + "birch_log": true, + "jungle_log": true, + "acacia_log": true, + "dark_oak_log": true, + "stripped_spruce_log": true, + "stripped_birch_log": true, + "stripped_jungle_log": true, + "stripped_acacia_log": true, + "stripped_dark_oak_log": true, + "stripped_oak_log": true, + "oak_wood": true, + "spruce_wood": true, + "birch_wood": true, + "jungle_wood": true, + "acacia_wood": true, + "dark_oak_wood": true, + "stripped_oak_wood": true, + "stripped_spruce_wood": true, + "stripped_birch_wood": true, + "stripped_jungle_wood": true, + "stripped_acacia_wood": true, + "stripped_dark_oak_wood": true, + "oak_leaves": true, + "spruce_leaves": true, + "birch_leaves": true, + "jungle_leaves": true, + "acacia_leaves": true, + "dark_oak_leaves": true, + "sponge": true, + "wet_sponge": true, + "glass": true, + "lapis_ore": true, + "lapis_block": true, + "dispenser": true, + "sandstone": true, + "chiseled_sandstone": true, + "cut_sandstone": true, + "note_block": true, + "white_bed": true, + "orange_bed": true, + "magenta_bed": true, + "light_blue_bed": true, + "yellow_bed": true, + "lime_bed": true, + "pink_bed": true, + "gray_bed": true, + "light_gray_bed": true, + "cyan_bed": true, + "purple_bed": true, + "blue_bed": true, + "brown_bed": true, + "green_bed": true, + "red_bed": true, + "black_bed": true, + "powered_rail": false, + "detector_rail": false, + "sticky_piston": true, + "cobweb": false, + "grass": false, + "fern": false, + "dead_bush": false, + "seagrass": false, + "tall_seagrass": false, + "piston": true, + "piston_head": true, + "white_wool": true, + "orange_wool": true, + "magenta_wool": true, + "light_blue_wool": true, + "yellow_wool": true, + "lime_wool": true, + "pink_wool": true, + "gray_wool": true, + "light_gray_wool": true, + "cyan_wool": true, + "purple_wool": true, + "blue_wool": true, + "brown_wool": true, + "green_wool": true, + "red_wool": true, + "black_wool": true, + "moving_piston": false, + "dandelion": false, + "poppy": false, + "blue_orchid": false, + "allium": false, + "azure_bluet": false, + "red_tulip": false, + "orange_tulip": false, + "white_tulip": false, + "pink_tulip": false, + "oxeye_daisy": false, + "brown_mushroom": false, + "red_mushroom": false, + "gold_block": true, + "iron_block": true, + "bricks": true, + "tnt": true, + "bookshelf": true, + "mossy_cobblestone": true, + "obsidian": true, + "torch": false, + "wall_torch": false, + "fire": false, + "spawner": true, + "oak_stairs": true, + "chest": true, + "redstone_wire": false, + "diamond_ore": true, + "diamond_block": true, + "crafting_table": true, + "wheat": false, + "farmland": true, + "furnace": true, + "sign": false, + "oak_door": true, + "ladder": true, + "rail": false, + "cobblestone_stairs": true, + "wall_sign": false, + "lever": false, + "stone_pressure_plate": false, + "iron_door": true, + "oak_pressure_plate": false, + "spruce_pressure_plate": false, + "birch_pressure_plate": false, + "jungle_pressure_plate": false, + "acacia_pressure_plate": false, + "dark_oak_pressure_plate": false, + "redstone_ore": true, + "redstone_torch": false, + "redstone_wall_torch": false, + "stone_button": false, + "snow": true, + "ice": true, + "snow_block": true, + "cactus": true, + "clay": true, + "sugar_cane": false, + "jukebox": true, + "oak_fence": true, + "pumpkin": true, + "netherrack": true, + "soul_sand": true, + "glowstone": true, + "nether_portal": false, + "carved_pumpkin": true, + "jack_o_lantern": true, + "cake": true, + "repeater": true, + "white_stained_glass": true, + "orange_stained_glass": true, + "magenta_stained_glass": true, + "light_blue_stained_glass": true, + "yellow_stained_glass": true, + "lime_stained_glass": true, + "pink_stained_glass": true, + "gray_stained_glass": true, + "light_gray_stained_glass": true, + "cyan_stained_glass": true, + "purple_stained_glass": true, + "blue_stained_glass": true, + "brown_stained_glass": true, + "green_stained_glass": true, + "red_stained_glass": true, + "black_stained_glass": true, + "oak_trapdoor": true, + "spruce_trapdoor": true, + "birch_trapdoor": true, + "jungle_trapdoor": true, + "acacia_trapdoor": true, + "dark_oak_trapdoor": true, + "infested_stone": true, + "infested_cobblestone": true, + "infested_stone_bricks": true, + "infested_mossy_stone_bricks": true, + "infested_cracked_stone_bricks": true, + "infested_chiseled_stone_bricks": true, + "stone_bricks": true, + "mossy_stone_bricks": true, + "cracked_stone_bricks": true, + "chiseled_stone_bricks": true, + "brown_mushroom_block": true, + "red_mushroom_block": true, + "mushroom_stem": true, + "iron_bars": true, + "glass_pane": true, + "melon": true, + "attached_pumpkin_stem": false, + "attached_melon_stem": false, + "pumpkin_stem": false, + "melon_stem": false, + "vine": false, + "oak_fence_gate": true, + "brick_stairs": true, + "stone_brick_stairs": true, + "mycelium": true, + "lily_pad": true, + "nether_bricks": true, + "nether_brick_fence": true, + "nether_brick_stairs": true, + "nether_wart": false, + "enchanting_table": true, + "brewing_stand": true, + "cauldron": true, + "end_portal": false, + "end_portal_frame": true, + "end_stone": true, + "dragon_egg": true, + "redstone_lamp": true, + "cocoa": true, + "sandstone_stairs": true, + "emerald_ore": true, + "ender_chest": true, + "tripwire_hook": false, + "tripwire": false, + "emerald_block": true, + "spruce_stairs": true, + "birch_stairs": true, + "jungle_stairs": true, + "command_block": true, + "beacon": true, + "cobblestone_wall": true, + "mossy_cobblestone_wall": true, + "flower_pot": true, + "potted_oak_sapling": true, + "potted_spruce_sapling": true, + "potted_birch_sapling": true, + "potted_jungle_sapling": true, + "potted_acacia_sapling": true, + "potted_dark_oak_sapling": true, + "potted_fern": true, + "potted_dandelion": true, + "potted_poppy": true, + "potted_blue_orchid": true, + "potted_allium": true, + "potted_azure_bluet": true, + "potted_red_tulip": true, + "potted_orange_tulip": true, + "potted_white_tulip": true, + "potted_pink_tulip": true, + "potted_oxeye_daisy": true, + "potted_red_mushroom": true, + "potted_brown_mushroom": true, + "potted_dead_bush": true, + "potted_cactus": true, + "carrots": false, + "potatoes": false, + "oak_button": false, + "spruce_button": false, + "birch_button": false, + "jungle_button": false, + "acacia_button": false, + "dark_oak_button": false, + "skeleton_wall_skull": true, + "skeleton_skull": true, + "wither_skeleton_wall_skull": true, + "wither_skeleton_skull": true, + "zombie_wall_head": true, + "zombie_head": true, + "player_wall_head": true, + "player_head": true, + "creeper_wall_head": true, + "creeper_head": true, + "dragon_wall_head": true, + "dragon_head": true, + "anvil": true, + "chipped_anvil": true, + "damaged_anvil": true, + "trapped_chest": true, + "light_weighted_pressure_plate": false, + "heavy_weighted_pressure_plate": false, + "comparator": true, + "daylight_detector": true, + "redstone_block": true, + "nether_quartz_ore": true, + "hopper": true, + "quartz_block": true, + "chiseled_quartz_block": true, + "quartz_pillar": true, + "quartz_stairs": true, + "activator_rail": false, + "dropper": true, + "white_terracotta": true, + "orange_terracotta": true, + "magenta_terracotta": true, + "light_blue_terracotta": true, + "yellow_terracotta": true, + "lime_terracotta": true, + "pink_terracotta": true, + "gray_terracotta": true, + "light_gray_terracotta": true, + "cyan_terracotta": true, + "purple_terracotta": true, + "blue_terracotta": true, + "brown_terracotta": true, + "green_terracotta": true, + "red_terracotta": true, + "black_terracotta": true, + "white_stained_glass_pane": true, + "orange_stained_glass_pane": true, + "magenta_stained_glass_pane": true, + "light_blue_stained_glass_pane": true, + "yellow_stained_glass_pane": true, + "lime_stained_glass_pane": true, + "pink_stained_glass_pane": true, + "gray_stained_glass_pane": true, + "light_gray_stained_glass_pane": true, + "cyan_stained_glass_pane": true, + "purple_stained_glass_pane": true, + "blue_stained_glass_pane": true, + "brown_stained_glass_pane": true, + "green_stained_glass_pane": true, + "red_stained_glass_pane": true, + "black_stained_glass_pane": true, + "acacia_stairs": true, + "dark_oak_stairs": true, + "slime_block": true, + "barrier": true, + "iron_trapdoor": true, + "prismarine": true, + "prismarine_bricks": true, + "dark_prismarine": true, + "prismarine_stairs": true, + "prismarine_brick_stairs": true, + "dark_prismarine_stairs": true, + "prismarine_slab": true, + "prismarine_brick_slab": true, + "dark_prismarine_slab": true, + "sea_lantern": true, + "hay_block": true, + "white_carpet": true, + "orange_carpet": true, + "magenta_carpet": true, + "light_blue_carpet": true, + "yellow_carpet": true, + "lime_carpet": true, + "pink_carpet": true, + "gray_carpet": true, + "light_gray_carpet": true, + "cyan_carpet": true, + "purple_carpet": true, + "blue_carpet": true, + "brown_carpet": true, + "green_carpet": true, + "red_carpet": true, + "black_carpet": true, + "terracotta": true, + "coal_block": true, + "packed_ice": true, + "sunflower": false, + "lilac": false, + "rose_bush": false, + "peony": false, + "tall_grass": false, + "large_fern": false, + "white_banner": false, + "orange_banner": false, + "magenta_banner": false, + "light_blue_banner": false, + "yellow_banner": false, + "lime_banner": false, + "pink_banner": false, + "gray_banner": false, + "light_gray_banner": false, + "cyan_banner": false, + "purple_banner": false, + "blue_banner": false, + "brown_banner": false, + "green_banner": false, + "red_banner": false, + "black_banner": false, + "white_wall_banner": false, + "orange_wall_banner": false, + "magenta_wall_banner": false, + "light_blue_wall_banner": false, + "yellow_wall_banner": false, + "lime_wall_banner": false, + "pink_wall_banner": false, + "gray_wall_banner": false, + "light_gray_wall_banner": false, + "cyan_wall_banner": false, + "purple_wall_banner": false, + "blue_wall_banner": false, + "brown_wall_banner": false, + "green_wall_banner": false, + "red_wall_banner": false, + "black_wall_banner": false, + "red_sandstone": true, + "chiseled_red_sandstone": true, + "cut_red_sandstone": true, + "red_sandstone_stairs": true, + "oak_slab": true, + "spruce_slab": true, + "birch_slab": true, + "jungle_slab": true, + "acacia_slab": true, + "dark_oak_slab": true, + "stone_slab": true, + "sandstone_slab": true, + "petrified_oak_slab": true, + "cobblestone_slab": true, + "brick_slab": true, + "stone_brick_slab": true, + "nether_brick_slab": true, + "quartz_slab": true, + "red_sandstone_slab": true, + "purpur_slab": true, + "smooth_stone": true, + "smooth_sandstone": true, + "smooth_quartz": true, + "smooth_red_sandstone": true, + "spruce_fence_gate": true, + "birch_fence_gate": true, + "jungle_fence_gate": true, + "acacia_fence_gate": true, + "dark_oak_fence_gate": true, + "spruce_fence": true, + "birch_fence": true, + "jungle_fence": true, + "acacia_fence": true, + "dark_oak_fence": true, + "spruce_door": true, + "birch_door": true, + "jungle_door": true, + "acacia_door": true, + "dark_oak_door": true, + "end_rod": true, + "chorus_plant": true, + "chorus_flower": true, + "purpur_block": true, + "purpur_pillar": true, + "purpur_stairs": true, + "end_stone_bricks": true, + "beetroots": false, + "grass_path": true, + "end_gateway": false, + "repeating_command_block": true, + "chain_command_block": true, + "frosted_ice": true, + "magma_block": true, + "nether_wart_block": true, + "red_nether_bricks": true, + "bone_block": true, + "structure_void": false, + "observer": true, + "shulker_box": true, + "white_shulker_box": true, + "orange_shulker_box": true, + "magenta_shulker_box": true, + "light_blue_shulker_box": true, + "yellow_shulker_box": true, + "lime_shulker_box": true, + "pink_shulker_box": true, + "gray_shulker_box": true, + "light_gray_shulker_box": true, + "cyan_shulker_box": true, + "purple_shulker_box": true, + "blue_shulker_box": true, + "brown_shulker_box": true, + "green_shulker_box": true, + "red_shulker_box": true, + "black_shulker_box": true, + "white_glazed_terracotta": true, + "orange_glazed_terracotta": true, + "magenta_glazed_terracotta": true, + "light_blue_glazed_terracotta": true, + "yellow_glazed_terracotta": true, + "lime_glazed_terracotta": true, + "pink_glazed_terracotta": true, + "gray_glazed_terracotta": true, + "light_gray_glazed_terracotta": true, + "cyan_glazed_terracotta": true, + "purple_glazed_terracotta": true, + "blue_glazed_terracotta": true, + "brown_glazed_terracotta": true, + "green_glazed_terracotta": true, + "red_glazed_terracotta": true, + "black_glazed_terracotta": true, + "white_concrete": true, + "orange_concrete": true, + "magenta_concrete": true, + "light_blue_concrete": true, + "yellow_concrete": true, + "lime_concrete": true, + "pink_concrete": true, + "gray_concrete": true, + "light_gray_concrete": true, + "cyan_concrete": true, + "purple_concrete": true, + "blue_concrete": true, + "brown_concrete": true, + "green_concrete": true, + "red_concrete": true, + "black_concrete": true, + "white_concrete_powder": true, + "orange_concrete_powder": true, + "magenta_concrete_powder": true, + "light_blue_concrete_powder": true, + "yellow_concrete_powder": true, + "lime_concrete_powder": true, + "pink_concrete_powder": true, + "gray_concrete_powder": true, + "light_gray_concrete_powder": true, + "cyan_concrete_powder": true, + "purple_concrete_powder": true, + "blue_concrete_powder": true, + "brown_concrete_powder": true, + "green_concrete_powder": true, + "red_concrete_powder": true, + "black_concrete_powder": true, + "kelp": false, + "kelp_plant": false, + "dried_kelp_block": true, + "turtle_egg": true, + "dead_tube_coral_block": true, + "dead_brain_coral_block": true, + "dead_bubble_coral_block": true, + "dead_fire_coral_block": true, + "dead_horn_coral_block": true, + "tube_coral_block": true, + "brain_coral_block": true, + "bubble_coral_block": true, + "fire_coral_block": true, + "horn_coral_block": true, + "dead_tube_coral": false, + "dead_brain_coral": false, + "dead_bubble_coral": false, + "dead_fire_coral": false, + "dead_horn_coral": false, + "tube_coral": false, + "brain_coral": false, + "bubble_coral": false, + "fire_coral": false, + "horn_coral": false, + "dead_tube_coral_wall_fan": false, + "dead_brain_coral_wall_fan": false, + "dead_bubble_coral_wall_fan": false, + "dead_fire_coral_wall_fan": false, + "dead_horn_coral_wall_fan": false, + "tube_coral_wall_fan": false, + "brain_coral_wall_fan": false, + "bubble_coral_wall_fan": false, + "fire_coral_wall_fan": false, + "horn_coral_wall_fan": false, + "dead_tube_coral_fan": false, + "dead_brain_coral_fan": false, + "dead_bubble_coral_fan": false, + "dead_fire_coral_fan": false, + "dead_horn_coral_fan": false, + "tube_coral_fan": false, + "brain_coral_fan": false, + "bubble_coral_fan": false, + "fire_coral_fan": false, + "horn_coral_fan": false, + "sea_pickle": true, + "blue_ice": true, + "conduit": true, + "void_air": false, + "cave_air": false, + "bubble_column": false, + "structure_block": true, + }, + ), + Property( + on: "block_kind", + name: "full_block", + reverse: false, + type: bool, + mapping: { + "air": false, + "stone": true, + "granite": true, + "polished_granite": true, + "diorite": true, + "polished_diorite": true, + "andesite": true, + "polished_andesite": true, + "grass_block": true, + "dirt": true, + "coarse_dirt": true, + "podzol": true, + "cobblestone": true, + "oak_planks": true, + "spruce_planks": true, + "birch_planks": true, + "jungle_planks": true, + "acacia_planks": true, + "dark_oak_planks": true, + "oak_sapling": false, + "spruce_sapling": false, + "birch_sapling": false, + "jungle_sapling": false, + "acacia_sapling": false, + "dark_oak_sapling": false, + "bedrock": true, + "water": false, + "lava": false, + "sand": true, + "red_sand": true, + "gravel": true, + "gold_ore": true, + "iron_ore": true, + "coal_ore": true, + "oak_log": true, + "spruce_log": true, + "birch_log": true, + "jungle_log": true, + "acacia_log": true, + "dark_oak_log": true, + "stripped_spruce_log": true, + "stripped_birch_log": true, + "stripped_jungle_log": true, + "stripped_acacia_log": true, + "stripped_dark_oak_log": true, + "stripped_oak_log": true, + "oak_wood": true, + "spruce_wood": true, + "birch_wood": true, + "jungle_wood": true, + "acacia_wood": true, + "dark_oak_wood": true, + "stripped_oak_wood": true, + "stripped_spruce_wood": true, + "stripped_birch_wood": true, + "stripped_jungle_wood": true, + "stripped_acacia_wood": true, + "stripped_dark_oak_wood": true, + "oak_leaves": true, + "spruce_leaves": true, + "birch_leaves": true, + "jungle_leaves": true, + "acacia_leaves": true, + "dark_oak_leaves": true, + "sponge": true, + "wet_sponge": true, + "glass": true, + "lapis_ore": true, + "lapis_block": true, + "dispenser": true, + "sandstone": true, + "chiseled_sandstone": true, + "cut_sandstone": true, + "note_block": true, + "white_bed": false, + "orange_bed": false, + "magenta_bed": false, + "light_blue_bed": false, + "yellow_bed": false, + "lime_bed": false, + "pink_bed": false, + "gray_bed": false, + "light_gray_bed": false, + "cyan_bed": false, + "purple_bed": false, + "blue_bed": false, + "brown_bed": false, + "green_bed": false, + "red_bed": false, + "black_bed": false, + "powered_rail": false, + "detector_rail": false, + "sticky_piston": false, + "cobweb": false, + "grass": false, + "fern": false, + "dead_bush": false, + "seagrass": false, + "tall_seagrass": false, + "piston": false, + "piston_head": false, + "white_wool": true, + "orange_wool": true, + "magenta_wool": true, + "light_blue_wool": true, + "yellow_wool": true, + "lime_wool": true, + "pink_wool": true, + "gray_wool": true, + "light_gray_wool": true, + "cyan_wool": true, + "purple_wool": true, + "blue_wool": true, + "brown_wool": true, + "green_wool": true, + "red_wool": true, + "black_wool": true, + "moving_piston": false, + "dandelion": false, + "poppy": false, + "blue_orchid": false, + "allium": false, + "azure_bluet": false, + "red_tulip": false, + "orange_tulip": false, + "white_tulip": false, + "pink_tulip": false, + "oxeye_daisy": false, + "brown_mushroom": false, + "red_mushroom": false, + "gold_block": true, + "iron_block": true, + "bricks": true, + "tnt": true, + "bookshelf": true, + "mossy_cobblestone": true, + "obsidian": true, + "torch": false, + "wall_torch": false, + "fire": false, + "spawner": true, + "oak_stairs": false, + "chest": false, + "redstone_wire": false, + "diamond_ore": true, + "diamond_block": true, + "crafting_table": true, + "wheat": false, + "farmland": false, + "furnace": true, + "sign": false, + "oak_door": false, + "ladder": false, + "rail": false, + "cobblestone_stairs": false, + "wall_sign": false, + "lever": false, + "stone_pressure_plate": false, + "iron_door": false, + "oak_pressure_plate": false, + "spruce_pressure_plate": false, + "birch_pressure_plate": false, + "jungle_pressure_plate": false, + "acacia_pressure_plate": false, + "dark_oak_pressure_plate": false, + "redstone_ore": true, + "redstone_torch": false, + "redstone_wall_torch": false, + "stone_button": false, + "snow": false, + "ice": true, + "snow_block": true, + "cactus": false, + "clay": true, + "sugar_cane": false, + "jukebox": true, + "oak_fence": false, + "pumpkin": true, + "netherrack": true, + "soul_sand": false, + "glowstone": true, + "nether_portal": false, + "carved_pumpkin": true, + "jack_o_lantern": true, + "cake": false, + "repeater": false, + "white_stained_glass": true, + "orange_stained_glass": true, + "magenta_stained_glass": true, + "light_blue_stained_glass": true, + "yellow_stained_glass": true, + "lime_stained_glass": true, + "pink_stained_glass": true, + "gray_stained_glass": true, + "light_gray_stained_glass": true, + "cyan_stained_glass": true, + "purple_stained_glass": true, + "blue_stained_glass": true, + "brown_stained_glass": true, + "green_stained_glass": true, + "red_stained_glass": true, + "black_stained_glass": true, + "oak_trapdoor": false, + "spruce_trapdoor": false, + "birch_trapdoor": false, + "jungle_trapdoor": false, + "acacia_trapdoor": false, + "dark_oak_trapdoor": false, + "stone_bricks": true, + "mossy_stone_bricks": true, + "cracked_stone_bricks": true, + "chiseled_stone_bricks": true, + "infested_stone": true, + "infested_cobblestone": true, + "infested_stone_bricks": true, + "infested_mossy_stone_bricks": true, + "infested_cracked_stone_bricks": true, + "infested_chiseled_stone_bricks": true, + "brown_mushroom_block": true, + "red_mushroom_block": true, + "mushroom_stem": true, + "iron_bars": false, + "glass_pane": false, + "melon": true, + "attached_pumpkin_stem": false, + "attached_melon_stem": false, + "pumpkin_stem": false, + "melon_stem": false, + "vine": false, + "oak_fence_gate": false, + "brick_stairs": false, + "stone_brick_stairs": false, + "mycelium": true, + "lily_pad": false, + "nether_bricks": true, + "nether_brick_fence": false, + "nether_brick_stairs": false, + "nether_wart": false, + "enchanting_table": false, + "brewing_stand": false, + "cauldron": false, + "end_portal": false, + "end_portal_frame": false, + "end_stone": true, + "dragon_egg": false, + "redstone_lamp": true, + "cocoa": false, + "sandstone_stairs": false, + "emerald_ore": true, + "ender_chest": false, + "tripwire_hook": false, + "tripwire": false, + "emerald_block": true, + "spruce_stairs": false, + "birch_stairs": false, + "jungle_stairs": false, + "command_block": true, + "beacon": true, + "cobblestone_wall": false, + "mossy_cobblestone_wall": false, + "flower_pot": false, + "potted_oak_sapling": false, + "potted_spruce_sapling": false, + "potted_birch_sapling": false, + "potted_jungle_sapling": false, + "potted_acacia_sapling": false, + "potted_dark_oak_sapling": false, + "potted_fern": false, + "potted_dandelion": false, + "potted_poppy": false, + "potted_blue_orchid": false, + "potted_allium": false, + "potted_azure_bluet": false, + "potted_red_tulip": false, + "potted_orange_tulip": false, + "potted_white_tulip": false, + "potted_pink_tulip": false, + "potted_oxeye_daisy": false, + "potted_red_mushroom": false, + "potted_brown_mushroom": false, + "potted_dead_bush": false, + "potted_cactus": false, + "carrots": false, + "potatoes": false, + "oak_button": false, + "spruce_button": false, + "birch_button": false, + "jungle_button": false, + "acacia_button": false, + "dark_oak_button": false, + "skeleton_skull": false, + "skeleton_wall_skull": false, + "wither_skeleton_skull": false, + "wither_skeleton_wall_skull": false, + "zombie_head": false, + "zombie_wall_head": false, + "player_head": false, + "player_wall_head": false, + "creeper_head": false, + "creeper_wall_head": false, + "dragon_head": false, + "dragon_wall_head": false, + "anvil": false, + "chipped_anvil": false, + "damaged_anvil": false, + "trapped_chest": false, + "light_weighted_pressure_plate": false, + "heavy_weighted_pressure_plate": false, + "comparator": false, + "daylight_detector": false, + "redstone_block": true, + "nether_quartz_ore": true, + "hopper": false, + "quartz_block": true, + "chiseled_quartz_block": true, + "quartz_pillar": true, + "quartz_stairs": false, + "activator_rail": false, + "dropper": true, + "white_terracotta": true, + "orange_terracotta": true, + "magenta_terracotta": true, + "light_blue_terracotta": true, + "yellow_terracotta": true, + "lime_terracotta": true, + "pink_terracotta": true, + "gray_terracotta": true, + "light_gray_terracotta": true, + "cyan_terracotta": true, + "purple_terracotta": true, + "blue_terracotta": true, + "brown_terracotta": true, + "green_terracotta": true, + "red_terracotta": true, + "black_terracotta": true, + "white_stained_glass_pane": false, + "orange_stained_glass_pane": false, + "magenta_stained_glass_pane": false, + "light_blue_stained_glass_pane": false, + "yellow_stained_glass_pane": false, + "lime_stained_glass_pane": false, + "pink_stained_glass_pane": false, + "gray_stained_glass_pane": false, + "light_gray_stained_glass_pane": false, + "cyan_stained_glass_pane": false, + "purple_stained_glass_pane": false, + "blue_stained_glass_pane": false, + "brown_stained_glass_pane": false, + "green_stained_glass_pane": false, + "red_stained_glass_pane": false, + "black_stained_glass_pane": false, + "acacia_stairs": false, + "dark_oak_stairs": false, + "slime_block": true, + "barrier": true, + "iron_trapdoor": false, + "prismarine": true, + "prismarine_bricks": true, + "dark_prismarine": true, + "prismarine_stairs": false, + "prismarine_brick_stairs": false, + "dark_prismarine_stairs": false, + "prismarine_slab": false, + "prismarine_brick_slab": false, + "dark_prismarine_slab": false, + "sea_lantern": true, + "hay_block": true, + "white_carpet": false, + "orange_carpet": false, + "magenta_carpet": false, + "light_blue_carpet": false, + "yellow_carpet": false, + "lime_carpet": false, + "pink_carpet": false, + "gray_carpet": false, + "light_gray_carpet": false, + "cyan_carpet": false, + "purple_carpet": false, + "blue_carpet": false, + "brown_carpet": false, + "green_carpet": false, + "red_carpet": false, + "black_carpet": false, + "terracotta": true, + "coal_block": true, + "packed_ice": true, + "sunflower": false, + "lilac": false, + "rose_bush": false, + "peony": false, + "tall_grass": false, + "large_fern": false, + "white_banner": false, + "orange_banner": false, + "magenta_banner": false, + "light_blue_banner": false, + "yellow_banner": false, + "lime_banner": false, + "pink_banner": false, + "gray_banner": false, + "light_gray_banner": false, + "cyan_banner": false, + "purple_banner": false, + "blue_banner": false, + "brown_banner": false, + "green_banner": false, + "red_banner": false, + "black_banner": false, + "white_wall_banner": false, + "orange_wall_banner": false, + "magenta_wall_banner": false, + "light_blue_wall_banner": false, + "yellow_wall_banner": false, + "lime_wall_banner": false, + "pink_wall_banner": false, + "gray_wall_banner": false, + "light_gray_wall_banner": false, + "cyan_wall_banner": false, + "purple_wall_banner": false, + "blue_wall_banner": false, + "brown_wall_banner": false, + "green_wall_banner": false, + "red_wall_banner": false, + "black_wall_banner": false, + "red_sandstone": true, + "chiseled_red_sandstone": true, + "cut_red_sandstone": true, + "red_sandstone_stairs": false, + "oak_slab": false, + "spruce_slab": false, + "birch_slab": false, + "jungle_slab": false, + "acacia_slab": false, + "dark_oak_slab": false, + "stone_slab": false, + "sandstone_slab": false, + "petrified_oak_slab": false, + "cobblestone_slab": false, + "brick_slab": false, + "stone_brick_slab": false, + "nether_brick_slab": false, + "quartz_slab": false, + "red_sandstone_slab": false, + "purpur_slab": false, + "smooth_stone": true, + "smooth_sandstone": true, + "smooth_quartz": true, + "smooth_red_sandstone": true, + "spruce_fence_gate": false, + "birch_fence_gate": false, + "jungle_fence_gate": false, + "acacia_fence_gate": false, + "dark_oak_fence_gate": false, + "spruce_fence": false, + "birch_fence": false, + "jungle_fence": false, + "acacia_fence": false, + "dark_oak_fence": false, + "spruce_door": false, + "birch_door": false, + "jungle_door": false, + "acacia_door": false, + "dark_oak_door": false, + "end_rod": false, + "chorus_plant": false, + "chorus_flower": true, + "purpur_block": true, + "purpur_pillar": true, + "purpur_stairs": false, + "end_stone_bricks": true, + "beetroots": false, + "grass_path": false, + "end_gateway": false, + "repeating_command_block": true, + "chain_command_block": true, + "frosted_ice": true, + "magma_block": true, + "nether_wart_block": true, + "red_nether_bricks": true, + "bone_block": true, + "structure_void": false, + "observer": true, + "shulker_box": true, + "white_shulker_box": true, + "orange_shulker_box": true, + "magenta_shulker_box": true, + "light_blue_shulker_box": true, + "yellow_shulker_box": true, + "lime_shulker_box": true, + "pink_shulker_box": true, + "gray_shulker_box": true, + "light_gray_shulker_box": true, + "cyan_shulker_box": true, + "purple_shulker_box": true, + "blue_shulker_box": true, + "brown_shulker_box": true, + "green_shulker_box": true, + "red_shulker_box": true, + "black_shulker_box": true, + "white_glazed_terracotta": true, + "orange_glazed_terracotta": true, + "magenta_glazed_terracotta": true, + "light_blue_glazed_terracotta": true, + "yellow_glazed_terracotta": true, + "lime_glazed_terracotta": true, + "pink_glazed_terracotta": true, + "gray_glazed_terracotta": true, + "light_gray_glazed_terracotta": true, + "cyan_glazed_terracotta": true, + "purple_glazed_terracotta": true, + "blue_glazed_terracotta": true, + "brown_glazed_terracotta": true, + "green_glazed_terracotta": true, + "red_glazed_terracotta": true, + "black_glazed_terracotta": true, + "white_concrete": true, + "orange_concrete": true, + "magenta_concrete": true, + "light_blue_concrete": true, + "yellow_concrete": true, + "lime_concrete": true, + "pink_concrete": true, + "gray_concrete": true, + "light_gray_concrete": true, + "cyan_concrete": true, + "purple_concrete": true, + "blue_concrete": true, + "brown_concrete": true, + "green_concrete": true, + "red_concrete": true, + "black_concrete": true, + "white_concrete_powder": true, + "orange_concrete_powder": true, + "magenta_concrete_powder": true, + "light_blue_concrete_powder": true, + "yellow_concrete_powder": true, + "lime_concrete_powder": true, + "pink_concrete_powder": true, + "gray_concrete_powder": true, + "light_gray_concrete_powder": true, + "cyan_concrete_powder": true, + "purple_concrete_powder": true, + "blue_concrete_powder": true, + "brown_concrete_powder": true, + "green_concrete_powder": true, + "red_concrete_powder": true, + "black_concrete_powder": true, + "kelp": false, + "kelp_plant": false, + "dried_kelp_block": true, + "turtle_egg": false, + "dead_tube_coral_block": true, + "dead_brain_coral_block": true, + "dead_bubble_coral_block": true, + "dead_fire_coral_block": true, + "dead_horn_coral_block": true, + "tube_coral_block": true, + "brain_coral_block": true, + "bubble_coral_block": true, + "fire_coral_block": true, + "horn_coral_block": true, + "dead_tube_coral": false, + "dead_brain_coral": false, + "dead_bubble_coral": false, + "dead_fire_coral": false, + "dead_horn_coral": false, + "tube_coral": false, + "brain_coral": false, + "bubble_coral": false, + "fire_coral": false, + "horn_coral": false, + "dead_tube_coral_fan": false, + "dead_brain_coral_fan": false, + "dead_bubble_coral_fan": false, + "dead_fire_coral_fan": false, + "dead_horn_coral_fan": false, + "tube_coral_fan": false, + "brain_coral_fan": false, + "bubble_coral_fan": false, + "fire_coral_fan": false, + "horn_coral_fan": false, + "dead_tube_coral_wall_fan": false, + "dead_brain_coral_wall_fan": false, + "dead_bubble_coral_wall_fan": false, + "dead_fire_coral_wall_fan": false, + "dead_horn_coral_wall_fan": false, + "tube_coral_wall_fan": false, + "brain_coral_wall_fan": false, + "bubble_coral_wall_fan": false, + "fire_coral_wall_fan": false, + "horn_coral_wall_fan": false, + "sea_pickle": false, + "blue_ice": true, + "conduit": false, + "void_air": false, + "cave_air": false, + "bubble_column": false, + "structure_block": true, + }, + ), + Enum( + name: "simplified_block_kind", + variants: [ + + "air", + "stone", + "granite", + "polished_granite", + "diorite", + "polished_diorite", + "andesite", + "polished_andesite", + "grass_block", + "dirt", + "coarse_dirt", + "podzol", + "cobblestone", + "planks", + "sapling", + "bedrock", + "water", + "lava", + "sand", + "red_sand", + "gravel", + "gold_ore", + "iron_ore", + "coal_ore", + "log", + "leaves", + "sponge", + "wet_sponge", + "glass", + "lapis_ore", + "lapis_block", + "dispenser", + "sandstone", + "chiseled_sandstone", + "cut_sandstone", + "note_block", + "bed", + "powered_rail", + "detector_rail", + "sticky_piston", + "cobweb", + "grass", + "fern", + "dead_bush", + "seagrass", + "tall_seagrass", + "piston", + "piston_head", + "wool", + "moving_piston", + "flower", + "mushroom", + "gold_block", + "iron_block", + "bricks", + "tnt", + "bookshelf", + "mossy_cobblestone", + "obsidian", + "torch", + "wall_torch", + "fire", + "spawner", + "stairs", + "chest", + "redstone_wire", + "diamond_ore", + "diamond_block", + "crafting_table", + "wheat", + "farmland", + "furnace", + "sign", + "wooden_door", + "ladder", + "rail", + "wall_sign", + "lever", + "stone_pressure_plate", + "iron_door", + "wooden_pressure_plate", + "redstone_ore", + "redstone_torch", + "redstone_wall_torch", + "stone_button", + "snow", + "ice", + "snow_block", + "cactus", + "clay", + "sugar_cane", + "jukebox", + "fence", + "pumpkin", + "netherrack", + "soul_sand", + "glowstone", + "nether_portal", + "carved_pumpkin", + "jack_o_lantern", + "cake", + "repeater", + "stained_glass", + "wooden_trapdoor", + "infested_stone", + "infested_cobblestone", + "infested_stone_bricks", + "infested_mossy_stone_bricks", + "infested_cracked_stone_bricks", + "infested_chiseled_stone_bricks", + "stone_bricks", + "mossy_stone_bricks", + "cracked_stone_bricks", + "chiseled_stone_bricks", + "brown_mushroom_block", + "red_mushroom_block", + "mushroom_stem", + "iron_bars", + "glass_pane", + "melon", + "attached_pumpkin_stem", + "attached_melon_stem", + "pumpkin_stem", + "melon_stem", + "vine", + "fence_gate", + "mycelium", + "lily_pad", + "nether_bricks", + "nether_wart", + "enchanting_table", + "brewing_stand", + "cauldron", + "end_portal", + "end_portal_frame", + "end_stone", + "dragon_egg", + "redstone_lamp", + "cocoa", + "emerald_ore", + "ender_chest", + "tripwire_hook", + "tripwire", + "emerald_block", + "command_block", + "beacon", + "cobblestone_wall", + "mossy_cobblestone_wall", + "flower_pot", + "potted_plant", + "carrots", + "potatoes", + "wooden_button", + "skeleton_wall_skull", + "skeleton_skull", + "wither_skeleton_wall_skull", + "wither_skeleton_skull", + "zombie_wall_head", + "zombie_head", + "player_wall_head", + "player_head", + "creeper_wall_head", + "creeper_head", + "dragon_wall_head", + "dragon_head", + "anvil", + "trapped_chest", + "light_weighted_pressure_plate", + "heavy_weighted_pressure_plate", + "comparator", + "daylight_detector", + "redstone_block", + "nether_quartz_ore", + "hopper", + "quartz_block", + "chiseled_quartz_block", + "quartz_pillar", + "activator_rail", + "dropper", + "terracotta", + "stained_glass_pane", + "slime_block", + "barrier", + "iron_trapdoor", + "prismarine", + "prismarine_bricks", + "dark_prismarine", + "slab", + "sea_lantern", + "hay_block", + "carpet", + "coal_block", + "packed_ice", + "sunflower", + "lilac", + "rose_bush", + "peony", + "tall_grass", + "large_fern", + "banner", + "wall_banner", + "red_sandstone", + "chiseled_red_sandstone", + "cut_red_sandstone", + "smooth_stone", + "smooth_sandstone", + "smooth_quartz", + "smooth_red_sandstone", + "end_rod", + "chorus_plant", + "chorus_flower", + "purpur_block", + "purpur_pillar", + "end_stone_bricks", + "beetroots", + "grass_path", + "end_gateway", + "repeating_command_block", + "chain_command_block", + "frosted_ice", + "magma_block", + "nether_wart_block", + "red_nether_bricks", + "bone_block", + "structure_void", + "observer", + "shulker_box", + "glazed_terracotta", + "concrete", + "concrete_powder", + "kelp", + "kelp_plant", + "dried_kelp_block", + "turtle_egg", + "coral_block", + "coral", + "coral_wall_fan", + "coral_fan", + "sea_pickle", + "blue_ice", + "conduit", + "bubble_column", + "structure_block", ], + ), + Property( + on: "block_kind", + name: "to_simplified_kind", + reverse: false, + type: Custom("simplified_block_kind"), + mapping: { + "air": "air", + "stone": "stone", + "granite": "granite", + "polished_granite": "polished_granite", + "diorite": "diorite", + "polished_diorite": "polished_diorite", + "andesite": "andesite", + "polished_andesite": "polished_andesite", + "grass_block": "grass_block", + "dirt": "dirt", + "coarse_dirt": "coarse_dirt", + "podzol": "podzol", + "cobblestone": "cobblestone", + "oak_planks": "planks", + "spruce_planks": "planks", + "birch_planks": "planks", + "jungle_planks": "planks", + "acacia_planks": "planks", + "dark_oak_planks": "planks", + "oak_sapling": "sapling", + "spruce_sapling": "sapling", + "birch_sapling": "sapling", + "jungle_sapling": "sapling", + "acacia_sapling": "sapling", + "dark_oak_sapling": "sapling", + "bedrock": "bedrock", + "water": "water", + "lava": "lava", + "sand": "sand", + "red_sand": "red_sand", + "gravel": "gravel", + "gold_ore": "gold_ore", + "iron_ore": "iron_ore", + "coal_ore": "coal_ore", + "oak_log": "log", + "spruce_log": "log", + "birch_log": "log", + "jungle_log": "log", + "acacia_log": "log", + "dark_oak_log": "log", + "stripped_spruce_log": "log", + "stripped_birch_log": "log", + "stripped_jungle_log": "log", + "stripped_acacia_log": "log", + "stripped_dark_oak_log": "log", + "stripped_oak_log": "log", + "oak_wood": "log", + "spruce_wood": "log", + "birch_wood": "log", + "jungle_wood": "log", + "acacia_wood": "log", + "dark_oak_wood": "log", + "stripped_oak_wood": "log", + "stripped_spruce_wood": "log", + "stripped_birch_wood": "log", + "stripped_jungle_wood": "log", + "stripped_acacia_wood": "log", + "stripped_dark_oak_wood": "log", + "oak_leaves": "leaves", + "spruce_leaves": "leaves", + "birch_leaves": "leaves", + "jungle_leaves": "leaves", + "acacia_leaves": "leaves", + "dark_oak_leaves": "leaves", + "sponge": "sponge", + "wet_sponge": "wet_sponge", + "glass": "glass", + "lapis_ore": "lapis_ore", + "lapis_block": "lapis_block", + "dispenser": "dispenser", + "sandstone": "sandstone", + "chiseled_sandstone": "chiseled_sandstone", + "cut_sandstone": "cut_sandstone", + "note_block": "note_block", + "white_bed": "bed", + "orange_bed": "bed", + "magenta_bed": "bed", + "light_blue_bed": "bed", + "yellow_bed": "bed", + "lime_bed": "bed", + "pink_bed": "bed", + "gray_bed": "bed", + "light_gray_bed": "bed", + "cyan_bed": "bed", + "purple_bed": "bed", + "blue_bed": "bed", + "brown_bed": "bed", + "green_bed": "bed", + "red_bed": "bed", + "black_bed": "bed", + "powered_rail": "powered_rail", + "detector_rail": "detector_rail", + "sticky_piston": "sticky_piston", + "cobweb": "cobweb", + "grass": "grass", + "fern": "fern", + "dead_bush": "dead_bush", + "seagrass": "seagrass", + "tall_seagrass": "tall_seagrass", + "piston": "piston", + "piston_head": "piston_head", + "white_wool": "wool", + "orange_wool": "wool", + "magenta_wool": "wool", + "light_blue_wool": "wool", + "yellow_wool": "wool", + "lime_wool": "wool", + "pink_wool": "wool", + "gray_wool": "wool", + "light_gray_wool": "wool", + "cyan_wool": "wool", + "purple_wool": "wool", + "blue_wool": "wool", + "brown_wool": "wool", + "green_wool": "wool", + "red_wool": "wool", + "black_wool": "wool", + "moving_piston": "moving_piston", + "dandelion": "flower", + "poppy": "flower", + "blue_orchid": "flower", + "allium": "flower", + "azure_bluet": "flower", + "red_tulip": "flower", + "orange_tulip": "flower", + "white_tulip": "flower", + "pink_tulip": "flower", + "oxeye_daisy": "flower", + "brown_mushroom": "mushroom", + "red_mushroom": "mushroom", + "gold_block": "gold_block", + "iron_block": "iron_block", + "bricks": "bricks", + "tnt": "tnt", + "bookshelf": "bookshelf", + "mossy_cobblestone": "mossy_cobblestone", + "obsidian": "obsidian", + "torch": "torch", + "wall_torch": "wall_torch", + "fire": "fire", + "spawner": "spawner", + "oak_stairs": "stairs", + "chest": "chest", + "redstone_wire": "redstone_wire", + "diamond_ore": "diamond_ore", + "diamond_block": "diamond_block", + "crafting_table": "crafting_table", + "wheat": "wheat", + "farmland": "farmland", + "furnace": "furnace", + "sign": "sign", + "oak_door": "wooden_door", + "ladder": "ladder", + "rail": "rail", + "cobblestone_stairs": "stairs", + "wall_sign": "wall_sign", + "lever": "lever", + "stone_pressure_plate": "stone_pressure_plate", + "iron_door": "iron_door", + "oak_pressure_plate": "wooden_pressure_plate", + "spruce_pressure_plate": "wooden_pressure_plate", + "birch_pressure_plate": "wooden_pressure_plate", + "jungle_pressure_plate": "wooden_pressure_plate", + "acacia_pressure_plate": "wooden_pressure_plate", + "dark_oak_pressure_plate": "wooden_pressure_plate", + "redstone_ore": "redstone_ore", + "redstone_torch": "redstone_torch", + "redstone_wall_torch": "redstone_wall_torch", + "stone_button": "stone_button", + "snow": "snow", + "ice": "ice", + "snow_block": "snow_block", + "cactus": "cactus", + "clay": "clay", + "sugar_cane": "sugar_cane", + "jukebox": "jukebox", + "oak_fence": "fence", + "pumpkin": "pumpkin", + "netherrack": "netherrack", + "soul_sand": "soul_sand", + "glowstone": "glowstone", + "nether_portal": "nether_portal", + "carved_pumpkin": "carved_pumpkin", + "jack_o_lantern": "jack_o_lantern", + "cake": "cake", + "repeater": "repeater", + "white_stained_glass": "stained_glass", + "orange_stained_glass": "stained_glass", + "magenta_stained_glass": "stained_glass", + "light_blue_stained_glass": "stained_glass", + "yellow_stained_glass": "stained_glass", + "lime_stained_glass": "stained_glass", + "pink_stained_glass": "stained_glass", + "gray_stained_glass": "stained_glass", + "light_gray_stained_glass": "stained_glass", + "cyan_stained_glass": "stained_glass", + "purple_stained_glass": "stained_glass", + "blue_stained_glass": "stained_glass", + "brown_stained_glass": "stained_glass", + "green_stained_glass": "stained_glass", + "red_stained_glass": "stained_glass", + "black_stained_glass": "stained_glass", + "oak_trapdoor": "wooden_trapdoor", + "spruce_trapdoor": "wooden_trapdoor", + "birch_trapdoor": "wooden_trapdoor", + "jungle_trapdoor": "wooden_trapdoor", + "acacia_trapdoor": "wooden_trapdoor", + "dark_oak_trapdoor": "wooden_trapdoor", + "infested_stone": "infested_stone", + "infested_cobblestone": "infested_cobblestone", + "infested_stone_bricks": "infested_stone_bricks", + "infested_mossy_stone_bricks": "infested_mossy_stone_bricks", + "infested_cracked_stone_bricks": "infested_cracked_stone_bricks", + "infested_chiseled_stone_bricks": "infested_chiseled_stone_bricks", + "stone_bricks": "stone_bricks", + "mossy_stone_bricks": "mossy_stone_bricks", + "cracked_stone_bricks": "cracked_stone_bricks", + "chiseled_stone_bricks": "chiseled_stone_bricks", + "brown_mushroom_block": "brown_mushroom_block", + "red_mushroom_block": "red_mushroom_block", + "mushroom_stem": "mushroom_stem", + "iron_bars": "iron_bars", + "glass_pane": "glass_pane", + "melon": "melon", + "attached_pumpkin_stem": "attached_pumpkin_stem", + "attached_melon_stem": "attached_melon_stem", + "pumpkin_stem": "pumpkin_stem", + "melon_stem": "melon_stem", + "vine": "vine", + "oak_fence_gate": "fence_gate", + "brick_stairs": "stairs", + "stone_brick_stairs": "stairs", + "mycelium": "mycelium", + "lily_pad": "lily_pad", + "nether_bricks": "nether_bricks", + "nether_brick_fence": "fence", + "nether_brick_stairs": "stairs", + "nether_wart": "nether_wart", + "enchanting_table": "enchanting_table", + "brewing_stand": "brewing_stand", + "cauldron": "cauldron", + "end_portal": "end_portal", + "end_portal_frame": "end_portal_frame", + "end_stone": "end_stone", + "dragon_egg": "dragon_egg", + "redstone_lamp": "redstone_lamp", + "cocoa": "cocoa", + "sandstone_stairs": "stairs", + "emerald_ore": "emerald_ore", + "ender_chest": "ender_chest", + "tripwire_hook": "tripwire_hook", + "tripwire": "tripwire", + "emerald_block": "emerald_block", + "spruce_stairs": "stairs", + "birch_stairs": "stairs", + "jungle_stairs": "stairs", + "command_block": "command_block", + "beacon": "beacon", + "cobblestone_wall": "cobblestone_wall", + "mossy_cobblestone_wall": "mossy_cobblestone_wall", + "flower_pot": "flower_pot", + "potted_oak_sapling": "sapling", + "potted_spruce_sapling": "sapling", + "potted_birch_sapling": "sapling", + "potted_jungle_sapling": "sapling", + "potted_acacia_sapling": "sapling", + "potted_dark_oak_sapling": "sapling", + "potted_fern": "potted_plant", + "potted_dandelion": "potted_plant", + "potted_poppy": "potted_plant", + "potted_blue_orchid": "flower", + "potted_allium": "potted_plant", + "potted_azure_bluet": "flower", + "potted_red_tulip": "flower", + "potted_orange_tulip": "flower", + "potted_white_tulip": "flower", + "potted_pink_tulip": "flower", + "potted_oxeye_daisy": "flower", + "potted_red_mushroom": "potted_plant", + "potted_brown_mushroom": "potted_plant", + "potted_dead_bush": "potted_plant", + "potted_cactus": "potted_plant", + "carrots": "carrots", + "potatoes": "potatoes", + "oak_button": "wooden_button", + "spruce_button": "wooden_button", + "birch_button": "wooden_button", + "jungle_button": "wooden_button", + "acacia_button": "wooden_button", + "dark_oak_button": "wooden_button", + "skeleton_wall_skull": "skeleton_wall_skull", + "skeleton_skull": "skeleton_skull", + "wither_skeleton_wall_skull": "wither_skeleton_wall_skull", + "wither_skeleton_skull": "wither_skeleton_skull", + "zombie_wall_head": "zombie_wall_head", + "zombie_head": "zombie_head", + "player_wall_head": "player_wall_head", + "player_head": "player_head", + "creeper_wall_head": "creeper_wall_head", + "creeper_head": "creeper_head", + "dragon_wall_head": "dragon_wall_head", + "dragon_head": "dragon_head", + "anvil": "anvil", + "chipped_anvil": "anvil", + "damaged_anvil": "anvil", + "trapped_chest": "trapped_chest", + "light_weighted_pressure_plate": "light_weighted_pressure_plate", + "heavy_weighted_pressure_plate": "heavy_weighted_pressure_plate", + "comparator": "comparator", + "daylight_detector": "daylight_detector", + "redstone_block": "redstone_block", + "nether_quartz_ore": "nether_quartz_ore", + "hopper": "hopper", + "quartz_block": "quartz_block", + "chiseled_quartz_block": "chiseled_quartz_block", + "quartz_pillar": "quartz_pillar", + "quartz_stairs": "stairs", + "activator_rail": "activator_rail", + "dropper": "dropper", + "white_terracotta": "terracotta", + "orange_terracotta": "terracotta", + "magenta_terracotta": "terracotta", + "light_blue_terracotta": "terracotta", + "yellow_terracotta": "terracotta", + "lime_terracotta": "terracotta", + "pink_terracotta": "terracotta", + "gray_terracotta": "terracotta", + "light_gray_terracotta": "terracotta", + "cyan_terracotta": "terracotta", + "purple_terracotta": "terracotta", + "blue_terracotta": "terracotta", + "brown_terracotta": "terracotta", + "green_terracotta": "terracotta", + "red_terracotta": "terracotta", + "black_terracotta": "terracotta", + "white_stained_glass_pane": "stained_glass_pane", + "orange_stained_glass_pane": "stained_glass_pane", + "magenta_stained_glass_pane": "stained_glass_pane", + "light_blue_stained_glass_pane": "stained_glass_pane", + "yellow_stained_glass_pane": "stained_glass_pane", + "lime_stained_glass_pane": "stained_glass_pane", + "pink_stained_glass_pane": "stained_glass_pane", + "gray_stained_glass_pane": "stained_glass_pane", + "light_gray_stained_glass_pane": "stained_glass_pane", + "cyan_stained_glass_pane": "stained_glass_pane", + "purple_stained_glass_pane": "stained_glass_pane", + "blue_stained_glass_pane": "stained_glass_pane", + "brown_stained_glass_pane": "stained_glass_pane", + "green_stained_glass_pane": "stained_glass_pane", + "red_stained_glass_pane": "stained_glass_pane", + "black_stained_glass_pane": "stained_glass_pane", + "acacia_stairs": "stairs", + "dark_oak_stairs": "stairs", + "slime_block": "slime_block", + "barrier": "barrier", + "iron_trapdoor": "iron_trapdoor", + "prismarine": "prismarine", + "prismarine_bricks": "prismarine_bricks", + "dark_prismarine": "dark_prismarine", + "prismarine_stairs": "stairs", + "prismarine_brick_stairs": "stairs", + "dark_prismarine_stairs": "stairs", + "prismarine_slab": "slab", + "prismarine_brick_slab": "slab", + "dark_prismarine_slab": "slab", + "sea_lantern": "sea_lantern", + "hay_block": "hay_block", + "white_carpet": "carpet", + "orange_carpet": "carpet", + "magenta_carpet": "carpet", + "light_blue_carpet": "carpet", + "yellow_carpet": "carpet", + "lime_carpet": "carpet", + "pink_carpet": "carpet", + "gray_carpet": "carpet", + "light_gray_carpet": "carpet", + "cyan_carpet": "carpet", + "purple_carpet": "carpet", + "blue_carpet": "carpet", + "brown_carpet": "carpet", + "green_carpet": "carpet", + "red_carpet": "carpet", + "black_carpet": "carpet", + "terracotta": "terracotta", + "coal_block": "coal_block", + "packed_ice": "packed_ice", + "sunflower": "sunflower", + "lilac": "lilac", + "rose_bush": "rose_bush", + "peony": "peony", + "tall_grass": "tall_grass", + "large_fern": "large_fern", + "white_banner": "banner", + "orange_banner": "banner", + "magenta_banner": "banner", + "light_blue_banner": "banner", + "yellow_banner": "banner", + "lime_banner": "banner", + "pink_banner": "banner", + "gray_banner": "banner", + "light_gray_banner": "banner", + "cyan_banner": "banner", + "purple_banner": "banner", + "blue_banner": "banner", + "brown_banner": "banner", + "green_banner": "banner", + "red_banner": "banner", + "black_banner": "banner", + "white_wall_banner": "wall_banner", + "orange_wall_banner": "wall_banner", + "magenta_wall_banner": "wall_banner", + "light_blue_wall_banner": "wall_banner", + "yellow_wall_banner": "wall_banner", + "lime_wall_banner": "wall_banner", + "pink_wall_banner": "wall_banner", + "gray_wall_banner": "wall_banner", + "light_gray_wall_banner": "wall_banner", + "cyan_wall_banner": "wall_banner", + "purple_wall_banner": "wall_banner", + "blue_wall_banner": "wall_banner", + "brown_wall_banner": "wall_banner", + "green_wall_banner": "wall_banner", + "red_wall_banner": "wall_banner", + "black_wall_banner": "wall_banner", + "red_sandstone": "red_sandstone", + "chiseled_red_sandstone": "chiseled_red_sandstone", + "cut_red_sandstone": "cut_red_sandstone", + "red_sandstone_stairs": "stairs", + "oak_slab": "slab", + "spruce_slab": "slab", + "birch_slab": "slab", + "jungle_slab": "slab", + "acacia_slab": "slab", + "dark_oak_slab": "slab", + "stone_slab": "slab", + "sandstone_slab": "slab", + "petrified_oak_slab": "slab", + "cobblestone_slab": "slab", + "brick_slab": "slab", + "stone_brick_slab": "slab", + "nether_brick_slab": "slab", + "quartz_slab": "slab", + "red_sandstone_slab": "slab", + "purpur_slab": "slab", + "smooth_stone": "smooth_stone", + "smooth_sandstone": "smooth_sandstone", + "smooth_quartz": "smooth_quartz", + "smooth_red_sandstone": "smooth_red_sandstone", + "spruce_fence_gate": "fence_gate", + "birch_fence_gate": "fence_gate", + "jungle_fence_gate": "fence_gate", + "acacia_fence_gate": "fence_gate", + "dark_oak_fence_gate": "fence_gate", + "spruce_fence": "fence", + "birch_fence": "fence", + "jungle_fence": "fence", + "acacia_fence": "fence", + "dark_oak_fence": "fence", + "spruce_door": "wooden_door", + "birch_door": "wooden_door", + "jungle_door": "wooden_door", + "acacia_door": "wooden_door", + "dark_oak_door": "wooden_door", + "end_rod": "end_rod", + "chorus_plant": "chorus_plant", + "chorus_flower": "chorus_flower", + "purpur_block": "purpur_block", + "purpur_pillar": "purpur_pillar", + "purpur_stairs": "stairs", + "end_stone_bricks": "end_stone_bricks", + "beetroots": "beetroots", + "grass_path": "grass_path", + "end_gateway": "end_gateway", + "repeating_command_block": "repeating_command_block", + "chain_command_block": "chain_command_block", + "frosted_ice": "frosted_ice", + "magma_block": "magma_block", + "nether_wart_block": "nether_wart_block", + "red_nether_bricks": "red_nether_bricks", + "bone_block": "bone_block", + "structure_void": "structure_void", + "observer": "observer", + "shulker_box": "shulker_box", + "white_shulker_box": "shulker_box", + "orange_shulker_box": "shulker_box", + "magenta_shulker_box": "shulker_box", + "light_blue_shulker_box": "shulker_box", + "yellow_shulker_box": "shulker_box", + "lime_shulker_box": "shulker_box", + "pink_shulker_box": "shulker_box", + "gray_shulker_box": "shulker_box", + "light_gray_shulker_box": "shulker_box", + "cyan_shulker_box": "shulker_box", + "purple_shulker_box": "shulker_box", + "blue_shulker_box": "shulker_box", + "brown_shulker_box": "shulker_box", + "green_shulker_box": "shulker_box", + "red_shulker_box": "shulker_box", + "black_shulker_box": "shulker_box", + "white_glazed_terracotta": "glazed_terracotta", + "orange_glazed_terracotta": "glazed_terracotta", + "magenta_glazed_terracotta": "glazed_terracotta", + "light_blue_glazed_terracotta": "glazed_terracotta", + "yellow_glazed_terracotta": "glazed_terracotta", + "lime_glazed_terracotta": "glazed_terracotta", + "pink_glazed_terracotta": "glazed_terracotta", + "gray_glazed_terracotta": "glazed_terracotta", + "light_gray_glazed_terracotta": "glazed_terracotta", + "cyan_glazed_terracotta": "glazed_terracotta", + "purple_glazed_terracotta": "glazed_terracotta", + "blue_glazed_terracotta": "glazed_terracotta", + "brown_glazed_terracotta": "glazed_terracotta", + "green_glazed_terracotta": "glazed_terracotta", + "red_glazed_terracotta": "glazed_terracotta", + "black_glazed_terracotta": "glazed_terracotta", + "white_concrete": "concrete", + "orange_concrete": "concrete", + "magenta_concrete": "concrete", + "light_blue_concrete": "concrete", + "yellow_concrete": "concrete", + "lime_concrete": "concrete", + "pink_concrete": "concrete", + "gray_concrete": "concrete", + "light_gray_concrete": "concrete", + "cyan_concrete": "concrete", + "purple_concrete": "concrete", + "blue_concrete": "concrete", + "brown_concrete": "concrete", + "green_concrete": "concrete", + "red_concrete": "concrete", + "black_concrete": "concrete", + "white_concrete_powder": "concrete_powder", + "orange_concrete_powder": "concrete_powder", + "magenta_concrete_powder": "concrete_powder", + "light_blue_concrete_powder": "concrete_powder", + "yellow_concrete_powder": "concrete_powder", + "lime_concrete_powder": "concrete_powder", + "pink_concrete_powder": "concrete_powder", + "gray_concrete_powder": "concrete_powder", + "light_gray_concrete_powder": "concrete_powder", + "cyan_concrete_powder": "concrete_powder", + "purple_concrete_powder": "concrete_powder", + "blue_concrete_powder": "concrete_powder", + "brown_concrete_powder": "concrete_powder", + "green_concrete_powder": "concrete_powder", + "red_concrete_powder": "concrete_powder", + "black_concrete_powder": "concrete_powder", + "kelp": "kelp", + "kelp_plant": "kelp_plant", + "dried_kelp_block": "dried_kelp_block", + "turtle_egg": "turtle_egg", + "dead_tube_coral_block": "coral_block", + "dead_brain_coral_block": "coral_block", + "dead_bubble_coral_block": "coral_block", + "dead_fire_coral_block": "coral_block", + "dead_horn_coral_block": "coral_block", + "tube_coral_block": "coral_block", + "brain_coral_block": "coral_block", + "bubble_coral_block": "coral_block", + "fire_coral_block": "coral_block", + "horn_coral_block": "coral_block", + "dead_tube_coral": "coral", + "dead_brain_coral": "coral", + "dead_bubble_coral": "coral", + "dead_fire_coral": "coral", + "dead_horn_coral": "coral", + "tube_coral": "coral", + "brain_coral": "coral", + "bubble_coral": "coral", + "fire_coral": "coral", + "horn_coral": "coral", + "dead_tube_coral_wall_fan": "coral_wall_fan", + "dead_brain_coral_wall_fan": "coral_wall_fan", + "dead_bubble_coral_wall_fan": "coral_wall_fan", + "dead_fire_coral_wall_fan": "coral_wall_fan", + "dead_horn_coral_wall_fan": "coral_wall_fan", + "tube_coral_wall_fan": "coral_wall_fan", + "brain_coral_wall_fan": "coral_wall_fan", + "bubble_coral_wall_fan": "coral_wall_fan", + "fire_coral_wall_fan": "coral_wall_fan", + "horn_coral_wall_fan": "coral_wall_fan", + "dead_tube_coral_fan": "coral_fan", + "dead_brain_coral_fan": "coral_fan", + "dead_bubble_coral_fan": "coral_fan", + "dead_fire_coral_fan": "coral_fan", + "dead_horn_coral_fan": "coral_fan", + "tube_coral_fan": "coral_fan", + "brain_coral_fan": "coral_fan", + "bubble_coral_fan": "coral_fan", + "fire_coral_fan": "coral_fan", + "horn_coral_fan": "coral_fan", + "sea_pickle": "sea_pickle", + "blue_ice": "blue_ice", + "conduit": "conduit", + "void_air": "air", + "cave_air": "air", + "bubble_column": "bubble_column", + "structure_block": "structure_block", + }, + ),]) \ No newline at end of file diff --git a/feather/old/definitions/data/generated/item.ron b/feather/old/definitions/data/generated/item.ron new file mode 100644 index 000000000..a78c449bc --- /dev/null +++ b/feather/old/definitions/data/generated/item.ron @@ -0,0 +1,3990 @@ +// This files is @generated +Multiple([ + + Enum( + name: "item", + variants: [ + + "air", + "stone", + "granite", + "polished_granite", + "diorite", + "polished_diorite", + "andesite", + "polished_andesite", + "grass_block", + "dirt", + "coarse_dirt", + "podzol", + "cobblestone", + "oak_planks", + "spruce_planks", + "birch_planks", + "jungle_planks", + "acacia_planks", + "dark_oak_planks", + "oak_sapling", + "spruce_sapling", + "birch_sapling", + "jungle_sapling", + "acacia_sapling", + "dark_oak_sapling", + "bedrock", + "sand", + "red_sand", + "gravel", + "gold_ore", + "iron_ore", + "coal_ore", + "oak_log", + "spruce_log", + "birch_log", + "jungle_log", + "acacia_log", + "dark_oak_log", + "stripped_oak_log", + "stripped_spruce_log", + "stripped_birch_log", + "stripped_jungle_log", + "stripped_acacia_log", + "stripped_dark_oak_log", + "stripped_oak_wood", + "stripped_spruce_wood", + "stripped_birch_wood", + "stripped_jungle_wood", + "stripped_acacia_wood", + "stripped_dark_oak_wood", + "oak_wood", + "spruce_wood", + "birch_wood", + "jungle_wood", + "acacia_wood", + "dark_oak_wood", + "oak_leaves", + "spruce_leaves", + "birch_leaves", + "jungle_leaves", + "acacia_leaves", + "dark_oak_leaves", + "sponge", + "wet_sponge", + "glass", + "lapis_ore", + "lapis_block", + "dispenser", + "sandstone", + "chiseled_sandstone", + "cut_sandstone", + "note_block", + "powered_rail", + "detector_rail", + "sticky_piston", + "cobweb", + "grass", + "fern", + "dead_bush", + "seagrass", + "sea_pickle", + "piston", + "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", + "dandelion", + "poppy", + "blue_orchid", + "allium", + "azure_bluet", + "red_tulip", + "orange_tulip", + "white_tulip", + "pink_tulip", + "oxeye_daisy", + "brown_mushroom", + "red_mushroom", + "gold_block", + "iron_block", + "oak_slab", + "spruce_slab", + "birch_slab", + "jungle_slab", + "acacia_slab", + "dark_oak_slab", + "stone_slab", + "sandstone_slab", + "petrified_oak_slab", + "cobblestone_slab", + "brick_slab", + "stone_brick_slab", + "nether_brick_slab", + "quartz_slab", + "red_sandstone_slab", + "purpur_slab", + "prismarine_slab", + "prismarine_brick_slab", + "dark_prismarine_slab", + "smooth_quartz", + "smooth_red_sandstone", + "smooth_sandstone", + "smooth_stone", + "bricks", + "tnt", + "bookshelf", + "mossy_cobblestone", + "obsidian", + "torch", + "end_rod", + "chorus_plant", + "chorus_flower", + "purpur_block", + "purpur_pillar", + "purpur_stairs", + "spawner", + "oak_stairs", + "chest", + "diamond_ore", + "diamond_block", + "crafting_table", + "farmland", + "furnace", + "ladder", + "rail", + "cobblestone_stairs", + "lever", + "stone_pressure_plate", + "oak_pressure_plate", + "spruce_pressure_plate", + "birch_pressure_plate", + "jungle_pressure_plate", + "acacia_pressure_plate", + "dark_oak_pressure_plate", + "redstone_ore", + "redstone_torch", + "stone_button", + "snow", + "ice", + "snow_block", + "cactus", + "clay", + "jukebox", + "oak_fence", + "spruce_fence", + "birch_fence", + "jungle_fence", + "acacia_fence", + "dark_oak_fence", + "pumpkin", + "carved_pumpkin", + "netherrack", + "soul_sand", + "glowstone", + "jack_o_lantern", + "oak_trapdoor", + "spruce_trapdoor", + "birch_trapdoor", + "jungle_trapdoor", + "acacia_trapdoor", + "dark_oak_trapdoor", + "infested_stone", + "infested_cobblestone", + "infested_stone_bricks", + "infested_mossy_stone_bricks", + "infested_cracked_stone_bricks", + "infested_chiseled_stone_bricks", + "stone_bricks", + "mossy_stone_bricks", + "cracked_stone_bricks", + "chiseled_stone_bricks", + "brown_mushroom_block", + "red_mushroom_block", + "mushroom_stem", + "iron_bars", + "glass_pane", + "melon", + "vine", + "oak_fence_gate", + "spruce_fence_gate", + "birch_fence_gate", + "jungle_fence_gate", + "acacia_fence_gate", + "dark_oak_fence_gate", + "brick_stairs", + "stone_brick_stairs", + "mycelium", + "lily_pad", + "nether_bricks", + "nether_brick_fence", + "nether_brick_stairs", + "enchanting_table", + "end_portal_frame", + "end_stone", + "end_stone_bricks", + "dragon_egg", + "redstone_lamp", + "sandstone_stairs", + "emerald_ore", + "ender_chest", + "tripwire_hook", + "emerald_block", + "spruce_stairs", + "birch_stairs", + "jungle_stairs", + "command_block", + "beacon", + "cobblestone_wall", + "mossy_cobblestone_wall", + "oak_button", + "spruce_button", + "birch_button", + "jungle_button", + "acacia_button", + "dark_oak_button", + "anvil", + "chipped_anvil", + "damaged_anvil", + "trapped_chest", + "light_weighted_pressure_plate", + "heavy_weighted_pressure_plate", + "daylight_detector", + "redstone_block", + "nether_quartz_ore", + "hopper", + "chiseled_quartz_block", + "quartz_block", + "quartz_pillar", + "quartz_stairs", + "activator_rail", + "dropper", + "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", + "barrier", + "iron_trapdoor", + "hay_block", + "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", + "terracotta", + "coal_block", + "packed_ice", + "acacia_stairs", + "dark_oak_stairs", + "slime_block", + "grass_path", + "sunflower", + "lilac", + "rose_bush", + "peony", + "tall_grass", + "large_fern", + "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", + "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", + "prismarine", + "prismarine_bricks", + "dark_prismarine", + "prismarine_stairs", + "prismarine_brick_stairs", + "dark_prismarine_stairs", + "sea_lantern", + "red_sandstone", + "chiseled_red_sandstone", + "cut_red_sandstone", + "red_sandstone_stairs", + "repeating_command_block", + "chain_command_block", + "magma_block", + "nether_wart_block", + "red_nether_bricks", + "bone_block", + "structure_void", + "observer", + "shulker_box", + "white_shulker_box", + "orange_shulker_box", + "magenta_shulker_box", + "light_blue_shulker_box", + "yellow_shulker_box", + "lime_shulker_box", + "pink_shulker_box", + "gray_shulker_box", + "light_gray_shulker_box", + "cyan_shulker_box", + "purple_shulker_box", + "blue_shulker_box", + "brown_shulker_box", + "green_shulker_box", + "red_shulker_box", + "black_shulker_box", + "white_glazed_terracotta", + "orange_glazed_terracotta", + "magenta_glazed_terracotta", + "light_blue_glazed_terracotta", + "yellow_glazed_terracotta", + "lime_glazed_terracotta", + "pink_glazed_terracotta", + "gray_glazed_terracotta", + "light_gray_glazed_terracotta", + "cyan_glazed_terracotta", + "purple_glazed_terracotta", + "blue_glazed_terracotta", + "brown_glazed_terracotta", + "green_glazed_terracotta", + "red_glazed_terracotta", + "black_glazed_terracotta", + "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", + "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", + "turtle_egg", + "dead_tube_coral_block", + "dead_brain_coral_block", + "dead_bubble_coral_block", + "dead_fire_coral_block", + "dead_horn_coral_block", + "tube_coral_block", + "brain_coral_block", + "bubble_coral_block", + "fire_coral_block", + "horn_coral_block", + "tube_coral", + "brain_coral", + "bubble_coral", + "fire_coral", + "horn_coral", + "dead_brain_coral", + "dead_bubble_coral", + "dead_fire_coral", + "dead_horn_coral", + "dead_tube_coral", + "tube_coral_fan", + "brain_coral_fan", + "bubble_coral_fan", + "fire_coral_fan", + "horn_coral_fan", + "dead_tube_coral_fan", + "dead_brain_coral_fan", + "dead_bubble_coral_fan", + "dead_fire_coral_fan", + "dead_horn_coral_fan", + "blue_ice", + "conduit", + "iron_door", + "oak_door", + "spruce_door", + "birch_door", + "jungle_door", + "acacia_door", + "dark_oak_door", + "repeater", + "comparator", + "structure_block", + "turtle_helmet", + "scute", + "iron_shovel", + "iron_pickaxe", + "iron_axe", + "flint_and_steel", + "apple", + "bow", + "arrow", + "coal", + "charcoal", + "diamond", + "iron_ingot", + "gold_ingot", + "iron_sword", + "wooden_sword", + "wooden_shovel", + "wooden_pickaxe", + "wooden_axe", + "stone_sword", + "stone_shovel", + "stone_pickaxe", + "stone_axe", + "diamond_sword", + "diamond_shovel", + "diamond_pickaxe", + "diamond_axe", + "stick", + "bowl", + "mushroom_stew", + "golden_sword", + "golden_shovel", + "golden_pickaxe", + "golden_axe", + "string", + "feather", + "gunpowder", + "wooden_hoe", + "stone_hoe", + "iron_hoe", + "diamond_hoe", + "golden_hoe", + "wheat_seeds", + "wheat", + "bread", + "leather_helmet", + "leather_chestplate", + "leather_leggings", + "leather_boots", + "chainmail_helmet", + "chainmail_chestplate", + "chainmail_leggings", + "chainmail_boots", + "iron_helmet", + "iron_chestplate", + "iron_leggings", + "iron_boots", + "diamond_helmet", + "diamond_chestplate", + "diamond_leggings", + "diamond_boots", + "golden_helmet", + "golden_chestplate", + "golden_leggings", + "golden_boots", + "flint", + "porkchop", + "cooked_porkchop", + "painting", + "golden_apple", + "enchanted_golden_apple", + "sign", + "bucket", + "water_bucket", + "lava_bucket", + "minecart", + "saddle", + "redstone", + "snowball", + "oak_boat", + "leather", + "milk_bucket", + "pufferfish_bucket", + "salmon_bucket", + "cod_bucket", + "tropical_fish_bucket", + "brick", + "clay_ball", + "sugar_cane", + "kelp", + "dried_kelp_block", + "paper", + "book", + "slime_ball", + "chest_minecart", + "furnace_minecart", + "egg", + "compass", + "fishing_rod", + "clock", + "glowstone_dust", + "cod", + "salmon", + "tropical_fish", + "pufferfish", + "cooked_cod", + "cooked_salmon", + "ink_sac", + "rose_red", + "cactus_green", + "cocoa_beans", + "lapis_lazuli", + "purple_dye", + "cyan_dye", + "light_gray_dye", + "gray_dye", + "pink_dye", + "lime_dye", + "dandelion_yellow", + "light_blue_dye", + "magenta_dye", + "orange_dye", + "bone_meal", + "bone", + "sugar", + "cake", + "white_bed", + "orange_bed", + "magenta_bed", + "light_blue_bed", + "yellow_bed", + "lime_bed", + "pink_bed", + "gray_bed", + "light_gray_bed", + "cyan_bed", + "purple_bed", + "blue_bed", + "brown_bed", + "green_bed", + "red_bed", + "black_bed", + "cookie", + "filled_map", + "shears", + "melon_slice", + "dried_kelp", + "pumpkin_seeds", + "melon_seeds", + "beef", + "cooked_beef", + "chicken", + "cooked_chicken", + "rotten_flesh", + "ender_pearl", + "blaze_rod", + "ghast_tear", + "gold_nugget", + "nether_wart", + "potion", + "glass_bottle", + "spider_eye", + "fermented_spider_eye", + "blaze_powder", + "magma_cream", + "brewing_stand", + "cauldron", + "ender_eye", + "glistering_melon_slice", + "bat_spawn_egg", + "blaze_spawn_egg", + "cave_spider_spawn_egg", + "chicken_spawn_egg", + "cod_spawn_egg", + "cow_spawn_egg", + "creeper_spawn_egg", + "dolphin_spawn_egg", + "donkey_spawn_egg", + "drowned_spawn_egg", + "elder_guardian_spawn_egg", + "enderman_spawn_egg", + "endermite_spawn_egg", + "evoker_spawn_egg", + "ghast_spawn_egg", + "guardian_spawn_egg", + "horse_spawn_egg", + "husk_spawn_egg", + "llama_spawn_egg", + "magma_cube_spawn_egg", + "mooshroom_spawn_egg", + "mule_spawn_egg", + "ocelot_spawn_egg", + "parrot_spawn_egg", + "phantom_spawn_egg", + "pig_spawn_egg", + "polar_bear_spawn_egg", + "pufferfish_spawn_egg", + "rabbit_spawn_egg", + "salmon_spawn_egg", + "sheep_spawn_egg", + "shulker_spawn_egg", + "silverfish_spawn_egg", + "skeleton_spawn_egg", + "skeleton_horse_spawn_egg", + "slime_spawn_egg", + "spider_spawn_egg", + "squid_spawn_egg", + "stray_spawn_egg", + "tropical_fish_spawn_egg", + "turtle_spawn_egg", + "vex_spawn_egg", + "villager_spawn_egg", + "vindicator_spawn_egg", + "witch_spawn_egg", + "wither_skeleton_spawn_egg", + "wolf_spawn_egg", + "zombie_spawn_egg", + "zombie_horse_spawn_egg", + "zombie_pigman_spawn_egg", + "zombie_villager_spawn_egg", + "experience_bottle", + "fire_charge", + "writable_book", + "written_book", + "emerald", + "item_frame", + "flower_pot", + "carrot", + "potato", + "baked_potato", + "poisonous_potato", + "map", + "golden_carrot", + "skeleton_skull", + "wither_skeleton_skull", + "player_head", + "zombie_head", + "creeper_head", + "dragon_head", + "carrot_on_a_stick", + "nether_star", + "pumpkin_pie", + "firework_rocket", + "firework_star", + "enchanted_book", + "nether_brick", + "quartz", + "tnt_minecart", + "hopper_minecart", + "prismarine_shard", + "prismarine_crystals", + "rabbit", + "cooked_rabbit", + "rabbit_stew", + "rabbit_foot", + "rabbit_hide", + "armor_stand", + "iron_horse_armor", + "golden_horse_armor", + "diamond_horse_armor", + "lead", + "name_tag", + "command_block_minecart", + "mutton", + "cooked_mutton", + "white_banner", + "orange_banner", + "magenta_banner", + "light_blue_banner", + "yellow_banner", + "lime_banner", + "pink_banner", + "gray_banner", + "light_gray_banner", + "cyan_banner", + "purple_banner", + "blue_banner", + "brown_banner", + "green_banner", + "red_banner", + "black_banner", + "end_crystal", + "chorus_fruit", + "popped_chorus_fruit", + "beetroot", + "beetroot_seeds", + "beetroot_soup", + "dragon_breath", + "splash_potion", + "spectral_arrow", + "tipped_arrow", + "lingering_potion", + "shield", + "elytra", + "spruce_boat", + "birch_boat", + "jungle_boat", + "acacia_boat", + "dark_oak_boat", + "totem_of_undying", + "shulker_shell", + "iron_nugget", + "knowledge_book", + "debug_stick", + "music_disc_13", + "music_disc_cat", + "music_disc_blocks", + "music_disc_chirp", + "music_disc_far", + "music_disc_mall", + "music_disc_mellohi", + "music_disc_stal", + "music_disc_strad", + "music_disc_ward", + "music_disc_11", + "music_disc_wait", + "trident", + "phantom_membrane", + "nautilus_shell", + "heart_of_the_sea", ], + ), + Property( + on: "item", + name: "display_name", + reverse: false, + type: string, + mapping: { + "air": "Air", + "stone": "Stone", + "granite": "Granite", + "polished_granite": "Polished Granite", + "diorite": "Diorite", + "polished_diorite": "Polished Diorite", + "andesite": "Andesite", + "polished_andesite": "Polished Andesite", + "grass_block": "Grass Block", + "dirt": "Dirt", + "coarse_dirt": "Coarse Dirt", + "podzol": "Podzol", + "cobblestone": "Cobblestone", + "oak_planks": "Oak Planks", + "spruce_planks": "Spruce Planks", + "birch_planks": "Birch Planks", + "jungle_planks": "Jungle Planks", + "acacia_planks": "Acacia Planks", + "dark_oak_planks": "Dark Oak Planks", + "oak_sapling": "Oak Sapling", + "spruce_sapling": "Spruce Sapling", + "birch_sapling": "Birch Sapling", + "jungle_sapling": "Jungle Sapling", + "acacia_sapling": "Acacia Sapling", + "dark_oak_sapling": "Dark Oak Sapling", + "bedrock": "Bedrock", + "sand": "Sand", + "red_sand": "Red Sand", + "gravel": "Gravel", + "gold_ore": "Gold Ore", + "iron_ore": "Iron Ore", + "coal_ore": "Coal Ore", + "oak_log": "Oak Log", + "spruce_log": "Spruce Log", + "birch_log": "Birch Log", + "jungle_log": "Jungle Log", + "acacia_log": "Acacia Log", + "dark_oak_log": "Dark Oak Log", + "stripped_oak_log": "Stripped Oak Log", + "stripped_spruce_log": "Stripped Spruce Log", + "stripped_birch_log": "Stripped Birch Log", + "stripped_jungle_log": "Stripped Jungle Log", + "stripped_acacia_log": "Stripped Acacia Log", + "stripped_dark_oak_log": "Stripped Dark Oak Log", + "stripped_oak_wood": "Stripped Oak Wood", + "stripped_spruce_wood": "Stripped Spruce Wood", + "stripped_birch_wood": "Stripped Birch Wood", + "stripped_jungle_wood": "Stripped Jungle Wood", + "stripped_acacia_wood": "Stripped Acacia Wood", + "stripped_dark_oak_wood": "Stripped Dark Oak Wood", + "oak_wood": "Oak Wood", + "spruce_wood": "Spruce Wood", + "birch_wood": "Birch Wood", + "jungle_wood": "Jungle Wood", + "acacia_wood": "Acacia Wood", + "dark_oak_wood": "Dark Oak Wood", + "oak_leaves": "Oak Leaves", + "spruce_leaves": "Spruce Leaves", + "birch_leaves": "Birch Leaves", + "jungle_leaves": "Jungle Leaves", + "acacia_leaves": "Acacia Leaves", + "dark_oak_leaves": "Dark Oak Leaves", + "sponge": "Sponge", + "wet_sponge": "Wet Sponge", + "glass": "Glass", + "lapis_ore": "Lapis Lazuli Ore", + "lapis_block": "Lapis Lazuli Block", + "dispenser": "Dispenser", + "sandstone": "Sandstone", + "chiseled_sandstone": "Chiseled Sandstone", + "cut_sandstone": "Cut Sandstone", + "note_block": "Note Block", + "powered_rail": "Powered Rail", + "detector_rail": "Detector Rail", + "sticky_piston": "Sticky Piston", + "cobweb": "Cobweb", + "grass": "Grass", + "fern": "Fern", + "dead_bush": "Dead Bush", + "seagrass": "Seagrass", + "sea_pickle": "Sea Pickle", + "piston": "Piston", + "white_wool": "White Wool", + "orange_wool": "Orange Wool", + "magenta_wool": "Magenta Wool", + "light_blue_wool": "Light Blue Wool", + "yellow_wool": "Yellow Wool", + "lime_wool": "Lime Wool", + "pink_wool": "Pink Wool", + "gray_wool": "Gray Wool", + "light_gray_wool": "Light Gray Wool", + "cyan_wool": "Cyan Wool", + "purple_wool": "Purple Wool", + "blue_wool": "Blue Wool", + "brown_wool": "Brown Wool", + "green_wool": "Green Wool", + "red_wool": "Red Wool", + "black_wool": "Black Wool", + "dandelion": "Dandelion", + "poppy": "Poppy", + "blue_orchid": "Blue Orchid", + "allium": "Allium", + "azure_bluet": "Azure Bluet", + "red_tulip": "Red Tulip", + "orange_tulip": "Orange Tulip", + "white_tulip": "White Tulip", + "pink_tulip": "Pink Tulip", + "oxeye_daisy": "Oxeye Daisy", + "brown_mushroom": "Brown Mushroom", + "red_mushroom": "Red Mushroom", + "gold_block": "Block of Gold", + "iron_block": "Block of Iron", + "oak_slab": "Oak Slab", + "spruce_slab": "Spruce Slab", + "birch_slab": "Birch Slab", + "jungle_slab": "Jungle Slab", + "acacia_slab": "Acacia Slab", + "dark_oak_slab": "Dark Oak Slab", + "stone_slab": "Stone Slab", + "sandstone_slab": "Sandstone Slab", + "petrified_oak_slab": "Petrified Oak Slab", + "cobblestone_slab": "Cobblestone Slab", + "brick_slab": "Brick Slab", + "stone_brick_slab": "Stone Brick Slab", + "nether_brick_slab": "Nether Brick Slab", + "quartz_slab": "Quartz Slab", + "red_sandstone_slab": "Red Sandstone Slab", + "purpur_slab": "Purpur Slab", + "prismarine_slab": "Prismarine Slab", + "prismarine_brick_slab": "Prismarine Brick Slab", + "dark_prismarine_slab": "Dark Prismarine Slab", + "smooth_quartz": "Smooth Quartz", + "smooth_red_sandstone": "Smooth Red Sandstone", + "smooth_sandstone": "Smooth Sandstone", + "smooth_stone": "Smooth Stone", + "bricks": "Bricks", + "tnt": "TNT", + "bookshelf": "Bookshelf", + "mossy_cobblestone": "Mossy Cobblestone", + "obsidian": "Obsidian", + "torch": "Torch", + "end_rod": "End Rod", + "chorus_plant": "Chorus Plant", + "chorus_flower": "Chorus Flower", + "purpur_block": "Purpur Block", + "purpur_pillar": "Purpur Pillar", + "purpur_stairs": "Purpur Stairs", + "spawner": "Spawner", + "oak_stairs": "Oak Stairs", + "chest": "Chest", + "diamond_ore": "Diamond Ore", + "diamond_block": "Block of Diamond", + "crafting_table": "Crafting Table", + "farmland": "Farmland", + "furnace": "Furnace", + "ladder": "Ladder", + "rail": "Rail", + "cobblestone_stairs": "Cobblestone Stairs", + "lever": "Lever", + "stone_pressure_plate": "Stone Pressure Plate", + "oak_pressure_plate": "Oak Pressure Plate", + "spruce_pressure_plate": "Spruce Pressure Plate", + "birch_pressure_plate": "Birch Pressure Plate", + "jungle_pressure_plate": "Jungle Pressure Plate", + "acacia_pressure_plate": "Acacia Pressure Plate", + "dark_oak_pressure_plate": "Dark Oak Pressure Plate", + "redstone_ore": "Redstone Ore", + "redstone_torch": "Redstone Torch", + "stone_button": "Stone Button", + "snow": "Snow", + "ice": "Ice", + "snow_block": "Snow Block", + "cactus": "Cactus", + "clay": "Clay", + "jukebox": "Jukebox", + "oak_fence": "Oak Fence", + "spruce_fence": "Spruce Fence", + "birch_fence": "Birch Fence", + "jungle_fence": "Jungle Fence", + "acacia_fence": "Acacia Fence", + "dark_oak_fence": "Dark Oak Fence", + "pumpkin": "Pumpkin", + "carved_pumpkin": "Carved Pumpkin", + "netherrack": "Netherrack", + "soul_sand": "Soul Sand", + "glowstone": "Glowstone", + "jack_o_lantern": "Jack o\'Lantern", + "oak_trapdoor": "Oak Trapdoor", + "spruce_trapdoor": "Spruce Trapdoor", + "birch_trapdoor": "Birch Trapdoor", + "jungle_trapdoor": "Jungle Trapdoor", + "acacia_trapdoor": "Acacia Trapdoor", + "dark_oak_trapdoor": "Dark Oak Trapdoor", + "infested_stone": "Infested Stone", + "infested_cobblestone": "Infested Cobblestone", + "infested_stone_bricks": "Infested Stone Bricks", + "infested_mossy_stone_bricks": "Infested Mossy Stone Bricks", + "infested_cracked_stone_bricks": "Infested Cracked Stone Bricks", + "infested_chiseled_stone_bricks": "Infested Chiseled Stone Bricks", + "stone_bricks": "Stone Bricks", + "mossy_stone_bricks": "Mossy Stone Bricks", + "cracked_stone_bricks": "Cracked Stone Bricks", + "chiseled_stone_bricks": "Chiseled Stone Bricks", + "brown_mushroom_block": "Brown Mushroom Block", + "red_mushroom_block": "Red Mushroom Block", + "mushroom_stem": "Mushroom Stem", + "iron_bars": "Iron Bars", + "glass_pane": "Glass Pane", + "melon": "Melon", + "vine": "Vines", + "oak_fence_gate": "Oak Fence Gate", + "spruce_fence_gate": "Spruce Fence Gate", + "birch_fence_gate": "Birch Fence Gate", + "jungle_fence_gate": "Jungle Fence Gate", + "acacia_fence_gate": "Acacia Fence Gate", + "dark_oak_fence_gate": "Dark Oak Fence Gate", + "brick_stairs": "Brick Stairs", + "stone_brick_stairs": "Stone Brick Stairs", + "mycelium": "Mycelium", + "lily_pad": "Lily Pad", + "nether_bricks": "Nether Bricks", + "nether_brick_fence": "Nether Brick Fence", + "nether_brick_stairs": "Nether Brick Stairs", + "enchanting_table": "Enchanting Table", + "end_portal_frame": "End Portal Frame", + "end_stone": "End Stone", + "end_stone_bricks": "End Stone Bricks", + "dragon_egg": "Dragon Egg", + "redstone_lamp": "Redstone Lamp", + "sandstone_stairs": "Sandstone Stairs", + "emerald_ore": "Emerald Ore", + "ender_chest": "Ender Chest", + "tripwire_hook": "Tripwire Hook", + "emerald_block": "Block of Emerald", + "spruce_stairs": "Spruce Stairs", + "birch_stairs": "Birch Stairs", + "jungle_stairs": "Jungle Stairs", + "command_block": "Command Block", + "beacon": "Beacon", + "cobblestone_wall": "Cobblestone Wall", + "mossy_cobblestone_wall": "Mossy Cobblestone Wall", + "oak_button": "Oak Button", + "spruce_button": "Spruce Button", + "birch_button": "Birch Button", + "jungle_button": "Jungle Button", + "acacia_button": "Acacia Button", + "dark_oak_button": "Dark Oak Button", + "anvil": "Anvil", + "chipped_anvil": "Chipped Anvil", + "damaged_anvil": "Damaged Anvil", + "trapped_chest": "Trapped Chest", + "light_weighted_pressure_plate": "Light Weighted Pressure Plate", + "heavy_weighted_pressure_plate": "Heavy Weighted Pressure Plate", + "daylight_detector": "Daylight Detector", + "redstone_block": "Block of Redstone", + "nether_quartz_ore": "Nether Quartz Ore", + "hopper": "Hopper", + "chiseled_quartz_block": "Chiseled Quartz Block", + "quartz_block": "Block of Quartz", + "quartz_pillar": "Quartz Pillar", + "quartz_stairs": "Quartz Stairs", + "activator_rail": "Activator Rail", + "dropper": "Dropper", + "white_terracotta": "White Terracotta", + "orange_terracotta": "Orange Terracotta", + "magenta_terracotta": "Magenta Terracotta", + "light_blue_terracotta": "Light Blue Terracotta", + "yellow_terracotta": "Yellow Terracotta", + "lime_terracotta": "Lime Terracotta", + "pink_terracotta": "Pink Terracotta", + "gray_terracotta": "Gray Terracotta", + "light_gray_terracotta": "Light Gray Terracotta", + "cyan_terracotta": "Cyan Terracotta", + "purple_terracotta": "Purple Terracotta", + "blue_terracotta": "Blue Terracotta", + "brown_terracotta": "Brown Terracotta", + "green_terracotta": "Green Terracotta", + "red_terracotta": "Red Terracotta", + "black_terracotta": "Black Terracotta", + "barrier": "Barrier", + "iron_trapdoor": "Iron Trapdoor", + "hay_block": "Hay Bale", + "white_carpet": "White Carpet", + "orange_carpet": "Orange Carpet", + "magenta_carpet": "Magenta Carpet", + "light_blue_carpet": "Light Blue Carpet", + "yellow_carpet": "Yellow Carpet", + "lime_carpet": "Lime Carpet", + "pink_carpet": "Pink Carpet", + "gray_carpet": "Gray Carpet", + "light_gray_carpet": "Light Gray Carpet", + "cyan_carpet": "Cyan Carpet", + "purple_carpet": "Purple Carpet", + "blue_carpet": "Blue Carpet", + "brown_carpet": "Brown Carpet", + "green_carpet": "Green Carpet", + "red_carpet": "Red Carpet", + "black_carpet": "Black Carpet", + "terracotta": "Terracotta", + "coal_block": "Block of Coal", + "packed_ice": "Packed Ice", + "acacia_stairs": "Acacia Stairs", + "dark_oak_stairs": "Dark Oak Stairs", + "slime_block": "Slime Block", + "grass_path": "Grass Path", + "sunflower": "Sunflower", + "lilac": "Lilac", + "rose_bush": "Rose Bush", + "peony": "Peony", + "tall_grass": "Tall Grass", + "large_fern": "Large Fern", + "white_stained_glass": "White Stained Glass", + "orange_stained_glass": "Orange Stained Glass", + "magenta_stained_glass": "Magenta Stained Glass", + "light_blue_stained_glass": "Light Blue Stained Glass", + "yellow_stained_glass": "Yellow Stained Glass", + "lime_stained_glass": "Lime Stained Glass", + "pink_stained_glass": "Pink Stained Glass", + "gray_stained_glass": "Gray Stained Glass", + "light_gray_stained_glass": "Light Gray Stained Glass", + "cyan_stained_glass": "Cyan Stained Glass", + "purple_stained_glass": "Purple Stained Glass", + "blue_stained_glass": "Blue Stained Glass", + "brown_stained_glass": "Brown Stained Glass", + "green_stained_glass": "Green Stained Glass", + "red_stained_glass": "Red Stained Glass", + "black_stained_glass": "Black Stained Glass", + "white_stained_glass_pane": "White Stained Glass Pane", + "orange_stained_glass_pane": "Orange Stained Glass Pane", + "magenta_stained_glass_pane": "Magenta Stained Glass Pane", + "light_blue_stained_glass_pane": "Light Blue Stained Glass Pane", + "yellow_stained_glass_pane": "Yellow Stained Glass Pane", + "lime_stained_glass_pane": "Lime Stained Glass Pane", + "pink_stained_glass_pane": "Pink Stained Glass Pane", + "gray_stained_glass_pane": "Gray Stained Glass Pane", + "light_gray_stained_glass_pane": "Light Gray Stained Glass Pane", + "cyan_stained_glass_pane": "Cyan Stained Glass Pane", + "purple_stained_glass_pane": "Purple Stained Glass Pane", + "blue_stained_glass_pane": "Blue Stained Glass Pane", + "brown_stained_glass_pane": "Brown Stained Glass Pane", + "green_stained_glass_pane": "Green Stained Glass Pane", + "red_stained_glass_pane": "Red Stained Glass Pane", + "black_stained_glass_pane": "Black Stained Glass Pane", + "prismarine": "Prismarine", + "prismarine_bricks": "Prismarine Bricks", + "dark_prismarine": "Dark Prismarine", + "prismarine_stairs": "Prismarine Stairs", + "prismarine_brick_stairs": "Prismarine Brick Stairs", + "dark_prismarine_stairs": "Dark Prismarine Stairs", + "sea_lantern": "Sea Lantern", + "red_sandstone": "Red Sandstone", + "chiseled_red_sandstone": "Chiseled Red Sandstone", + "cut_red_sandstone": "Cut Red Sandstone", + "red_sandstone_stairs": "Red Sandstone Stairs", + "repeating_command_block": "Repeating Command Block", + "chain_command_block": "Chain Command Block", + "magma_block": "Magma Block", + "nether_wart_block": "Nether Wart Block", + "red_nether_bricks": "Red Nether Bricks", + "bone_block": "Bone Block", + "structure_void": "Structure Void", + "observer": "Observer", + "shulker_box": "Shulker Box", + "white_shulker_box": "White Shulker Box", + "orange_shulker_box": "Orange Shulker Box", + "magenta_shulker_box": "Magenta Shulker Box", + "light_blue_shulker_box": "Light Blue Shulker Box", + "yellow_shulker_box": "Yellow Shulker Box", + "lime_shulker_box": "Lime Shulker Box", + "pink_shulker_box": "Pink Shulker Box", + "gray_shulker_box": "Gray Shulker Box", + "light_gray_shulker_box": "Light Gray Shulker Box", + "cyan_shulker_box": "Cyan Shulker Box", + "purple_shulker_box": "Purple Shulker Box", + "blue_shulker_box": "Blue Shulker Box", + "brown_shulker_box": "Brown Shulker Box", + "green_shulker_box": "Green Shulker Box", + "red_shulker_box": "Red Shulker Box", + "black_shulker_box": "Black Shulker Box", + "white_glazed_terracotta": "White Glazed Terracotta", + "orange_glazed_terracotta": "Orange Glazed Terracotta", + "magenta_glazed_terracotta": "Magenta Glazed Terracotta", + "light_blue_glazed_terracotta": "Light Blue Glazed Terracotta", + "yellow_glazed_terracotta": "Yellow Glazed Terracotta", + "lime_glazed_terracotta": "Lime Glazed Terracotta", + "pink_glazed_terracotta": "Pink Glazed Terracotta", + "gray_glazed_terracotta": "Gray Glazed Terracotta", + "light_gray_glazed_terracotta": "Light Gray Glazed Terracotta", + "cyan_glazed_terracotta": "Cyan Glazed Terracotta", + "purple_glazed_terracotta": "Purple Glazed Terracotta", + "blue_glazed_terracotta": "Blue Glazed Terracotta", + "brown_glazed_terracotta": "Brown Glazed Terracotta", + "green_glazed_terracotta": "Green Glazed Terracotta", + "red_glazed_terracotta": "Red Glazed Terracotta", + "black_glazed_terracotta": "Black Glazed Terracotta", + "white_concrete": "White Concrete", + "orange_concrete": "Orange Concrete", + "magenta_concrete": "Magenta Concrete", + "light_blue_concrete": "Light Blue Concrete", + "yellow_concrete": "Yellow Concrete", + "lime_concrete": "Lime Concrete", + "pink_concrete": "Pink Concrete", + "gray_concrete": "Gray Concrete", + "light_gray_concrete": "Light Gray Concrete", + "cyan_concrete": "Cyan Concrete", + "purple_concrete": "Purple Concrete", + "blue_concrete": "Blue Concrete", + "brown_concrete": "Brown Concrete", + "green_concrete": "Green Concrete", + "red_concrete": "Red Concrete", + "black_concrete": "Black Concrete", + "white_concrete_powder": "White Concrete Powder", + "orange_concrete_powder": "Orange Concrete Powder", + "magenta_concrete_powder": "Magenta Concrete Powder", + "light_blue_concrete_powder": "Light Blue Concrete Powder", + "yellow_concrete_powder": "Yellow Concrete Powder", + "lime_concrete_powder": "Lime Concrete Powder", + "pink_concrete_powder": "Pink Concrete Powder", + "gray_concrete_powder": "Gray Concrete Powder", + "light_gray_concrete_powder": "Light Gray Concrete Powder", + "cyan_concrete_powder": "Cyan Concrete Powder", + "purple_concrete_powder": "Purple Concrete Powder", + "blue_concrete_powder": "Blue Concrete Powder", + "brown_concrete_powder": "Brown Concrete Powder", + "green_concrete_powder": "Green Concrete Powder", + "red_concrete_powder": "Red Concrete Powder", + "black_concrete_powder": "Black Concrete Powder", + "turtle_egg": "Turtle Egg", + "dead_tube_coral_block": "Dead Tube Coral Block", + "dead_brain_coral_block": "Dead Brain Coral Block", + "dead_bubble_coral_block": "Dead Bubble Coral Block", + "dead_fire_coral_block": "Dead Fire Coral Block", + "dead_horn_coral_block": "Dead Horn Coral Block", + "tube_coral_block": "Tube Coral Block", + "brain_coral_block": "Brain Coral Block", + "bubble_coral_block": "Bubble Coral Block", + "fire_coral_block": "Fire Coral Block", + "horn_coral_block": "Horn Coral Block", + "tube_coral": "Tube Coral", + "brain_coral": "Brain Coral", + "bubble_coral": "Bubble Coral", + "fire_coral": "Fire Coral", + "horn_coral": "Horn Coral", + "dead_brain_coral": "Dead Brain Coral", + "dead_bubble_coral": "Dead Bubble Coral", + "dead_fire_coral": "Dead Fire Coral", + "dead_horn_coral": "Dead Horn Coral", + "dead_tube_coral": "Dead Tube Coral", + "tube_coral_fan": "Tube Coral Fan", + "brain_coral_fan": "Brain Coral Fan", + "bubble_coral_fan": "Bubble Coral Fan", + "fire_coral_fan": "Fire Coral Fan", + "horn_coral_fan": "Horn Coral Fan", + "dead_tube_coral_fan": "Dead Tube Coral Fan", + "dead_brain_coral_fan": "Dead Brain Coral Fan", + "dead_bubble_coral_fan": "Dead Bubble Coral Fan", + "dead_fire_coral_fan": "Dead Fire Coral Fan", + "dead_horn_coral_fan": "Dead Horn Coral Fan", + "blue_ice": "Blue Ice", + "conduit": "Conduit", + "iron_door": "Iron Door", + "oak_door": "Oak Door", + "spruce_door": "Spruce Door", + "birch_door": "Birch Door", + "jungle_door": "Jungle Door", + "acacia_door": "Acacia Door", + "dark_oak_door": "Dark Oak Door", + "repeater": "Redstone Repeater", + "comparator": "Redstone Comparator", + "structure_block": "Structure Block", + "turtle_helmet": "Turtle Shell", + "scute": "Scute", + "iron_shovel": "Iron Shovel", + "iron_pickaxe": "Iron Pickaxe", + "iron_axe": "Iron Axe", + "flint_and_steel": "Flint and Steel", + "apple": "Apple", + "bow": "Bow", + "arrow": "Arrow", + "coal": "Coal", + "charcoal": "Charcoal", + "diamond": "Diamond", + "iron_ingot": "Iron Ingot", + "gold_ingot": "Gold Ingot", + "iron_sword": "Iron Sword", + "wooden_sword": "Wooden Sword", + "wooden_shovel": "Wooden Shovel", + "wooden_pickaxe": "Wooden Pickaxe", + "wooden_axe": "Wooden Axe", + "stone_sword": "Stone Sword", + "stone_shovel": "Stone Shovel", + "stone_pickaxe": "Stone Pickaxe", + "stone_axe": "Stone Axe", + "diamond_sword": "Diamond Sword", + "diamond_shovel": "Diamond Shovel", + "diamond_pickaxe": "Diamond Pickaxe", + "diamond_axe": "Diamond Axe", + "stick": "Stick", + "bowl": "Bowl", + "mushroom_stew": "Mushroom Stew", + "golden_sword": "Golden Sword", + "golden_shovel": "Golden Shovel", + "golden_pickaxe": "Golden Pickaxe", + "golden_axe": "Golden Axe", + "string": "String", + "feather": "Feather", + "gunpowder": "Gunpowder", + "wooden_hoe": "Wooden Hoe", + "stone_hoe": "Stone Hoe", + "iron_hoe": "Iron Hoe", + "diamond_hoe": "Diamond Hoe", + "golden_hoe": "Golden Hoe", + "wheat_seeds": "Wheat Seeds", + "wheat": "Wheat", + "bread": "Bread", + "leather_helmet": "Leather Cap", + "leather_chestplate": "Leather Tunic", + "leather_leggings": "Leather Pants", + "leather_boots": "Leather Boots", + "chainmail_helmet": "Chainmail Helmet", + "chainmail_chestplate": "Chainmail Chestplate", + "chainmail_leggings": "Chainmail Leggings", + "chainmail_boots": "Chainmail Boots", + "iron_helmet": "Iron Helmet", + "iron_chestplate": "Iron Chestplate", + "iron_leggings": "Iron Leggings", + "iron_boots": "Iron Boots", + "diamond_helmet": "Diamond Helmet", + "diamond_chestplate": "Diamond Chestplate", + "diamond_leggings": "Diamond Leggings", + "diamond_boots": "Diamond Boots", + "golden_helmet": "Golden Helmet", + "golden_chestplate": "Golden Chestplate", + "golden_leggings": "Golden Leggings", + "golden_boots": "Golden Boots", + "flint": "Flint", + "porkchop": "Raw Porkchop", + "cooked_porkchop": "Cooked Porkchop", + "painting": "Painting", + "golden_apple": "Golden Apple", + "enchanted_golden_apple": "Enchanted Golden Apple", + "sign": "Sign", + "bucket": "Bucket", + "water_bucket": "Water Bucket", + "lava_bucket": "Lava Bucket", + "minecart": "Minecart", + "saddle": "Saddle", + "redstone": "Redstone", + "snowball": "Snowball", + "oak_boat": "Oak Boat", + "leather": "Leather", + "milk_bucket": "Milk Bucket", + "pufferfish_bucket": "Bucket of Pufferfish", + "salmon_bucket": "Bucket of Salmon", + "cod_bucket": "Bucket of Cod", + "tropical_fish_bucket": "Bucket of Tropical Fish", + "brick": "Brick", + "clay_ball": "Clay", + "sugar_cane": "Sugar Cane", + "kelp": "Kelp", + "dried_kelp_block": "Dried Kelp Block", + "paper": "Paper", + "book": "Book", + "slime_ball": "Slimeball", + "chest_minecart": "Minecart with Chest", + "furnace_minecart": "Minecart with Furnace", + "egg": "Egg", + "compass": "Compass", + "fishing_rod": "Fishing Rod", + "clock": "Clock", + "glowstone_dust": "Glowstone Dust", + "cod": "Raw Cod", + "salmon": "Raw Salmon", + "tropical_fish": "Tropical Fish", + "pufferfish": "Pufferfish", + "cooked_cod": "Cooked Cod", + "cooked_salmon": "Cooked Salmon", + "ink_sac": "Ink Sac", + "rose_red": "Rose Red", + "cactus_green": "Cactus Green", + "cocoa_beans": "Cocoa Beans", + "lapis_lazuli": "Lapis Lazuli", + "purple_dye": "Purple Dye", + "cyan_dye": "Cyan Dye", + "light_gray_dye": "Light Gray Dye", + "gray_dye": "Gray Dye", + "pink_dye": "Pink Dye", + "lime_dye": "Lime Dye", + "dandelion_yellow": "Dandelion Yellow", + "light_blue_dye": "Light Blue Dye", + "magenta_dye": "Magenta Dye", + "orange_dye": "Orange Dye", + "bone_meal": "Bone Meal", + "bone": "Bone", + "sugar": "Sugar", + "cake": "Cake", + "white_bed": "White Bed", + "orange_bed": "Orange Bed", + "magenta_bed": "Magenta Bed", + "light_blue_bed": "Light Blue Bed", + "yellow_bed": "Yellow Bed", + "lime_bed": "Lime Bed", + "pink_bed": "Pink Bed", + "gray_bed": "Gray Bed", + "light_gray_bed": "Light Gray Bed", + "cyan_bed": "Cyan Bed", + "purple_bed": "Purple Bed", + "blue_bed": "Blue Bed", + "brown_bed": "Brown Bed", + "green_bed": "Green Bed", + "red_bed": "Red Bed", + "black_bed": "Black Bed", + "cookie": "Cookie", + "filled_map": "Map", + "shears": "Shears", + "melon_slice": "Melon Slice", + "dried_kelp": "Dried Kelp", + "pumpkin_seeds": "Pumpkin Seeds", + "melon_seeds": "Melon Seeds", + "beef": "Raw Beef", + "cooked_beef": "Steak", + "chicken": "Raw Chicken", + "cooked_chicken": "Cooked Chicken", + "rotten_flesh": "Rotten Flesh", + "ender_pearl": "Ender Pearl", + "blaze_rod": "Blaze Rod", + "ghast_tear": "Ghast Tear", + "gold_nugget": "Gold Nugget", + "nether_wart": "Nether Wart", + "potion": "Potion", + "glass_bottle": "Glass Bottle", + "spider_eye": "Spider Eye", + "fermented_spider_eye": "Fermented Spider Eye", + "blaze_powder": "Blaze Powder", + "magma_cream": "Magma Cream", + "brewing_stand": "Brewing Stand", + "cauldron": "Cauldron", + "ender_eye": "Eye of Ender", + "glistering_melon_slice": "Glistering Melon Slice", + "bat_spawn_egg": "Bat Spawn Egg", + "blaze_spawn_egg": "Blaze Spawn Egg", + "cave_spider_spawn_egg": "Cave Spider Spawn Egg", + "chicken_spawn_egg": "Chicken Spawn Egg", + "cod_spawn_egg": "Cod Spawn Egg", + "cow_spawn_egg": "Cow Spawn Egg", + "creeper_spawn_egg": "Creeper Spawn Egg", + "dolphin_spawn_egg": "Dolphin Spawn Egg", + "donkey_spawn_egg": "Donkey Spawn Egg", + "drowned_spawn_egg": "Drowned Spawn Egg", + "elder_guardian_spawn_egg": "Elder Guardian Spawn Egg", + "enderman_spawn_egg": "Enderman Spawn Egg", + "endermite_spawn_egg": "Endermite Spawn Egg", + "evoker_spawn_egg": "Evoker Spawn Egg", + "ghast_spawn_egg": "Ghast Spawn Egg", + "guardian_spawn_egg": "Guardian Spawn Egg", + "horse_spawn_egg": "Horse Spawn Egg", + "husk_spawn_egg": "Husk Spawn Egg", + "llama_spawn_egg": "Llama Spawn Egg", + "magma_cube_spawn_egg": "Magma Cube Spawn Egg", + "mooshroom_spawn_egg": "Mooshroom Spawn Egg", + "mule_spawn_egg": "Mule Spawn Egg", + "ocelot_spawn_egg": "Ocelot Spawn Egg", + "parrot_spawn_egg": "Parrot Spawn Egg", + "phantom_spawn_egg": "Phantom Spawn Egg", + "pig_spawn_egg": "Pig Spawn Egg", + "polar_bear_spawn_egg": "Polar Bear Spawn Egg", + "pufferfish_spawn_egg": "Pufferfish Spawn Egg", + "rabbit_spawn_egg": "Rabbit Spawn Egg", + "salmon_spawn_egg": "Salmon Spawn Egg", + "sheep_spawn_egg": "Sheep Spawn Egg", + "shulker_spawn_egg": "Shulker Spawn Egg", + "silverfish_spawn_egg": "Silverfish Spawn Egg", + "skeleton_spawn_egg": "Skeleton Spawn Egg", + "skeleton_horse_spawn_egg": "Skeleton Horse Spawn Egg", + "slime_spawn_egg": "Slime Spawn Egg", + "spider_spawn_egg": "Spider Spawn Egg", + "squid_spawn_egg": "Squid Spawn Egg", + "stray_spawn_egg": "Stray Spawn Egg", + "tropical_fish_spawn_egg": "Tropical Fish Spawn Egg", + "turtle_spawn_egg": "Turtle Spawn Egg", + "vex_spawn_egg": "Vex Spawn Egg", + "villager_spawn_egg": "Villager Spawn Egg", + "vindicator_spawn_egg": "Vindicator Spawn Egg", + "witch_spawn_egg": "Witch Spawn Egg", + "wither_skeleton_spawn_egg": "Wither Skeleton Spawn Egg", + "wolf_spawn_egg": "Wolf Spawn Egg", + "zombie_spawn_egg": "Zombie Spawn Egg", + "zombie_horse_spawn_egg": "Zombie Horse Spawn Egg", + "zombie_pigman_spawn_egg": "Zombie Pigman Spawn Egg", + "zombie_villager_spawn_egg": "Zombie Villager Spawn Egg", + "experience_bottle": "Bottle o\' Enchanting", + "fire_charge": "Fire Charge", + "writable_book": "Book and Quill", + "written_book": "Written Book", + "emerald": "Emerald", + "item_frame": "Item Frame", + "flower_pot": "Flower Pot", + "carrot": "Carrot", + "potato": "Potato", + "baked_potato": "Baked Potato", + "poisonous_potato": "Poisonous Potato", + "map": "Empty Map", + "golden_carrot": "Golden Carrot", + "skeleton_skull": "Skeleton Skull", + "wither_skeleton_skull": "Wither Skeleton Skull", + "player_head": "Player Head", + "zombie_head": "Zombie Head", + "creeper_head": "Creeper Head", + "dragon_head": "Dragon Head", + "carrot_on_a_stick": "Carrot on a Stick", + "nether_star": "Nether Star", + "pumpkin_pie": "Pumpkin Pie", + "firework_rocket": "Firework Rocket", + "firework_star": "Firework Star", + "enchanted_book": "Enchanted Book", + "nether_brick": "Nether Brick", + "quartz": "Nether Quartz", + "tnt_minecart": "Minecart with TNT", + "hopper_minecart": "Minecart with Hopper", + "prismarine_shard": "Prismarine Shard", + "prismarine_crystals": "Prismarine Crystals", + "rabbit": "Raw Rabbit", + "cooked_rabbit": "Cooked Rabbit", + "rabbit_stew": "Rabbit Stew", + "rabbit_foot": "Rabbit\'s Foot", + "rabbit_hide": "Rabbit Hide", + "armor_stand": "Armor Stand", + "iron_horse_armor": "Iron Horse Armor", + "golden_horse_armor": "Golden Horse Armor", + "diamond_horse_armor": "Diamond Horse Armor", + "lead": "Lead", + "name_tag": "Name Tag", + "command_block_minecart": "Minecart with Command Block", + "mutton": "Raw Mutton", + "cooked_mutton": "Cooked Mutton", + "white_banner": "White Banner", + "orange_banner": "Orange Banner", + "magenta_banner": "Magenta Banner", + "light_blue_banner": "Light Blue Banner", + "yellow_banner": "Yellow Banner", + "lime_banner": "Lime Banner", + "pink_banner": "Pink Banner", + "gray_banner": "Gray Banner", + "light_gray_banner": "Light Gray Banner", + "cyan_banner": "Cyan Banner", + "purple_banner": "Purple Banner", + "blue_banner": "Blue Banner", + "brown_banner": "Brown Banner", + "green_banner": "Green Banner", + "red_banner": "Red Banner", + "black_banner": "Black Banner", + "end_crystal": "End Crystal", + "chorus_fruit": "Chorus Fruit", + "popped_chorus_fruit": "Popped Chorus Fruit", + "beetroot": "Beetroot", + "beetroot_seeds": "Beetroot Seeds", + "beetroot_soup": "Beetroot Soup", + "dragon_breath": "Dragon\'s Breath", + "splash_potion": "Splash Potion", + "spectral_arrow": "Spectral Arrow", + "tipped_arrow": "Tipped Arrow", + "lingering_potion": "Lingering Potion", + "shield": "Shield", + "elytra": "Elytra", + "spruce_boat": "Spruce Boat", + "birch_boat": "Birch Boat", + "jungle_boat": "Jungle Boat", + "acacia_boat": "Acacia Boat", + "dark_oak_boat": "Dark Oak Boat", + "totem_of_undying": "Totem of Undying", + "shulker_shell": "Shulker Shell", + "iron_nugget": "Iron Nugget", + "knowledge_book": "Knowledge Book", + "debug_stick": "Debug Stick", + "music_disc_13": "13 Disc", + "music_disc_cat": "Cat Disc", + "music_disc_blocks": "Blocks Disc", + "music_disc_chirp": "Chirp Disc", + "music_disc_far": "Far Disc", + "music_disc_mall": "Mall Disc", + "music_disc_mellohi": "Mellohi Disc", + "music_disc_stal": "Stal Disc", + "music_disc_strad": "Strad Disc", + "music_disc_ward": "Ward Disc", + "music_disc_11": "11 Disc", + "music_disc_wait": "Wait Disc", + "trident": "Trident", + "phantom_membrane": "Phantom Membrane", + "nautilus_shell": "Nautilus Shell", + "heart_of_the_sea": "Heart of the Sea", + }, + ), + Property( + on: "item", + name: "stack_size", + reverse: false, + type: u32, + mapping: { + "air": 64, + "stone": 64, + "granite": 64, + "polished_granite": 64, + "diorite": 64, + "polished_diorite": 64, + "andesite": 64, + "polished_andesite": 64, + "grass_block": 64, + "dirt": 64, + "coarse_dirt": 64, + "podzol": 64, + "cobblestone": 64, + "oak_planks": 64, + "spruce_planks": 64, + "birch_planks": 64, + "jungle_planks": 64, + "acacia_planks": 64, + "dark_oak_planks": 64, + "oak_sapling": 64, + "spruce_sapling": 64, + "birch_sapling": 64, + "jungle_sapling": 64, + "acacia_sapling": 64, + "dark_oak_sapling": 64, + "bedrock": 64, + "sand": 64, + "red_sand": 64, + "gravel": 64, + "gold_ore": 64, + "iron_ore": 64, + "coal_ore": 64, + "oak_log": 64, + "spruce_log": 64, + "birch_log": 64, + "jungle_log": 64, + "acacia_log": 64, + "dark_oak_log": 64, + "stripped_oak_log": 64, + "stripped_spruce_log": 64, + "stripped_birch_log": 64, + "stripped_jungle_log": 64, + "stripped_acacia_log": 64, + "stripped_dark_oak_log": 64, + "stripped_oak_wood": 64, + "stripped_spruce_wood": 64, + "stripped_birch_wood": 64, + "stripped_jungle_wood": 64, + "stripped_acacia_wood": 64, + "stripped_dark_oak_wood": 64, + "oak_wood": 64, + "spruce_wood": 64, + "birch_wood": 64, + "jungle_wood": 64, + "acacia_wood": 64, + "dark_oak_wood": 64, + "oak_leaves": 64, + "spruce_leaves": 64, + "birch_leaves": 64, + "jungle_leaves": 64, + "acacia_leaves": 64, + "dark_oak_leaves": 64, + "sponge": 64, + "wet_sponge": 64, + "glass": 64, + "lapis_ore": 64, + "lapis_block": 64, + "dispenser": 64, + "sandstone": 64, + "chiseled_sandstone": 64, + "cut_sandstone": 64, + "note_block": 64, + "powered_rail": 64, + "detector_rail": 64, + "sticky_piston": 64, + "cobweb": 64, + "grass": 64, + "fern": 64, + "dead_bush": 64, + "seagrass": 64, + "sea_pickle": 64, + "piston": 64, + "white_wool": 64, + "orange_wool": 64, + "magenta_wool": 64, + "light_blue_wool": 64, + "yellow_wool": 64, + "lime_wool": 64, + "pink_wool": 64, + "gray_wool": 64, + "light_gray_wool": 64, + "cyan_wool": 64, + "purple_wool": 64, + "blue_wool": 64, + "brown_wool": 64, + "green_wool": 64, + "red_wool": 64, + "black_wool": 64, + "dandelion": 64, + "poppy": 64, + "blue_orchid": 64, + "allium": 64, + "azure_bluet": 64, + "red_tulip": 64, + "orange_tulip": 64, + "white_tulip": 64, + "pink_tulip": 64, + "oxeye_daisy": 64, + "brown_mushroom": 64, + "red_mushroom": 64, + "gold_block": 64, + "iron_block": 64, + "oak_slab": 64, + "spruce_slab": 64, + "birch_slab": 64, + "jungle_slab": 64, + "acacia_slab": 64, + "dark_oak_slab": 64, + "stone_slab": 64, + "sandstone_slab": 64, + "petrified_oak_slab": 64, + "cobblestone_slab": 64, + "brick_slab": 64, + "stone_brick_slab": 64, + "nether_brick_slab": 64, + "quartz_slab": 64, + "red_sandstone_slab": 64, + "purpur_slab": 64, + "prismarine_slab": 64, + "prismarine_brick_slab": 64, + "dark_prismarine_slab": 64, + "smooth_quartz": 64, + "smooth_red_sandstone": 64, + "smooth_sandstone": 64, + "smooth_stone": 64, + "bricks": 64, + "tnt": 64, + "bookshelf": 64, + "mossy_cobblestone": 64, + "obsidian": 64, + "torch": 64, + "end_rod": 64, + "chorus_plant": 64, + "chorus_flower": 64, + "purpur_block": 64, + "purpur_pillar": 64, + "purpur_stairs": 64, + "spawner": 64, + "oak_stairs": 64, + "chest": 64, + "diamond_ore": 64, + "diamond_block": 64, + "crafting_table": 64, + "farmland": 64, + "furnace": 64, + "ladder": 64, + "rail": 64, + "cobblestone_stairs": 64, + "lever": 64, + "stone_pressure_plate": 64, + "oak_pressure_plate": 64, + "spruce_pressure_plate": 64, + "birch_pressure_plate": 64, + "jungle_pressure_plate": 64, + "acacia_pressure_plate": 64, + "dark_oak_pressure_plate": 64, + "redstone_ore": 64, + "redstone_torch": 64, + "stone_button": 64, + "snow": 64, + "ice": 64, + "snow_block": 64, + "cactus": 64, + "clay": 64, + "jukebox": 64, + "oak_fence": 64, + "spruce_fence": 64, + "birch_fence": 64, + "jungle_fence": 64, + "acacia_fence": 64, + "dark_oak_fence": 64, + "pumpkin": 64, + "carved_pumpkin": 64, + "netherrack": 64, + "soul_sand": 64, + "glowstone": 64, + "jack_o_lantern": 64, + "oak_trapdoor": 64, + "spruce_trapdoor": 64, + "birch_trapdoor": 64, + "jungle_trapdoor": 64, + "acacia_trapdoor": 64, + "dark_oak_trapdoor": 64, + "infested_stone": 64, + "infested_cobblestone": 64, + "infested_stone_bricks": 64, + "infested_mossy_stone_bricks": 64, + "infested_cracked_stone_bricks": 64, + "infested_chiseled_stone_bricks": 64, + "stone_bricks": 64, + "mossy_stone_bricks": 64, + "cracked_stone_bricks": 64, + "chiseled_stone_bricks": 64, + "brown_mushroom_block": 64, + "red_mushroom_block": 64, + "mushroom_stem": 64, + "iron_bars": 64, + "glass_pane": 64, + "melon": 64, + "vine": 64, + "oak_fence_gate": 64, + "spruce_fence_gate": 64, + "birch_fence_gate": 64, + "jungle_fence_gate": 64, + "acacia_fence_gate": 64, + "dark_oak_fence_gate": 64, + "brick_stairs": 64, + "stone_brick_stairs": 64, + "mycelium": 64, + "lily_pad": 64, + "nether_bricks": 64, + "nether_brick_fence": 64, + "nether_brick_stairs": 64, + "enchanting_table": 64, + "end_portal_frame": 64, + "end_stone": 64, + "end_stone_bricks": 64, + "dragon_egg": 64, + "redstone_lamp": 64, + "sandstone_stairs": 64, + "emerald_ore": 64, + "ender_chest": 64, + "tripwire_hook": 64, + "emerald_block": 64, + "spruce_stairs": 64, + "birch_stairs": 64, + "jungle_stairs": 64, + "command_block": 64, + "beacon": 64, + "cobblestone_wall": 64, + "mossy_cobblestone_wall": 64, + "oak_button": 64, + "spruce_button": 64, + "birch_button": 64, + "jungle_button": 64, + "acacia_button": 64, + "dark_oak_button": 64, + "anvil": 64, + "chipped_anvil": 64, + "damaged_anvil": 64, + "trapped_chest": 64, + "light_weighted_pressure_plate": 64, + "heavy_weighted_pressure_plate": 64, + "daylight_detector": 64, + "redstone_block": 64, + "nether_quartz_ore": 64, + "hopper": 64, + "chiseled_quartz_block": 64, + "quartz_block": 64, + "quartz_pillar": 64, + "quartz_stairs": 64, + "activator_rail": 64, + "dropper": 64, + "white_terracotta": 64, + "orange_terracotta": 64, + "magenta_terracotta": 64, + "light_blue_terracotta": 64, + "yellow_terracotta": 64, + "lime_terracotta": 64, + "pink_terracotta": 64, + "gray_terracotta": 64, + "light_gray_terracotta": 64, + "cyan_terracotta": 64, + "purple_terracotta": 64, + "blue_terracotta": 64, + "brown_terracotta": 64, + "green_terracotta": 64, + "red_terracotta": 64, + "black_terracotta": 64, + "barrier": 64, + "iron_trapdoor": 64, + "hay_block": 64, + "white_carpet": 64, + "orange_carpet": 64, + "magenta_carpet": 64, + "light_blue_carpet": 64, + "yellow_carpet": 64, + "lime_carpet": 64, + "pink_carpet": 64, + "gray_carpet": 64, + "light_gray_carpet": 64, + "cyan_carpet": 64, + "purple_carpet": 64, + "blue_carpet": 64, + "brown_carpet": 64, + "green_carpet": 64, + "red_carpet": 64, + "black_carpet": 64, + "terracotta": 64, + "coal_block": 64, + "packed_ice": 64, + "acacia_stairs": 64, + "dark_oak_stairs": 64, + "slime_block": 64, + "grass_path": 64, + "sunflower": 64, + "lilac": 64, + "rose_bush": 64, + "peony": 64, + "tall_grass": 64, + "large_fern": 64, + "white_stained_glass": 64, + "orange_stained_glass": 64, + "magenta_stained_glass": 64, + "light_blue_stained_glass": 64, + "yellow_stained_glass": 64, + "lime_stained_glass": 64, + "pink_stained_glass": 64, + "gray_stained_glass": 64, + "light_gray_stained_glass": 64, + "cyan_stained_glass": 64, + "purple_stained_glass": 64, + "blue_stained_glass": 64, + "brown_stained_glass": 64, + "green_stained_glass": 64, + "red_stained_glass": 64, + "black_stained_glass": 64, + "white_stained_glass_pane": 64, + "orange_stained_glass_pane": 64, + "magenta_stained_glass_pane": 64, + "light_blue_stained_glass_pane": 64, + "yellow_stained_glass_pane": 64, + "lime_stained_glass_pane": 64, + "pink_stained_glass_pane": 64, + "gray_stained_glass_pane": 64, + "light_gray_stained_glass_pane": 64, + "cyan_stained_glass_pane": 64, + "purple_stained_glass_pane": 64, + "blue_stained_glass_pane": 64, + "brown_stained_glass_pane": 64, + "green_stained_glass_pane": 64, + "red_stained_glass_pane": 64, + "black_stained_glass_pane": 64, + "prismarine": 64, + "prismarine_bricks": 64, + "dark_prismarine": 64, + "prismarine_stairs": 64, + "prismarine_brick_stairs": 64, + "dark_prismarine_stairs": 64, + "sea_lantern": 64, + "red_sandstone": 64, + "chiseled_red_sandstone": 64, + "cut_red_sandstone": 64, + "red_sandstone_stairs": 64, + "repeating_command_block": 64, + "chain_command_block": 64, + "magma_block": 64, + "nether_wart_block": 64, + "red_nether_bricks": 64, + "bone_block": 64, + "structure_void": 64, + "observer": 64, + "shulker_box": 1, + "white_shulker_box": 1, + "orange_shulker_box": 1, + "magenta_shulker_box": 1, + "light_blue_shulker_box": 1, + "yellow_shulker_box": 1, + "lime_shulker_box": 1, + "pink_shulker_box": 1, + "gray_shulker_box": 1, + "light_gray_shulker_box": 1, + "cyan_shulker_box": 1, + "purple_shulker_box": 1, + "blue_shulker_box": 1, + "brown_shulker_box": 1, + "green_shulker_box": 1, + "red_shulker_box": 1, + "black_shulker_box": 1, + "white_glazed_terracotta": 64, + "orange_glazed_terracotta": 64, + "magenta_glazed_terracotta": 64, + "light_blue_glazed_terracotta": 64, + "yellow_glazed_terracotta": 64, + "lime_glazed_terracotta": 64, + "pink_glazed_terracotta": 64, + "gray_glazed_terracotta": 64, + "light_gray_glazed_terracotta": 64, + "cyan_glazed_terracotta": 64, + "purple_glazed_terracotta": 64, + "blue_glazed_terracotta": 64, + "brown_glazed_terracotta": 64, + "green_glazed_terracotta": 64, + "red_glazed_terracotta": 64, + "black_glazed_terracotta": 64, + "white_concrete": 64, + "orange_concrete": 64, + "magenta_concrete": 64, + "light_blue_concrete": 64, + "yellow_concrete": 64, + "lime_concrete": 64, + "pink_concrete": 64, + "gray_concrete": 64, + "light_gray_concrete": 64, + "cyan_concrete": 64, + "purple_concrete": 64, + "blue_concrete": 64, + "brown_concrete": 64, + "green_concrete": 64, + "red_concrete": 64, + "black_concrete": 64, + "white_concrete_powder": 64, + "orange_concrete_powder": 64, + "magenta_concrete_powder": 64, + "light_blue_concrete_powder": 64, + "yellow_concrete_powder": 64, + "lime_concrete_powder": 64, + "pink_concrete_powder": 64, + "gray_concrete_powder": 64, + "light_gray_concrete_powder": 64, + "cyan_concrete_powder": 64, + "purple_concrete_powder": 64, + "blue_concrete_powder": 64, + "brown_concrete_powder": 64, + "green_concrete_powder": 64, + "red_concrete_powder": 64, + "black_concrete_powder": 64, + "turtle_egg": 64, + "dead_tube_coral_block": 64, + "dead_brain_coral_block": 64, + "dead_bubble_coral_block": 64, + "dead_fire_coral_block": 64, + "dead_horn_coral_block": 64, + "tube_coral_block": 64, + "brain_coral_block": 64, + "bubble_coral_block": 64, + "fire_coral_block": 64, + "horn_coral_block": 64, + "tube_coral": 64, + "brain_coral": 64, + "bubble_coral": 64, + "fire_coral": 64, + "horn_coral": 64, + "dead_brain_coral": 64, + "dead_bubble_coral": 64, + "dead_fire_coral": 64, + "dead_horn_coral": 64, + "dead_tube_coral": 64, + "tube_coral_fan": 64, + "brain_coral_fan": 64, + "bubble_coral_fan": 64, + "fire_coral_fan": 64, + "horn_coral_fan": 64, + "dead_tube_coral_fan": 64, + "dead_brain_coral_fan": 64, + "dead_bubble_coral_fan": 64, + "dead_fire_coral_fan": 64, + "dead_horn_coral_fan": 64, + "blue_ice": 64, + "conduit": 64, + "iron_door": 64, + "oak_door": 64, + "spruce_door": 64, + "birch_door": 64, + "jungle_door": 64, + "acacia_door": 64, + "dark_oak_door": 64, + "repeater": 64, + "comparator": 64, + "structure_block": 64, + "turtle_helmet": 1, + "scute": 64, + "iron_shovel": 64, + "iron_pickaxe": 64, + "iron_axe": 64, + "flint_and_steel": 64, + "apple": 64, + "bow": 64, + "arrow": 64, + "coal": 64, + "charcoal": 64, + "diamond": 64, + "iron_ingot": 64, + "gold_ingot": 64, + "iron_sword": 64, + "wooden_sword": 64, + "wooden_shovel": 64, + "wooden_pickaxe": 64, + "wooden_axe": 64, + "stone_sword": 64, + "stone_shovel": 64, + "stone_pickaxe": 64, + "stone_axe": 64, + "diamond_sword": 64, + "diamond_shovel": 64, + "diamond_pickaxe": 64, + "diamond_axe": 64, + "stick": 64, + "bowl": 64, + "mushroom_stew": 1, + "golden_sword": 64, + "golden_shovel": 64, + "golden_pickaxe": 64, + "golden_axe": 64, + "string": 64, + "feather": 64, + "gunpowder": 64, + "wooden_hoe": 64, + "stone_hoe": 64, + "iron_hoe": 64, + "diamond_hoe": 64, + "golden_hoe": 64, + "wheat_seeds": 64, + "wheat": 64, + "bread": 64, + "leather_helmet": 1, + "leather_chestplate": 1, + "leather_leggings": 1, + "leather_boots": 1, + "chainmail_helmet": 1, + "chainmail_chestplate": 1, + "chainmail_leggings": 1, + "chainmail_boots": 1, + "iron_helmet": 1, + "iron_chestplate": 1, + "iron_leggings": 1, + "iron_boots": 1, + "diamond_helmet": 1, + "diamond_chestplate": 1, + "diamond_leggings": 1, + "diamond_boots": 1, + "golden_helmet": 1, + "golden_chestplate": 1, + "golden_leggings": 1, + "golden_boots": 1, + "flint": 64, + "porkchop": 64, + "cooked_porkchop": 64, + "painting": 64, + "golden_apple": 64, + "enchanted_golden_apple": 64, + "sign": 16, + "bucket": 16, + "water_bucket": 1, + "lava_bucket": 1, + "minecart": 1, + "saddle": 1, + "redstone": 64, + "snowball": 16, + "oak_boat": 1, + "leather": 64, + "milk_bucket": 1, + "pufferfish_bucket": 1, + "salmon_bucket": 1, + "cod_bucket": 1, + "tropical_fish_bucket": 1, + "brick": 64, + "clay_ball": 64, + "sugar_cane": 64, + "kelp": 64, + "dried_kelp_block": 64, + "paper": 64, + "book": 64, + "slime_ball": 64, + "chest_minecart": 1, + "furnace_minecart": 1, + "egg": 16, + "compass": 64, + "fishing_rod": 64, + "clock": 64, + "glowstone_dust": 64, + "cod": 64, + "salmon": 64, + "tropical_fish": 64, + "pufferfish": 64, + "cooked_cod": 64, + "cooked_salmon": 64, + "ink_sac": 64, + "rose_red": 64, + "cactus_green": 64, + "cocoa_beans": 64, + "lapis_lazuli": 64, + "purple_dye": 64, + "cyan_dye": 64, + "light_gray_dye": 64, + "gray_dye": 64, + "pink_dye": 64, + "lime_dye": 64, + "dandelion_yellow": 64, + "light_blue_dye": 64, + "magenta_dye": 64, + "orange_dye": 64, + "bone_meal": 64, + "bone": 64, + "sugar": 64, + "cake": 1, + "white_bed": 1, + "orange_bed": 1, + "magenta_bed": 1, + "light_blue_bed": 1, + "yellow_bed": 1, + "lime_bed": 1, + "pink_bed": 1, + "gray_bed": 1, + "light_gray_bed": 1, + "cyan_bed": 1, + "purple_bed": 1, + "blue_bed": 1, + "brown_bed": 1, + "green_bed": 1, + "red_bed": 1, + "black_bed": 1, + "cookie": 64, + "filled_map": 64, + "shears": 64, + "melon_slice": 64, + "dried_kelp": 64, + "pumpkin_seeds": 64, + "melon_seeds": 64, + "beef": 64, + "cooked_beef": 64, + "chicken": 64, + "cooked_chicken": 64, + "rotten_flesh": 64, + "ender_pearl": 16, + "blaze_rod": 64, + "ghast_tear": 64, + "gold_nugget": 64, + "nether_wart": 64, + "potion": 1, + "glass_bottle": 64, + "spider_eye": 64, + "fermented_spider_eye": 64, + "blaze_powder": 64, + "magma_cream": 64, + "brewing_stand": 64, + "cauldron": 64, + "ender_eye": 64, + "glistering_melon_slice": 64, + "bat_spawn_egg": 64, + "blaze_spawn_egg": 64, + "cave_spider_spawn_egg": 64, + "chicken_spawn_egg": 64, + "cod_spawn_egg": 64, + "cow_spawn_egg": 64, + "creeper_spawn_egg": 64, + "dolphin_spawn_egg": 64, + "donkey_spawn_egg": 64, + "drowned_spawn_egg": 64, + "elder_guardian_spawn_egg": 64, + "enderman_spawn_egg": 64, + "endermite_spawn_egg": 64, + "evoker_spawn_egg": 64, + "ghast_spawn_egg": 64, + "guardian_spawn_egg": 64, + "horse_spawn_egg": 64, + "husk_spawn_egg": 64, + "llama_spawn_egg": 64, + "magma_cube_spawn_egg": 64, + "mooshroom_spawn_egg": 64, + "mule_spawn_egg": 64, + "ocelot_spawn_egg": 64, + "parrot_spawn_egg": 64, + "phantom_spawn_egg": 64, + "pig_spawn_egg": 64, + "polar_bear_spawn_egg": 64, + "pufferfish_spawn_egg": 64, + "rabbit_spawn_egg": 64, + "salmon_spawn_egg": 64, + "sheep_spawn_egg": 64, + "shulker_spawn_egg": 64, + "silverfish_spawn_egg": 64, + "skeleton_spawn_egg": 64, + "skeleton_horse_spawn_egg": 64, + "slime_spawn_egg": 64, + "spider_spawn_egg": 64, + "squid_spawn_egg": 64, + "stray_spawn_egg": 64, + "tropical_fish_spawn_egg": 64, + "turtle_spawn_egg": 64, + "vex_spawn_egg": 64, + "villager_spawn_egg": 64, + "vindicator_spawn_egg": 64, + "witch_spawn_egg": 64, + "wither_skeleton_spawn_egg": 64, + "wolf_spawn_egg": 64, + "zombie_spawn_egg": 64, + "zombie_horse_spawn_egg": 64, + "zombie_pigman_spawn_egg": 64, + "zombie_villager_spawn_egg": 64, + "experience_bottle": 64, + "fire_charge": 64, + "writable_book": 1, + "written_book": 16, + "emerald": 64, + "item_frame": 64, + "flower_pot": 64, + "carrot": 64, + "potato": 64, + "baked_potato": 64, + "poisonous_potato": 64, + "map": 64, + "golden_carrot": 64, + "skeleton_skull": 64, + "wither_skeleton_skull": 64, + "player_head": 64, + "zombie_head": 64, + "creeper_head": 64, + "dragon_head": 64, + "carrot_on_a_stick": 64, + "nether_star": 64, + "pumpkin_pie": 64, + "firework_rocket": 64, + "firework_star": 64, + "enchanted_book": 1, + "nether_brick": 64, + "quartz": 64, + "tnt_minecart": 1, + "hopper_minecart": 1, + "prismarine_shard": 64, + "prismarine_crystals": 64, + "rabbit": 64, + "cooked_rabbit": 64, + "rabbit_stew": 1, + "rabbit_foot": 64, + "rabbit_hide": 64, + "armor_stand": 16, + "iron_horse_armor": 1, + "golden_horse_armor": 1, + "diamond_horse_armor": 1, + "lead": 64, + "name_tag": 64, + "command_block_minecart": 1, + "mutton": 64, + "cooked_mutton": 64, + "white_banner": 16, + "orange_banner": 16, + "magenta_banner": 16, + "light_blue_banner": 16, + "yellow_banner": 16, + "lime_banner": 16, + "pink_banner": 16, + "gray_banner": 16, + "light_gray_banner": 16, + "cyan_banner": 16, + "purple_banner": 16, + "blue_banner": 16, + "brown_banner": 16, + "green_banner": 16, + "red_banner": 16, + "black_banner": 16, + "end_crystal": 64, + "chorus_fruit": 64, + "popped_chorus_fruit": 64, + "beetroot": 64, + "beetroot_seeds": 64, + "beetroot_soup": 1, + "dragon_breath": 64, + "splash_potion": 1, + "spectral_arrow": 64, + "tipped_arrow": 64, + "lingering_potion": 1, + "shield": 64, + "elytra": 64, + "spruce_boat": 1, + "birch_boat": 1, + "jungle_boat": 1, + "acacia_boat": 1, + "dark_oak_boat": 1, + "totem_of_undying": 1, + "shulker_shell": 64, + "iron_nugget": 64, + "knowledge_book": 1, + "debug_stick": 1, + "music_disc_13": 1, + "music_disc_cat": 1, + "music_disc_blocks": 1, + "music_disc_chirp": 1, + "music_disc_far": 1, + "music_disc_mall": 1, + "music_disc_mellohi": 1, + "music_disc_stal": 1, + "music_disc_strad": 1, + "music_disc_ward": 1, + "music_disc_11": 1, + "music_disc_wait": 1, + "trident": 1, + "phantom_membrane": 64, + "nautilus_shell": 64, + "heart_of_the_sea": 64, + }, + ), + Property( + on: "item", + name: "vanilla_id", + reverse: true, + type: u32, + mapping: { + "air": 0, + "stone": 1, + "granite": 2, + "polished_granite": 3, + "diorite": 4, + "polished_diorite": 5, + "andesite": 6, + "polished_andesite": 7, + "grass_block": 8, + "dirt": 9, + "coarse_dirt": 10, + "podzol": 11, + "cobblestone": 12, + "oak_planks": 13, + "spruce_planks": 14, + "birch_planks": 15, + "jungle_planks": 16, + "acacia_planks": 17, + "dark_oak_planks": 18, + "oak_sapling": 19, + "spruce_sapling": 20, + "birch_sapling": 21, + "jungle_sapling": 22, + "acacia_sapling": 23, + "dark_oak_sapling": 24, + "bedrock": 25, + "sand": 26, + "red_sand": 27, + "gravel": 28, + "gold_ore": 29, + "iron_ore": 30, + "coal_ore": 31, + "oak_log": 32, + "spruce_log": 33, + "birch_log": 34, + "jungle_log": 35, + "acacia_log": 36, + "dark_oak_log": 37, + "stripped_oak_log": 38, + "stripped_spruce_log": 39, + "stripped_birch_log": 40, + "stripped_jungle_log": 41, + "stripped_acacia_log": 42, + "stripped_dark_oak_log": 43, + "stripped_oak_wood": 44, + "stripped_spruce_wood": 45, + "stripped_birch_wood": 46, + "stripped_jungle_wood": 47, + "stripped_acacia_wood": 48, + "stripped_dark_oak_wood": 49, + "oak_wood": 50, + "spruce_wood": 51, + "birch_wood": 52, + "jungle_wood": 53, + "acacia_wood": 54, + "dark_oak_wood": 55, + "oak_leaves": 56, + "spruce_leaves": 57, + "birch_leaves": 58, + "jungle_leaves": 59, + "acacia_leaves": 60, + "dark_oak_leaves": 61, + "sponge": 62, + "wet_sponge": 63, + "glass": 64, + "lapis_ore": 65, + "lapis_block": 66, + "dispenser": 67, + "sandstone": 68, + "chiseled_sandstone": 69, + "cut_sandstone": 70, + "note_block": 71, + "powered_rail": 72, + "detector_rail": 73, + "sticky_piston": 74, + "cobweb": 75, + "grass": 76, + "fern": 77, + "dead_bush": 78, + "seagrass": 79, + "sea_pickle": 80, + "piston": 81, + "white_wool": 82, + "orange_wool": 83, + "magenta_wool": 84, + "light_blue_wool": 85, + "yellow_wool": 86, + "lime_wool": 87, + "pink_wool": 88, + "gray_wool": 89, + "light_gray_wool": 90, + "cyan_wool": 91, + "purple_wool": 92, + "blue_wool": 93, + "brown_wool": 94, + "green_wool": 95, + "red_wool": 96, + "black_wool": 97, + "dandelion": 98, + "poppy": 99, + "blue_orchid": 100, + "allium": 101, + "azure_bluet": 102, + "red_tulip": 103, + "orange_tulip": 104, + "white_tulip": 105, + "pink_tulip": 106, + "oxeye_daisy": 107, + "brown_mushroom": 108, + "red_mushroom": 109, + "gold_block": 110, + "iron_block": 111, + "oak_slab": 112, + "spruce_slab": 113, + "birch_slab": 114, + "jungle_slab": 115, + "acacia_slab": 116, + "dark_oak_slab": 117, + "stone_slab": 118, + "sandstone_slab": 119, + "petrified_oak_slab": 120, + "cobblestone_slab": 121, + "brick_slab": 122, + "stone_brick_slab": 123, + "nether_brick_slab": 124, + "quartz_slab": 125, + "red_sandstone_slab": 126, + "purpur_slab": 127, + "prismarine_slab": 128, + "prismarine_brick_slab": 129, + "dark_prismarine_slab": 130, + "smooth_quartz": 131, + "smooth_red_sandstone": 132, + "smooth_sandstone": 133, + "smooth_stone": 134, + "bricks": 135, + "tnt": 136, + "bookshelf": 137, + "mossy_cobblestone": 138, + "obsidian": 139, + "torch": 140, + "end_rod": 141, + "chorus_plant": 142, + "chorus_flower": 143, + "purpur_block": 144, + "purpur_pillar": 145, + "purpur_stairs": 146, + "spawner": 147, + "oak_stairs": 148, + "chest": 149, + "diamond_ore": 150, + "diamond_block": 151, + "crafting_table": 152, + "farmland": 153, + "furnace": 154, + "ladder": 155, + "rail": 156, + "cobblestone_stairs": 157, + "lever": 158, + "stone_pressure_plate": 159, + "oak_pressure_plate": 160, + "spruce_pressure_plate": 161, + "birch_pressure_plate": 162, + "jungle_pressure_plate": 163, + "acacia_pressure_plate": 164, + "dark_oak_pressure_plate": 165, + "redstone_ore": 166, + "redstone_torch": 167, + "stone_button": 168, + "snow": 169, + "ice": 170, + "snow_block": 171, + "cactus": 172, + "clay": 173, + "jukebox": 174, + "oak_fence": 175, + "spruce_fence": 176, + "birch_fence": 177, + "jungle_fence": 178, + "acacia_fence": 179, + "dark_oak_fence": 180, + "pumpkin": 181, + "carved_pumpkin": 182, + "netherrack": 183, + "soul_sand": 184, + "glowstone": 185, + "jack_o_lantern": 186, + "oak_trapdoor": 187, + "spruce_trapdoor": 188, + "birch_trapdoor": 189, + "jungle_trapdoor": 190, + "acacia_trapdoor": 191, + "dark_oak_trapdoor": 192, + "infested_stone": 193, + "infested_cobblestone": 194, + "infested_stone_bricks": 195, + "infested_mossy_stone_bricks": 196, + "infested_cracked_stone_bricks": 197, + "infested_chiseled_stone_bricks": 198, + "stone_bricks": 199, + "mossy_stone_bricks": 200, + "cracked_stone_bricks": 201, + "chiseled_stone_bricks": 202, + "brown_mushroom_block": 203, + "red_mushroom_block": 204, + "mushroom_stem": 205, + "iron_bars": 206, + "glass_pane": 207, + "melon": 208, + "vine": 209, + "oak_fence_gate": 210, + "spruce_fence_gate": 211, + "birch_fence_gate": 212, + "jungle_fence_gate": 213, + "acacia_fence_gate": 214, + "dark_oak_fence_gate": 215, + "brick_stairs": 216, + "stone_brick_stairs": 217, + "mycelium": 218, + "lily_pad": 219, + "nether_bricks": 220, + "nether_brick_fence": 221, + "nether_brick_stairs": 222, + "enchanting_table": 223, + "end_portal_frame": 224, + "end_stone": 225, + "end_stone_bricks": 226, + "dragon_egg": 227, + "redstone_lamp": 228, + "sandstone_stairs": 229, + "emerald_ore": 230, + "ender_chest": 231, + "tripwire_hook": 232, + "emerald_block": 233, + "spruce_stairs": 234, + "birch_stairs": 235, + "jungle_stairs": 236, + "command_block": 237, + "beacon": 238, + "cobblestone_wall": 239, + "mossy_cobblestone_wall": 240, + "oak_button": 241, + "spruce_button": 242, + "birch_button": 243, + "jungle_button": 244, + "acacia_button": 245, + "dark_oak_button": 246, + "anvil": 247, + "chipped_anvil": 248, + "damaged_anvil": 249, + "trapped_chest": 250, + "light_weighted_pressure_plate": 251, + "heavy_weighted_pressure_plate": 252, + "daylight_detector": 253, + "redstone_block": 254, + "nether_quartz_ore": 255, + "hopper": 256, + "chiseled_quartz_block": 257, + "quartz_block": 258, + "quartz_pillar": 259, + "quartz_stairs": 260, + "activator_rail": 261, + "dropper": 262, + "white_terracotta": 263, + "orange_terracotta": 264, + "magenta_terracotta": 265, + "light_blue_terracotta": 266, + "yellow_terracotta": 267, + "lime_terracotta": 268, + "pink_terracotta": 269, + "gray_terracotta": 270, + "light_gray_terracotta": 271, + "cyan_terracotta": 272, + "purple_terracotta": 273, + "blue_terracotta": 274, + "brown_terracotta": 275, + "green_terracotta": 276, + "red_terracotta": 277, + "black_terracotta": 278, + "barrier": 279, + "iron_trapdoor": 280, + "hay_block": 281, + "white_carpet": 282, + "orange_carpet": 283, + "magenta_carpet": 284, + "light_blue_carpet": 285, + "yellow_carpet": 286, + "lime_carpet": 287, + "pink_carpet": 288, + "gray_carpet": 289, + "light_gray_carpet": 290, + "cyan_carpet": 291, + "purple_carpet": 292, + "blue_carpet": 293, + "brown_carpet": 294, + "green_carpet": 295, + "red_carpet": 296, + "black_carpet": 297, + "terracotta": 298, + "coal_block": 299, + "packed_ice": 300, + "acacia_stairs": 301, + "dark_oak_stairs": 302, + "slime_block": 303, + "grass_path": 304, + "sunflower": 305, + "lilac": 306, + "rose_bush": 307, + "peony": 308, + "tall_grass": 309, + "large_fern": 310, + "white_stained_glass": 311, + "orange_stained_glass": 312, + "magenta_stained_glass": 313, + "light_blue_stained_glass": 314, + "yellow_stained_glass": 315, + "lime_stained_glass": 316, + "pink_stained_glass": 317, + "gray_stained_glass": 318, + "light_gray_stained_glass": 319, + "cyan_stained_glass": 320, + "purple_stained_glass": 321, + "blue_stained_glass": 322, + "brown_stained_glass": 323, + "green_stained_glass": 324, + "red_stained_glass": 325, + "black_stained_glass": 326, + "white_stained_glass_pane": 327, + "orange_stained_glass_pane": 328, + "magenta_stained_glass_pane": 329, + "light_blue_stained_glass_pane": 330, + "yellow_stained_glass_pane": 331, + "lime_stained_glass_pane": 332, + "pink_stained_glass_pane": 333, + "gray_stained_glass_pane": 334, + "light_gray_stained_glass_pane": 335, + "cyan_stained_glass_pane": 336, + "purple_stained_glass_pane": 337, + "blue_stained_glass_pane": 338, + "brown_stained_glass_pane": 339, + "green_stained_glass_pane": 340, + "red_stained_glass_pane": 341, + "black_stained_glass_pane": 342, + "prismarine": 343, + "prismarine_bricks": 344, + "dark_prismarine": 345, + "prismarine_stairs": 346, + "prismarine_brick_stairs": 347, + "dark_prismarine_stairs": 348, + "sea_lantern": 349, + "red_sandstone": 350, + "chiseled_red_sandstone": 351, + "cut_red_sandstone": 352, + "red_sandstone_stairs": 353, + "repeating_command_block": 354, + "chain_command_block": 355, + "magma_block": 356, + "nether_wart_block": 357, + "red_nether_bricks": 358, + "bone_block": 359, + "structure_void": 360, + "observer": 361, + "shulker_box": 362, + "white_shulker_box": 363, + "orange_shulker_box": 364, + "magenta_shulker_box": 365, + "light_blue_shulker_box": 366, + "yellow_shulker_box": 367, + "lime_shulker_box": 368, + "pink_shulker_box": 369, + "gray_shulker_box": 370, + "light_gray_shulker_box": 371, + "cyan_shulker_box": 372, + "purple_shulker_box": 373, + "blue_shulker_box": 374, + "brown_shulker_box": 375, + "green_shulker_box": 376, + "red_shulker_box": 377, + "black_shulker_box": 378, + "white_glazed_terracotta": 379, + "orange_glazed_terracotta": 380, + "magenta_glazed_terracotta": 381, + "light_blue_glazed_terracotta": 382, + "yellow_glazed_terracotta": 383, + "lime_glazed_terracotta": 384, + "pink_glazed_terracotta": 385, + "gray_glazed_terracotta": 386, + "light_gray_glazed_terracotta": 387, + "cyan_glazed_terracotta": 388, + "purple_glazed_terracotta": 389, + "blue_glazed_terracotta": 390, + "brown_glazed_terracotta": 391, + "green_glazed_terracotta": 392, + "red_glazed_terracotta": 393, + "black_glazed_terracotta": 394, + "white_concrete": 395, + "orange_concrete": 396, + "magenta_concrete": 397, + "light_blue_concrete": 398, + "yellow_concrete": 399, + "lime_concrete": 400, + "pink_concrete": 401, + "gray_concrete": 402, + "light_gray_concrete": 403, + "cyan_concrete": 404, + "purple_concrete": 405, + "blue_concrete": 406, + "brown_concrete": 407, + "green_concrete": 408, + "red_concrete": 409, + "black_concrete": 410, + "white_concrete_powder": 411, + "orange_concrete_powder": 412, + "magenta_concrete_powder": 413, + "light_blue_concrete_powder": 414, + "yellow_concrete_powder": 415, + "lime_concrete_powder": 416, + "pink_concrete_powder": 417, + "gray_concrete_powder": 418, + "light_gray_concrete_powder": 419, + "cyan_concrete_powder": 420, + "purple_concrete_powder": 421, + "blue_concrete_powder": 422, + "brown_concrete_powder": 423, + "green_concrete_powder": 424, + "red_concrete_powder": 425, + "black_concrete_powder": 426, + "turtle_egg": 427, + "dead_tube_coral_block": 428, + "dead_brain_coral_block": 429, + "dead_bubble_coral_block": 430, + "dead_fire_coral_block": 431, + "dead_horn_coral_block": 432, + "tube_coral_block": 433, + "brain_coral_block": 434, + "bubble_coral_block": 435, + "fire_coral_block": 436, + "horn_coral_block": 437, + "tube_coral": 438, + "brain_coral": 439, + "bubble_coral": 440, + "fire_coral": 441, + "horn_coral": 442, + "dead_brain_coral": 443, + "dead_bubble_coral": 444, + "dead_fire_coral": 445, + "dead_horn_coral": 446, + "dead_tube_coral": 447, + "tube_coral_fan": 448, + "brain_coral_fan": 449, + "bubble_coral_fan": 450, + "fire_coral_fan": 451, + "horn_coral_fan": 452, + "dead_tube_coral_fan": 453, + "dead_brain_coral_fan": 454, + "dead_bubble_coral_fan": 455, + "dead_fire_coral_fan": 456, + "dead_horn_coral_fan": 457, + "blue_ice": 458, + "conduit": 459, + "iron_door": 460, + "oak_door": 461, + "spruce_door": 462, + "birch_door": 463, + "jungle_door": 464, + "acacia_door": 465, + "dark_oak_door": 466, + "repeater": 467, + "comparator": 468, + "structure_block": 469, + "turtle_helmet": 470, + "scute": 471, + "iron_shovel": 472, + "iron_pickaxe": 473, + "iron_axe": 474, + "flint_and_steel": 475, + "apple": 476, + "bow": 477, + "arrow": 478, + "coal": 479, + "charcoal": 480, + "diamond": 481, + "iron_ingot": 482, + "gold_ingot": 483, + "iron_sword": 484, + "wooden_sword": 485, + "wooden_shovel": 486, + "wooden_pickaxe": 487, + "wooden_axe": 488, + "stone_sword": 489, + "stone_shovel": 490, + "stone_pickaxe": 491, + "stone_axe": 492, + "diamond_sword": 493, + "diamond_shovel": 494, + "diamond_pickaxe": 495, + "diamond_axe": 496, + "stick": 497, + "bowl": 498, + "mushroom_stew": 499, + "golden_sword": 500, + "golden_shovel": 501, + "golden_pickaxe": 502, + "golden_axe": 503, + "string": 504, + "feather": 505, + "gunpowder": 506, + "wooden_hoe": 507, + "stone_hoe": 508, + "iron_hoe": 509, + "diamond_hoe": 510, + "golden_hoe": 511, + "wheat_seeds": 512, + "wheat": 513, + "bread": 514, + "leather_helmet": 515, + "leather_chestplate": 516, + "leather_leggings": 517, + "leather_boots": 518, + "chainmail_helmet": 519, + "chainmail_chestplate": 520, + "chainmail_leggings": 521, + "chainmail_boots": 522, + "iron_helmet": 523, + "iron_chestplate": 524, + "iron_leggings": 525, + "iron_boots": 526, + "diamond_helmet": 527, + "diamond_chestplate": 528, + "diamond_leggings": 529, + "diamond_boots": 530, + "golden_helmet": 531, + "golden_chestplate": 532, + "golden_leggings": 533, + "golden_boots": 534, + "flint": 535, + "porkchop": 536, + "cooked_porkchop": 537, + "painting": 538, + "golden_apple": 539, + "enchanted_golden_apple": 540, + "sign": 541, + "bucket": 542, + "water_bucket": 543, + "lava_bucket": 544, + "minecart": 545, + "saddle": 546, + "redstone": 547, + "snowball": 548, + "oak_boat": 549, + "leather": 550, + "milk_bucket": 551, + "pufferfish_bucket": 552, + "salmon_bucket": 553, + "cod_bucket": 554, + "tropical_fish_bucket": 555, + "brick": 556, + "clay_ball": 557, + "sugar_cane": 558, + "kelp": 559, + "dried_kelp_block": 560, + "paper": 561, + "book": 562, + "slime_ball": 563, + "chest_minecart": 564, + "furnace_minecart": 565, + "egg": 566, + "compass": 567, + "fishing_rod": 568, + "clock": 569, + "glowstone_dust": 570, + "cod": 571, + "salmon": 572, + "tropical_fish": 573, + "pufferfish": 574, + "cooked_cod": 575, + "cooked_salmon": 576, + "ink_sac": 577, + "rose_red": 578, + "cactus_green": 579, + "cocoa_beans": 580, + "lapis_lazuli": 581, + "purple_dye": 582, + "cyan_dye": 583, + "light_gray_dye": 584, + "gray_dye": 585, + "pink_dye": 586, + "lime_dye": 587, + "dandelion_yellow": 588, + "light_blue_dye": 589, + "magenta_dye": 590, + "orange_dye": 591, + "bone_meal": 592, + "bone": 593, + "sugar": 594, + "cake": 595, + "white_bed": 596, + "orange_bed": 597, + "magenta_bed": 598, + "light_blue_bed": 599, + "yellow_bed": 600, + "lime_bed": 601, + "pink_bed": 602, + "gray_bed": 603, + "light_gray_bed": 604, + "cyan_bed": 605, + "purple_bed": 606, + "blue_bed": 607, + "brown_bed": 608, + "green_bed": 609, + "red_bed": 610, + "black_bed": 611, + "cookie": 612, + "filled_map": 613, + "shears": 614, + "melon_slice": 615, + "dried_kelp": 616, + "pumpkin_seeds": 617, + "melon_seeds": 618, + "beef": 619, + "cooked_beef": 620, + "chicken": 621, + "cooked_chicken": 622, + "rotten_flesh": 623, + "ender_pearl": 624, + "blaze_rod": 625, + "ghast_tear": 626, + "gold_nugget": 627, + "nether_wart": 628, + "potion": 629, + "glass_bottle": 630, + "spider_eye": 631, + "fermented_spider_eye": 632, + "blaze_powder": 633, + "magma_cream": 634, + "brewing_stand": 635, + "cauldron": 636, + "ender_eye": 637, + "glistering_melon_slice": 638, + "bat_spawn_egg": 639, + "blaze_spawn_egg": 640, + "cave_spider_spawn_egg": 641, + "chicken_spawn_egg": 642, + "cod_spawn_egg": 643, + "cow_spawn_egg": 644, + "creeper_spawn_egg": 645, + "dolphin_spawn_egg": 646, + "donkey_spawn_egg": 647, + "drowned_spawn_egg": 648, + "elder_guardian_spawn_egg": 649, + "enderman_spawn_egg": 650, + "endermite_spawn_egg": 651, + "evoker_spawn_egg": 652, + "ghast_spawn_egg": 653, + "guardian_spawn_egg": 654, + "horse_spawn_egg": 655, + "husk_spawn_egg": 656, + "llama_spawn_egg": 657, + "magma_cube_spawn_egg": 658, + "mooshroom_spawn_egg": 659, + "mule_spawn_egg": 660, + "ocelot_spawn_egg": 661, + "parrot_spawn_egg": 662, + "phantom_spawn_egg": 663, + "pig_spawn_egg": 664, + "polar_bear_spawn_egg": 665, + "pufferfish_spawn_egg": 666, + "rabbit_spawn_egg": 667, + "salmon_spawn_egg": 668, + "sheep_spawn_egg": 669, + "shulker_spawn_egg": 670, + "silverfish_spawn_egg": 671, + "skeleton_spawn_egg": 672, + "skeleton_horse_spawn_egg": 673, + "slime_spawn_egg": 674, + "spider_spawn_egg": 675, + "squid_spawn_egg": 676, + "stray_spawn_egg": 677, + "tropical_fish_spawn_egg": 678, + "turtle_spawn_egg": 679, + "vex_spawn_egg": 680, + "villager_spawn_egg": 681, + "vindicator_spawn_egg": 682, + "witch_spawn_egg": 683, + "wither_skeleton_spawn_egg": 684, + "wolf_spawn_egg": 685, + "zombie_spawn_egg": 686, + "zombie_horse_spawn_egg": 687, + "zombie_pigman_spawn_egg": 688, + "zombie_villager_spawn_egg": 689, + "experience_bottle": 690, + "fire_charge": 691, + "writable_book": 692, + "written_book": 693, + "emerald": 694, + "item_frame": 695, + "flower_pot": 696, + "carrot": 697, + "potato": 698, + "baked_potato": 699, + "poisonous_potato": 700, + "map": 701, + "golden_carrot": 702, + "skeleton_skull": 703, + "wither_skeleton_skull": 704, + "player_head": 705, + "zombie_head": 706, + "creeper_head": 707, + "dragon_head": 708, + "carrot_on_a_stick": 709, + "nether_star": 710, + "pumpkin_pie": 711, + "firework_rocket": 712, + "firework_star": 713, + "enchanted_book": 714, + "nether_brick": 715, + "quartz": 716, + "tnt_minecart": 717, + "hopper_minecart": 718, + "prismarine_shard": 719, + "prismarine_crystals": 720, + "rabbit": 721, + "cooked_rabbit": 722, + "rabbit_stew": 723, + "rabbit_foot": 724, + "rabbit_hide": 725, + "armor_stand": 726, + "iron_horse_armor": 727, + "golden_horse_armor": 728, + "diamond_horse_armor": 729, + "lead": 730, + "name_tag": 731, + "command_block_minecart": 732, + "mutton": 733, + "cooked_mutton": 734, + "white_banner": 735, + "orange_banner": 736, + "magenta_banner": 737, + "light_blue_banner": 738, + "yellow_banner": 739, + "lime_banner": 740, + "pink_banner": 741, + "gray_banner": 742, + "light_gray_banner": 743, + "cyan_banner": 744, + "purple_banner": 745, + "blue_banner": 746, + "brown_banner": 747, + "green_banner": 748, + "red_banner": 749, + "black_banner": 750, + "end_crystal": 751, + "chorus_fruit": 752, + "popped_chorus_fruit": 753, + "beetroot": 754, + "beetroot_seeds": 755, + "beetroot_soup": 756, + "dragon_breath": 757, + "splash_potion": 758, + "spectral_arrow": 759, + "tipped_arrow": 760, + "lingering_potion": 761, + "shield": 762, + "elytra": 763, + "spruce_boat": 764, + "birch_boat": 765, + "jungle_boat": 766, + "acacia_boat": 767, + "dark_oak_boat": 768, + "totem_of_undying": 769, + "shulker_shell": 770, + "iron_nugget": 771, + "knowledge_book": 772, + "debug_stick": 773, + "music_disc_13": 774, + "music_disc_cat": 775, + "music_disc_blocks": 776, + "music_disc_chirp": 777, + "music_disc_far": 778, + "music_disc_mall": 779, + "music_disc_mellohi": 780, + "music_disc_stal": 781, + "music_disc_strad": 782, + "music_disc_ward": 783, + "music_disc_11": 784, + "music_disc_wait": 785, + "trident": 786, + "phantom_membrane": 787, + "nautilus_shell": 788, + "heart_of_the_sea": 789, + }, + ), + Property( + on: "item", + name: "identifier", + reverse: true, + type: string, + mapping: { + "air": "minecraft:air", + "stone": "minecraft:stone", + "granite": "minecraft:granite", + "polished_granite": "minecraft:polished_granite", + "diorite": "minecraft:diorite", + "polished_diorite": "minecraft:polished_diorite", + "andesite": "minecraft:andesite", + "polished_andesite": "minecraft:polished_andesite", + "grass_block": "minecraft:grass_block", + "dirt": "minecraft:dirt", + "coarse_dirt": "minecraft:coarse_dirt", + "podzol": "minecraft:podzol", + "cobblestone": "minecraft:cobblestone", + "oak_planks": "minecraft:oak_planks", + "spruce_planks": "minecraft:spruce_planks", + "birch_planks": "minecraft:birch_planks", + "jungle_planks": "minecraft:jungle_planks", + "acacia_planks": "minecraft:acacia_planks", + "dark_oak_planks": "minecraft:dark_oak_planks", + "oak_sapling": "minecraft:oak_sapling", + "spruce_sapling": "minecraft:spruce_sapling", + "birch_sapling": "minecraft:birch_sapling", + "jungle_sapling": "minecraft:jungle_sapling", + "acacia_sapling": "minecraft:acacia_sapling", + "dark_oak_sapling": "minecraft:dark_oak_sapling", + "bedrock": "minecraft:bedrock", + "sand": "minecraft:sand", + "red_sand": "minecraft:red_sand", + "gravel": "minecraft:gravel", + "gold_ore": "minecraft:gold_ore", + "iron_ore": "minecraft:iron_ore", + "coal_ore": "minecraft:coal_ore", + "oak_log": "minecraft:oak_log", + "spruce_log": "minecraft:spruce_log", + "birch_log": "minecraft:birch_log", + "jungle_log": "minecraft:jungle_log", + "acacia_log": "minecraft:acacia_log", + "dark_oak_log": "minecraft:dark_oak_log", + "stripped_oak_log": "minecraft:stripped_oak_log", + "stripped_spruce_log": "minecraft:stripped_spruce_log", + "stripped_birch_log": "minecraft:stripped_birch_log", + "stripped_jungle_log": "minecraft:stripped_jungle_log", + "stripped_acacia_log": "minecraft:stripped_acacia_log", + "stripped_dark_oak_log": "minecraft:stripped_dark_oak_log", + "stripped_oak_wood": "minecraft:stripped_oak_wood", + "stripped_spruce_wood": "minecraft:stripped_spruce_wood", + "stripped_birch_wood": "minecraft:stripped_birch_wood", + "stripped_jungle_wood": "minecraft:stripped_jungle_wood", + "stripped_acacia_wood": "minecraft:stripped_acacia_wood", + "stripped_dark_oak_wood": "minecraft:stripped_dark_oak_wood", + "oak_wood": "minecraft:oak_wood", + "spruce_wood": "minecraft:spruce_wood", + "birch_wood": "minecraft:birch_wood", + "jungle_wood": "minecraft:jungle_wood", + "acacia_wood": "minecraft:acacia_wood", + "dark_oak_wood": "minecraft:dark_oak_wood", + "oak_leaves": "minecraft:oak_leaves", + "spruce_leaves": "minecraft:spruce_leaves", + "birch_leaves": "minecraft:birch_leaves", + "jungle_leaves": "minecraft:jungle_leaves", + "acacia_leaves": "minecraft:acacia_leaves", + "dark_oak_leaves": "minecraft:dark_oak_leaves", + "sponge": "minecraft:sponge", + "wet_sponge": "minecraft:wet_sponge", + "glass": "minecraft:glass", + "lapis_ore": "minecraft:lapis_ore", + "lapis_block": "minecraft:lapis_block", + "dispenser": "minecraft:dispenser", + "sandstone": "minecraft:sandstone", + "chiseled_sandstone": "minecraft:chiseled_sandstone", + "cut_sandstone": "minecraft:cut_sandstone", + "note_block": "minecraft:note_block", + "powered_rail": "minecraft:powered_rail", + "detector_rail": "minecraft:detector_rail", + "sticky_piston": "minecraft:sticky_piston", + "cobweb": "minecraft:cobweb", + "grass": "minecraft:grass", + "fern": "minecraft:fern", + "dead_bush": "minecraft:dead_bush", + "seagrass": "minecraft:seagrass", + "sea_pickle": "minecraft:sea_pickle", + "piston": "minecraft:piston", + "white_wool": "minecraft:white_wool", + "orange_wool": "minecraft:orange_wool", + "magenta_wool": "minecraft:magenta_wool", + "light_blue_wool": "minecraft:light_blue_wool", + "yellow_wool": "minecraft:yellow_wool", + "lime_wool": "minecraft:lime_wool", + "pink_wool": "minecraft:pink_wool", + "gray_wool": "minecraft:gray_wool", + "light_gray_wool": "minecraft:light_gray_wool", + "cyan_wool": "minecraft:cyan_wool", + "purple_wool": "minecraft:purple_wool", + "blue_wool": "minecraft:blue_wool", + "brown_wool": "minecraft:brown_wool", + "green_wool": "minecraft:green_wool", + "red_wool": "minecraft:red_wool", + "black_wool": "minecraft:black_wool", + "dandelion": "minecraft:dandelion", + "poppy": "minecraft:poppy", + "blue_orchid": "minecraft:blue_orchid", + "allium": "minecraft:allium", + "azure_bluet": "minecraft:azure_bluet", + "red_tulip": "minecraft:red_tulip", + "orange_tulip": "minecraft:orange_tulip", + "white_tulip": "minecraft:white_tulip", + "pink_tulip": "minecraft:pink_tulip", + "oxeye_daisy": "minecraft:oxeye_daisy", + "brown_mushroom": "minecraft:brown_mushroom", + "red_mushroom": "minecraft:red_mushroom", + "gold_block": "minecraft:gold_block", + "iron_block": "minecraft:iron_block", + "oak_slab": "minecraft:oak_slab", + "spruce_slab": "minecraft:spruce_slab", + "birch_slab": "minecraft:birch_slab", + "jungle_slab": "minecraft:jungle_slab", + "acacia_slab": "minecraft:acacia_slab", + "dark_oak_slab": "minecraft:dark_oak_slab", + "stone_slab": "minecraft:stone_slab", + "sandstone_slab": "minecraft:sandstone_slab", + "petrified_oak_slab": "minecraft:petrified_oak_slab", + "cobblestone_slab": "minecraft:cobblestone_slab", + "brick_slab": "minecraft:brick_slab", + "stone_brick_slab": "minecraft:stone_brick_slab", + "nether_brick_slab": "minecraft:nether_brick_slab", + "quartz_slab": "minecraft:quartz_slab", + "red_sandstone_slab": "minecraft:red_sandstone_slab", + "purpur_slab": "minecraft:purpur_slab", + "prismarine_slab": "minecraft:prismarine_slab", + "prismarine_brick_slab": "minecraft:prismarine_brick_slab", + "dark_prismarine_slab": "minecraft:dark_prismarine_slab", + "smooth_quartz": "minecraft:smooth_quartz", + "smooth_red_sandstone": "minecraft:smooth_red_sandstone", + "smooth_sandstone": "minecraft:smooth_sandstone", + "smooth_stone": "minecraft:smooth_stone", + "bricks": "minecraft:bricks", + "tnt": "minecraft:tnt", + "bookshelf": "minecraft:bookshelf", + "mossy_cobblestone": "minecraft:mossy_cobblestone", + "obsidian": "minecraft:obsidian", + "torch": "minecraft:torch", + "end_rod": "minecraft:end_rod", + "chorus_plant": "minecraft:chorus_plant", + "chorus_flower": "minecraft:chorus_flower", + "purpur_block": "minecraft:purpur_block", + "purpur_pillar": "minecraft:purpur_pillar", + "purpur_stairs": "minecraft:purpur_stairs", + "spawner": "minecraft:spawner", + "oak_stairs": "minecraft:oak_stairs", + "chest": "minecraft:chest", + "diamond_ore": "minecraft:diamond_ore", + "diamond_block": "minecraft:diamond_block", + "crafting_table": "minecraft:crafting_table", + "farmland": "minecraft:farmland", + "furnace": "minecraft:furnace", + "ladder": "minecraft:ladder", + "rail": "minecraft:rail", + "cobblestone_stairs": "minecraft:cobblestone_stairs", + "lever": "minecraft:lever", + "stone_pressure_plate": "minecraft:stone_pressure_plate", + "oak_pressure_plate": "minecraft:oak_pressure_plate", + "spruce_pressure_plate": "minecraft:spruce_pressure_plate", + "birch_pressure_plate": "minecraft:birch_pressure_plate", + "jungle_pressure_plate": "minecraft:jungle_pressure_plate", + "acacia_pressure_plate": "minecraft:acacia_pressure_plate", + "dark_oak_pressure_plate": "minecraft:dark_oak_pressure_plate", + "redstone_ore": "minecraft:redstone_ore", + "redstone_torch": "minecraft:redstone_torch", + "stone_button": "minecraft:stone_button", + "snow": "minecraft:snow", + "ice": "minecraft:ice", + "snow_block": "minecraft:snow_block", + "cactus": "minecraft:cactus", + "clay": "minecraft:clay", + "jukebox": "minecraft:jukebox", + "oak_fence": "minecraft:oak_fence", + "spruce_fence": "minecraft:spruce_fence", + "birch_fence": "minecraft:birch_fence", + "jungle_fence": "minecraft:jungle_fence", + "acacia_fence": "minecraft:acacia_fence", + "dark_oak_fence": "minecraft:dark_oak_fence", + "pumpkin": "minecraft:pumpkin", + "carved_pumpkin": "minecraft:carved_pumpkin", + "netherrack": "minecraft:netherrack", + "soul_sand": "minecraft:soul_sand", + "glowstone": "minecraft:glowstone", + "jack_o_lantern": "minecraft:jack_o_lantern", + "oak_trapdoor": "minecraft:oak_trapdoor", + "spruce_trapdoor": "minecraft:spruce_trapdoor", + "birch_trapdoor": "minecraft:birch_trapdoor", + "jungle_trapdoor": "minecraft:jungle_trapdoor", + "acacia_trapdoor": "minecraft:acacia_trapdoor", + "dark_oak_trapdoor": "minecraft:dark_oak_trapdoor", + "infested_stone": "minecraft:infested_stone", + "infested_cobblestone": "minecraft:infested_cobblestone", + "infested_stone_bricks": "minecraft:infested_stone_bricks", + "infested_mossy_stone_bricks": "minecraft:infested_mossy_stone_bricks", + "infested_cracked_stone_bricks": "minecraft:infested_cracked_stone_bricks", + "infested_chiseled_stone_bricks": "minecraft:infested_chiseled_stone_bricks", + "stone_bricks": "minecraft:stone_bricks", + "mossy_stone_bricks": "minecraft:mossy_stone_bricks", + "cracked_stone_bricks": "minecraft:cracked_stone_bricks", + "chiseled_stone_bricks": "minecraft:chiseled_stone_bricks", + "brown_mushroom_block": "minecraft:brown_mushroom_block", + "red_mushroom_block": "minecraft:red_mushroom_block", + "mushroom_stem": "minecraft:mushroom_stem", + "iron_bars": "minecraft:iron_bars", + "glass_pane": "minecraft:glass_pane", + "melon": "minecraft:melon", + "vine": "minecraft:vine", + "oak_fence_gate": "minecraft:oak_fence_gate", + "spruce_fence_gate": "minecraft:spruce_fence_gate", + "birch_fence_gate": "minecraft:birch_fence_gate", + "jungle_fence_gate": "minecraft:jungle_fence_gate", + "acacia_fence_gate": "minecraft:acacia_fence_gate", + "dark_oak_fence_gate": "minecraft:dark_oak_fence_gate", + "brick_stairs": "minecraft:brick_stairs", + "stone_brick_stairs": "minecraft:stone_brick_stairs", + "mycelium": "minecraft:mycelium", + "lily_pad": "minecraft:lily_pad", + "nether_bricks": "minecraft:nether_bricks", + "nether_brick_fence": "minecraft:nether_brick_fence", + "nether_brick_stairs": "minecraft:nether_brick_stairs", + "enchanting_table": "minecraft:enchanting_table", + "end_portal_frame": "minecraft:end_portal_frame", + "end_stone": "minecraft:end_stone", + "end_stone_bricks": "minecraft:end_stone_bricks", + "dragon_egg": "minecraft:dragon_egg", + "redstone_lamp": "minecraft:redstone_lamp", + "sandstone_stairs": "minecraft:sandstone_stairs", + "emerald_ore": "minecraft:emerald_ore", + "ender_chest": "minecraft:ender_chest", + "tripwire_hook": "minecraft:tripwire_hook", + "emerald_block": "minecraft:emerald_block", + "spruce_stairs": "minecraft:spruce_stairs", + "birch_stairs": "minecraft:birch_stairs", + "jungle_stairs": "minecraft:jungle_stairs", + "command_block": "minecraft:command_block", + "beacon": "minecraft:beacon", + "cobblestone_wall": "minecraft:cobblestone_wall", + "mossy_cobblestone_wall": "minecraft:mossy_cobblestone_wall", + "oak_button": "minecraft:oak_button", + "spruce_button": "minecraft:spruce_button", + "birch_button": "minecraft:birch_button", + "jungle_button": "minecraft:jungle_button", + "acacia_button": "minecraft:acacia_button", + "dark_oak_button": "minecraft:dark_oak_button", + "anvil": "minecraft:anvil", + "chipped_anvil": "minecraft:chipped_anvil", + "damaged_anvil": "minecraft:damaged_anvil", + "trapped_chest": "minecraft:trapped_chest", + "light_weighted_pressure_plate": "minecraft:light_weighted_pressure_plate", + "heavy_weighted_pressure_plate": "minecraft:heavy_weighted_pressure_plate", + "daylight_detector": "minecraft:daylight_detector", + "redstone_block": "minecraft:redstone_block", + "nether_quartz_ore": "minecraft:nether_quartz_ore", + "hopper": "minecraft:hopper", + "chiseled_quartz_block": "minecraft:chiseled_quartz_block", + "quartz_block": "minecraft:quartz_block", + "quartz_pillar": "minecraft:quartz_pillar", + "quartz_stairs": "minecraft:quartz_stairs", + "activator_rail": "minecraft:activator_rail", + "dropper": "minecraft:dropper", + "white_terracotta": "minecraft:white_terracotta", + "orange_terracotta": "minecraft:orange_terracotta", + "magenta_terracotta": "minecraft:magenta_terracotta", + "light_blue_terracotta": "minecraft:light_blue_terracotta", + "yellow_terracotta": "minecraft:yellow_terracotta", + "lime_terracotta": "minecraft:lime_terracotta", + "pink_terracotta": "minecraft:pink_terracotta", + "gray_terracotta": "minecraft:gray_terracotta", + "light_gray_terracotta": "minecraft:light_gray_terracotta", + "cyan_terracotta": "minecraft:cyan_terracotta", + "purple_terracotta": "minecraft:purple_terracotta", + "blue_terracotta": "minecraft:blue_terracotta", + "brown_terracotta": "minecraft:brown_terracotta", + "green_terracotta": "minecraft:green_terracotta", + "red_terracotta": "minecraft:red_terracotta", + "black_terracotta": "minecraft:black_terracotta", + "barrier": "minecraft:barrier", + "iron_trapdoor": "minecraft:iron_trapdoor", + "hay_block": "minecraft:hay_block", + "white_carpet": "minecraft:white_carpet", + "orange_carpet": "minecraft:orange_carpet", + "magenta_carpet": "minecraft:magenta_carpet", + "light_blue_carpet": "minecraft:light_blue_carpet", + "yellow_carpet": "minecraft:yellow_carpet", + "lime_carpet": "minecraft:lime_carpet", + "pink_carpet": "minecraft:pink_carpet", + "gray_carpet": "minecraft:gray_carpet", + "light_gray_carpet": "minecraft:light_gray_carpet", + "cyan_carpet": "minecraft:cyan_carpet", + "purple_carpet": "minecraft:purple_carpet", + "blue_carpet": "minecraft:blue_carpet", + "brown_carpet": "minecraft:brown_carpet", + "green_carpet": "minecraft:green_carpet", + "red_carpet": "minecraft:red_carpet", + "black_carpet": "minecraft:black_carpet", + "terracotta": "minecraft:terracotta", + "coal_block": "minecraft:coal_block", + "packed_ice": "minecraft:packed_ice", + "acacia_stairs": "minecraft:acacia_stairs", + "dark_oak_stairs": "minecraft:dark_oak_stairs", + "slime_block": "minecraft:slime_block", + "grass_path": "minecraft:grass_path", + "sunflower": "minecraft:sunflower", + "lilac": "minecraft:lilac", + "rose_bush": "minecraft:rose_bush", + "peony": "minecraft:peony", + "tall_grass": "minecraft:tall_grass", + "large_fern": "minecraft:large_fern", + "white_stained_glass": "minecraft:white_stained_glass", + "orange_stained_glass": "minecraft:orange_stained_glass", + "magenta_stained_glass": "minecraft:magenta_stained_glass", + "light_blue_stained_glass": "minecraft:light_blue_stained_glass", + "yellow_stained_glass": "minecraft:yellow_stained_glass", + "lime_stained_glass": "minecraft:lime_stained_glass", + "pink_stained_glass": "minecraft:pink_stained_glass", + "gray_stained_glass": "minecraft:gray_stained_glass", + "light_gray_stained_glass": "minecraft:light_gray_stained_glass", + "cyan_stained_glass": "minecraft:cyan_stained_glass", + "purple_stained_glass": "minecraft:purple_stained_glass", + "blue_stained_glass": "minecraft:blue_stained_glass", + "brown_stained_glass": "minecraft:brown_stained_glass", + "green_stained_glass": "minecraft:green_stained_glass", + "red_stained_glass": "minecraft:red_stained_glass", + "black_stained_glass": "minecraft:black_stained_glass", + "white_stained_glass_pane": "minecraft:white_stained_glass_pane", + "orange_stained_glass_pane": "minecraft:orange_stained_glass_pane", + "magenta_stained_glass_pane": "minecraft:magenta_stained_glass_pane", + "light_blue_stained_glass_pane": "minecraft:light_blue_stained_glass_pane", + "yellow_stained_glass_pane": "minecraft:yellow_stained_glass_pane", + "lime_stained_glass_pane": "minecraft:lime_stained_glass_pane", + "pink_stained_glass_pane": "minecraft:pink_stained_glass_pane", + "gray_stained_glass_pane": "minecraft:gray_stained_glass_pane", + "light_gray_stained_glass_pane": "minecraft:light_gray_stained_glass_pane", + "cyan_stained_glass_pane": "minecraft:cyan_stained_glass_pane", + "purple_stained_glass_pane": "minecraft:purple_stained_glass_pane", + "blue_stained_glass_pane": "minecraft:blue_stained_glass_pane", + "brown_stained_glass_pane": "minecraft:brown_stained_glass_pane", + "green_stained_glass_pane": "minecraft:green_stained_glass_pane", + "red_stained_glass_pane": "minecraft:red_stained_glass_pane", + "black_stained_glass_pane": "minecraft:black_stained_glass_pane", + "prismarine": "minecraft:prismarine", + "prismarine_bricks": "minecraft:prismarine_bricks", + "dark_prismarine": "minecraft:dark_prismarine", + "prismarine_stairs": "minecraft:prismarine_stairs", + "prismarine_brick_stairs": "minecraft:prismarine_brick_stairs", + "dark_prismarine_stairs": "minecraft:dark_prismarine_stairs", + "sea_lantern": "minecraft:sea_lantern", + "red_sandstone": "minecraft:red_sandstone", + "chiseled_red_sandstone": "minecraft:chiseled_red_sandstone", + "cut_red_sandstone": "minecraft:cut_red_sandstone", + "red_sandstone_stairs": "minecraft:red_sandstone_stairs", + "repeating_command_block": "minecraft:repeating_command_block", + "chain_command_block": "minecraft:chain_command_block", + "magma_block": "minecraft:magma_block", + "nether_wart_block": "minecraft:nether_wart_block", + "red_nether_bricks": "minecraft:red_nether_bricks", + "bone_block": "minecraft:bone_block", + "structure_void": "minecraft:structure_void", + "observer": "minecraft:observer", + "shulker_box": "minecraft:shulker_box", + "white_shulker_box": "minecraft:white_shulker_box", + "orange_shulker_box": "minecraft:orange_shulker_box", + "magenta_shulker_box": "minecraft:magenta_shulker_box", + "light_blue_shulker_box": "minecraft:light_blue_shulker_box", + "yellow_shulker_box": "minecraft:yellow_shulker_box", + "lime_shulker_box": "minecraft:lime_shulker_box", + "pink_shulker_box": "minecraft:pink_shulker_box", + "gray_shulker_box": "minecraft:gray_shulker_box", + "light_gray_shulker_box": "minecraft:light_gray_shulker_box", + "cyan_shulker_box": "minecraft:cyan_shulker_box", + "purple_shulker_box": "minecraft:purple_shulker_box", + "blue_shulker_box": "minecraft:blue_shulker_box", + "brown_shulker_box": "minecraft:brown_shulker_box", + "green_shulker_box": "minecraft:green_shulker_box", + "red_shulker_box": "minecraft:red_shulker_box", + "black_shulker_box": "minecraft:black_shulker_box", + "white_glazed_terracotta": "minecraft:white_glazed_terracotta", + "orange_glazed_terracotta": "minecraft:orange_glazed_terracotta", + "magenta_glazed_terracotta": "minecraft:magenta_glazed_terracotta", + "light_blue_glazed_terracotta": "minecraft:light_blue_glazed_terracotta", + "yellow_glazed_terracotta": "minecraft:yellow_glazed_terracotta", + "lime_glazed_terracotta": "minecraft:lime_glazed_terracotta", + "pink_glazed_terracotta": "minecraft:pink_glazed_terracotta", + "gray_glazed_terracotta": "minecraft:gray_glazed_terracotta", + "light_gray_glazed_terracotta": "minecraft:light_gray_glazed_terracotta", + "cyan_glazed_terracotta": "minecraft:cyan_glazed_terracotta", + "purple_glazed_terracotta": "minecraft:purple_glazed_terracotta", + "blue_glazed_terracotta": "minecraft:blue_glazed_terracotta", + "brown_glazed_terracotta": "minecraft:brown_glazed_terracotta", + "green_glazed_terracotta": "minecraft:green_glazed_terracotta", + "red_glazed_terracotta": "minecraft:red_glazed_terracotta", + "black_glazed_terracotta": "minecraft:black_glazed_terracotta", + "white_concrete": "minecraft:white_concrete", + "orange_concrete": "minecraft:orange_concrete", + "magenta_concrete": "minecraft:magenta_concrete", + "light_blue_concrete": "minecraft:light_blue_concrete", + "yellow_concrete": "minecraft:yellow_concrete", + "lime_concrete": "minecraft:lime_concrete", + "pink_concrete": "minecraft:pink_concrete", + "gray_concrete": "minecraft:gray_concrete", + "light_gray_concrete": "minecraft:light_gray_concrete", + "cyan_concrete": "minecraft:cyan_concrete", + "purple_concrete": "minecraft:purple_concrete", + "blue_concrete": "minecraft:blue_concrete", + "brown_concrete": "minecraft:brown_concrete", + "green_concrete": "minecraft:green_concrete", + "red_concrete": "minecraft:red_concrete", + "black_concrete": "minecraft:black_concrete", + "white_concrete_powder": "minecraft:white_concrete_powder", + "orange_concrete_powder": "minecraft:orange_concrete_powder", + "magenta_concrete_powder": "minecraft:magenta_concrete_powder", + "light_blue_concrete_powder": "minecraft:light_blue_concrete_powder", + "yellow_concrete_powder": "minecraft:yellow_concrete_powder", + "lime_concrete_powder": "minecraft:lime_concrete_powder", + "pink_concrete_powder": "minecraft:pink_concrete_powder", + "gray_concrete_powder": "minecraft:gray_concrete_powder", + "light_gray_concrete_powder": "minecraft:light_gray_concrete_powder", + "cyan_concrete_powder": "minecraft:cyan_concrete_powder", + "purple_concrete_powder": "minecraft:purple_concrete_powder", + "blue_concrete_powder": "minecraft:blue_concrete_powder", + "brown_concrete_powder": "minecraft:brown_concrete_powder", + "green_concrete_powder": "minecraft:green_concrete_powder", + "red_concrete_powder": "minecraft:red_concrete_powder", + "black_concrete_powder": "minecraft:black_concrete_powder", + "turtle_egg": "minecraft:turtle_egg", + "dead_tube_coral_block": "minecraft:dead_tube_coral_block", + "dead_brain_coral_block": "minecraft:dead_brain_coral_block", + "dead_bubble_coral_block": "minecraft:dead_bubble_coral_block", + "dead_fire_coral_block": "minecraft:dead_fire_coral_block", + "dead_horn_coral_block": "minecraft:dead_horn_coral_block", + "tube_coral_block": "minecraft:tube_coral_block", + "brain_coral_block": "minecraft:brain_coral_block", + "bubble_coral_block": "minecraft:bubble_coral_block", + "fire_coral_block": "minecraft:fire_coral_block", + "horn_coral_block": "minecraft:horn_coral_block", + "tube_coral": "minecraft:tube_coral", + "brain_coral": "minecraft:brain_coral", + "bubble_coral": "minecraft:bubble_coral", + "fire_coral": "minecraft:fire_coral", + "horn_coral": "minecraft:horn_coral", + "dead_brain_coral": "minecraft:dead_brain_coral", + "dead_bubble_coral": "minecraft:dead_bubble_coral", + "dead_fire_coral": "minecraft:dead_fire_coral", + "dead_horn_coral": "minecraft:dead_horn_coral", + "dead_tube_coral": "minecraft:dead_tube_coral", + "tube_coral_fan": "minecraft:tube_coral_fan", + "brain_coral_fan": "minecraft:brain_coral_fan", + "bubble_coral_fan": "minecraft:bubble_coral_fan", + "fire_coral_fan": "minecraft:fire_coral_fan", + "horn_coral_fan": "minecraft:horn_coral_fan", + "dead_tube_coral_fan": "minecraft:dead_tube_coral_fan", + "dead_brain_coral_fan": "minecraft:dead_brain_coral_fan", + "dead_bubble_coral_fan": "minecraft:dead_bubble_coral_fan", + "dead_fire_coral_fan": "minecraft:dead_fire_coral_fan", + "dead_horn_coral_fan": "minecraft:dead_horn_coral_fan", + "blue_ice": "minecraft:blue_ice", + "conduit": "minecraft:conduit", + "iron_door": "minecraft:iron_door", + "oak_door": "minecraft:oak_door", + "spruce_door": "minecraft:spruce_door", + "birch_door": "minecraft:birch_door", + "jungle_door": "minecraft:jungle_door", + "acacia_door": "minecraft:acacia_door", + "dark_oak_door": "minecraft:dark_oak_door", + "repeater": "minecraft:repeater", + "comparator": "minecraft:comparator", + "structure_block": "minecraft:structure_block", + "turtle_helmet": "minecraft:turtle_helmet", + "scute": "minecraft:scute", + "iron_shovel": "minecraft:iron_shovel", + "iron_pickaxe": "minecraft:iron_pickaxe", + "iron_axe": "minecraft:iron_axe", + "flint_and_steel": "minecraft:flint_and_steel", + "apple": "minecraft:apple", + "bow": "minecraft:bow", + "arrow": "minecraft:arrow", + "coal": "minecraft:coal", + "charcoal": "minecraft:charcoal", + "diamond": "minecraft:diamond", + "iron_ingot": "minecraft:iron_ingot", + "gold_ingot": "minecraft:gold_ingot", + "iron_sword": "minecraft:iron_sword", + "wooden_sword": "minecraft:wooden_sword", + "wooden_shovel": "minecraft:wooden_shovel", + "wooden_pickaxe": "minecraft:wooden_pickaxe", + "wooden_axe": "minecraft:wooden_axe", + "stone_sword": "minecraft:stone_sword", + "stone_shovel": "minecraft:stone_shovel", + "stone_pickaxe": "minecraft:stone_pickaxe", + "stone_axe": "minecraft:stone_axe", + "diamond_sword": "minecraft:diamond_sword", + "diamond_shovel": "minecraft:diamond_shovel", + "diamond_pickaxe": "minecraft:diamond_pickaxe", + "diamond_axe": "minecraft:diamond_axe", + "stick": "minecraft:stick", + "bowl": "minecraft:bowl", + "mushroom_stew": "minecraft:mushroom_stew", + "golden_sword": "minecraft:golden_sword", + "golden_shovel": "minecraft:golden_shovel", + "golden_pickaxe": "minecraft:golden_pickaxe", + "golden_axe": "minecraft:golden_axe", + "string": "minecraft:string", + "feather": "minecraft:feather", + "gunpowder": "minecraft:gunpowder", + "wooden_hoe": "minecraft:wooden_hoe", + "stone_hoe": "minecraft:stone_hoe", + "iron_hoe": "minecraft:iron_hoe", + "diamond_hoe": "minecraft:diamond_hoe", + "golden_hoe": "minecraft:golden_hoe", + "wheat_seeds": "minecraft:wheat_seeds", + "wheat": "minecraft:wheat", + "bread": "minecraft:bread", + "leather_helmet": "minecraft:leather_helmet", + "leather_chestplate": "minecraft:leather_chestplate", + "leather_leggings": "minecraft:leather_leggings", + "leather_boots": "minecraft:leather_boots", + "chainmail_helmet": "minecraft:chainmail_helmet", + "chainmail_chestplate": "minecraft:chainmail_chestplate", + "chainmail_leggings": "minecraft:chainmail_leggings", + "chainmail_boots": "minecraft:chainmail_boots", + "iron_helmet": "minecraft:iron_helmet", + "iron_chestplate": "minecraft:iron_chestplate", + "iron_leggings": "minecraft:iron_leggings", + "iron_boots": "minecraft:iron_boots", + "diamond_helmet": "minecraft:diamond_helmet", + "diamond_chestplate": "minecraft:diamond_chestplate", + "diamond_leggings": "minecraft:diamond_leggings", + "diamond_boots": "minecraft:diamond_boots", + "golden_helmet": "minecraft:golden_helmet", + "golden_chestplate": "minecraft:golden_chestplate", + "golden_leggings": "minecraft:golden_leggings", + "golden_boots": "minecraft:golden_boots", + "flint": "minecraft:flint", + "porkchop": "minecraft:porkchop", + "cooked_porkchop": "minecraft:cooked_porkchop", + "painting": "minecraft:painting", + "golden_apple": "minecraft:golden_apple", + "enchanted_golden_apple": "minecraft:enchanted_golden_apple", + "sign": "minecraft:sign", + "bucket": "minecraft:bucket", + "water_bucket": "minecraft:water_bucket", + "lava_bucket": "minecraft:lava_bucket", + "minecart": "minecraft:minecart", + "saddle": "minecraft:saddle", + "redstone": "minecraft:redstone", + "snowball": "minecraft:snowball", + "oak_boat": "minecraft:oak_boat", + "leather": "minecraft:leather", + "milk_bucket": "minecraft:milk_bucket", + "pufferfish_bucket": "minecraft:pufferfish_bucket", + "salmon_bucket": "minecraft:salmon_bucket", + "cod_bucket": "minecraft:cod_bucket", + "tropical_fish_bucket": "minecraft:tropical_fish_bucket", + "brick": "minecraft:brick", + "clay_ball": "minecraft:clay_ball", + "sugar_cane": "minecraft:sugar_cane", + "kelp": "minecraft:kelp", + "dried_kelp_block": "minecraft:dried_kelp_block", + "paper": "minecraft:paper", + "book": "minecraft:book", + "slime_ball": "minecraft:slime_ball", + "chest_minecart": "minecraft:chest_minecart", + "furnace_minecart": "minecraft:furnace_minecart", + "egg": "minecraft:egg", + "compass": "minecraft:compass", + "fishing_rod": "minecraft:fishing_rod", + "clock": "minecraft:clock", + "glowstone_dust": "minecraft:glowstone_dust", + "cod": "minecraft:cod", + "salmon": "minecraft:salmon", + "tropical_fish": "minecraft:tropical_fish", + "pufferfish": "minecraft:pufferfish", + "cooked_cod": "minecraft:cooked_cod", + "cooked_salmon": "minecraft:cooked_salmon", + "ink_sac": "minecraft:ink_sac", + "rose_red": "minecraft:rose_red", + "cactus_green": "minecraft:cactus_green", + "cocoa_beans": "minecraft:cocoa_beans", + "lapis_lazuli": "minecraft:lapis_lazuli", + "purple_dye": "minecraft:purple_dye", + "cyan_dye": "minecraft:cyan_dye", + "light_gray_dye": "minecraft:light_gray_dye", + "gray_dye": "minecraft:gray_dye", + "pink_dye": "minecraft:pink_dye", + "lime_dye": "minecraft:lime_dye", + "dandelion_yellow": "minecraft:dandelion_yellow", + "light_blue_dye": "minecraft:light_blue_dye", + "magenta_dye": "minecraft:magenta_dye", + "orange_dye": "minecraft:orange_dye", + "bone_meal": "minecraft:bone_meal", + "bone": "minecraft:bone", + "sugar": "minecraft:sugar", + "cake": "minecraft:cake", + "white_bed": "minecraft:white_bed", + "orange_bed": "minecraft:orange_bed", + "magenta_bed": "minecraft:magenta_bed", + "light_blue_bed": "minecraft:light_blue_bed", + "yellow_bed": "minecraft:yellow_bed", + "lime_bed": "minecraft:lime_bed", + "pink_bed": "minecraft:pink_bed", + "gray_bed": "minecraft:gray_bed", + "light_gray_bed": "minecraft:light_gray_bed", + "cyan_bed": "minecraft:cyan_bed", + "purple_bed": "minecraft:purple_bed", + "blue_bed": "minecraft:blue_bed", + "brown_bed": "minecraft:brown_bed", + "green_bed": "minecraft:green_bed", + "red_bed": "minecraft:red_bed", + "black_bed": "minecraft:black_bed", + "cookie": "minecraft:cookie", + "filled_map": "minecraft:filled_map", + "shears": "minecraft:shears", + "melon_slice": "minecraft:melon_slice", + "dried_kelp": "minecraft:dried_kelp", + "pumpkin_seeds": "minecraft:pumpkin_seeds", + "melon_seeds": "minecraft:melon_seeds", + "beef": "minecraft:beef", + "cooked_beef": "minecraft:cooked_beef", + "chicken": "minecraft:chicken", + "cooked_chicken": "minecraft:cooked_chicken", + "rotten_flesh": "minecraft:rotten_flesh", + "ender_pearl": "minecraft:ender_pearl", + "blaze_rod": "minecraft:blaze_rod", + "ghast_tear": "minecraft:ghast_tear", + "gold_nugget": "minecraft:gold_nugget", + "nether_wart": "minecraft:nether_wart", + "potion": "minecraft:potion", + "glass_bottle": "minecraft:glass_bottle", + "spider_eye": "minecraft:spider_eye", + "fermented_spider_eye": "minecraft:fermented_spider_eye", + "blaze_powder": "minecraft:blaze_powder", + "magma_cream": "minecraft:magma_cream", + "brewing_stand": "minecraft:brewing_stand", + "cauldron": "minecraft:cauldron", + "ender_eye": "minecraft:ender_eye", + "glistering_melon_slice": "minecraft:glistering_melon_slice", + "bat_spawn_egg": "minecraft:bat_spawn_egg", + "blaze_spawn_egg": "minecraft:blaze_spawn_egg", + "cave_spider_spawn_egg": "minecraft:cave_spider_spawn_egg", + "chicken_spawn_egg": "minecraft:chicken_spawn_egg", + "cod_spawn_egg": "minecraft:cod_spawn_egg", + "cow_spawn_egg": "minecraft:cow_spawn_egg", + "creeper_spawn_egg": "minecraft:creeper_spawn_egg", + "dolphin_spawn_egg": "minecraft:dolphin_spawn_egg", + "donkey_spawn_egg": "minecraft:donkey_spawn_egg", + "drowned_spawn_egg": "minecraft:drowned_spawn_egg", + "elder_guardian_spawn_egg": "minecraft:elder_guardian_spawn_egg", + "enderman_spawn_egg": "minecraft:enderman_spawn_egg", + "endermite_spawn_egg": "minecraft:endermite_spawn_egg", + "evoker_spawn_egg": "minecraft:evoker_spawn_egg", + "ghast_spawn_egg": "minecraft:ghast_spawn_egg", + "guardian_spawn_egg": "minecraft:guardian_spawn_egg", + "horse_spawn_egg": "minecraft:horse_spawn_egg", + "husk_spawn_egg": "minecraft:husk_spawn_egg", + "llama_spawn_egg": "minecraft:llama_spawn_egg", + "magma_cube_spawn_egg": "minecraft:magma_cube_spawn_egg", + "mooshroom_spawn_egg": "minecraft:mooshroom_spawn_egg", + "mule_spawn_egg": "minecraft:mule_spawn_egg", + "ocelot_spawn_egg": "minecraft:ocelot_spawn_egg", + "parrot_spawn_egg": "minecraft:parrot_spawn_egg", + "phantom_spawn_egg": "minecraft:phantom_spawn_egg", + "pig_spawn_egg": "minecraft:pig_spawn_egg", + "polar_bear_spawn_egg": "minecraft:polar_bear_spawn_egg", + "pufferfish_spawn_egg": "minecraft:pufferfish_spawn_egg", + "rabbit_spawn_egg": "minecraft:rabbit_spawn_egg", + "salmon_spawn_egg": "minecraft:salmon_spawn_egg", + "sheep_spawn_egg": "minecraft:sheep_spawn_egg", + "shulker_spawn_egg": "minecraft:shulker_spawn_egg", + "silverfish_spawn_egg": "minecraft:silverfish_spawn_egg", + "skeleton_spawn_egg": "minecraft:skeleton_spawn_egg", + "skeleton_horse_spawn_egg": "minecraft:skeleton_horse_spawn_egg", + "slime_spawn_egg": "minecraft:slime_spawn_egg", + "spider_spawn_egg": "minecraft:spider_spawn_egg", + "squid_spawn_egg": "minecraft:squid_spawn_egg", + "stray_spawn_egg": "minecraft:stray_spawn_egg", + "tropical_fish_spawn_egg": "minecraft:tropical_fish_spawn_egg", + "turtle_spawn_egg": "minecraft:turtle_spawn_egg", + "vex_spawn_egg": "minecraft:vex_spawn_egg", + "villager_spawn_egg": "minecraft:villager_spawn_egg", + "vindicator_spawn_egg": "minecraft:vindicator_spawn_egg", + "witch_spawn_egg": "minecraft:witch_spawn_egg", + "wither_skeleton_spawn_egg": "minecraft:wither_skeleton_spawn_egg", + "wolf_spawn_egg": "minecraft:wolf_spawn_egg", + "zombie_spawn_egg": "minecraft:zombie_spawn_egg", + "zombie_horse_spawn_egg": "minecraft:zombie_horse_spawn_egg", + "zombie_pigman_spawn_egg": "minecraft:zombie_pigman_spawn_egg", + "zombie_villager_spawn_egg": "minecraft:zombie_villager_spawn_egg", + "experience_bottle": "minecraft:experience_bottle", + "fire_charge": "minecraft:fire_charge", + "writable_book": "minecraft:writable_book", + "written_book": "minecraft:written_book", + "emerald": "minecraft:emerald", + "item_frame": "minecraft:item_frame", + "flower_pot": "minecraft:flower_pot", + "carrot": "minecraft:carrot", + "potato": "minecraft:potato", + "baked_potato": "minecraft:baked_potato", + "poisonous_potato": "minecraft:poisonous_potato", + "map": "minecraft:map", + "golden_carrot": "minecraft:golden_carrot", + "skeleton_skull": "minecraft:skeleton_skull", + "wither_skeleton_skull": "minecraft:wither_skeleton_skull", + "player_head": "minecraft:player_head", + "zombie_head": "minecraft:zombie_head", + "creeper_head": "minecraft:creeper_head", + "dragon_head": "minecraft:dragon_head", + "carrot_on_a_stick": "minecraft:carrot_on_a_stick", + "nether_star": "minecraft:nether_star", + "pumpkin_pie": "minecraft:pumpkin_pie", + "firework_rocket": "minecraft:firework_rocket", + "firework_star": "minecraft:firework_star", + "enchanted_book": "minecraft:enchanted_book", + "nether_brick": "minecraft:nether_brick", + "quartz": "minecraft:quartz", + "tnt_minecart": "minecraft:tnt_minecart", + "hopper_minecart": "minecraft:hopper_minecart", + "prismarine_shard": "minecraft:prismarine_shard", + "prismarine_crystals": "minecraft:prismarine_crystals", + "rabbit": "minecraft:rabbit", + "cooked_rabbit": "minecraft:cooked_rabbit", + "rabbit_stew": "minecraft:rabbit_stew", + "rabbit_foot": "minecraft:rabbit_foot", + "rabbit_hide": "minecraft:rabbit_hide", + "armor_stand": "minecraft:armor_stand", + "iron_horse_armor": "minecraft:iron_horse_armor", + "golden_horse_armor": "minecraft:golden_horse_armor", + "diamond_horse_armor": "minecraft:diamond_horse_armor", + "lead": "minecraft:lead", + "name_tag": "minecraft:name_tag", + "command_block_minecart": "minecraft:command_block_minecart", + "mutton": "minecraft:mutton", + "cooked_mutton": "minecraft:cooked_mutton", + "white_banner": "minecraft:white_banner", + "orange_banner": "minecraft:orange_banner", + "magenta_banner": "minecraft:magenta_banner", + "light_blue_banner": "minecraft:light_blue_banner", + "yellow_banner": "minecraft:yellow_banner", + "lime_banner": "minecraft:lime_banner", + "pink_banner": "minecraft:pink_banner", + "gray_banner": "minecraft:gray_banner", + "light_gray_banner": "minecraft:light_gray_banner", + "cyan_banner": "minecraft:cyan_banner", + "purple_banner": "minecraft:purple_banner", + "blue_banner": "minecraft:blue_banner", + "brown_banner": "minecraft:brown_banner", + "green_banner": "minecraft:green_banner", + "red_banner": "minecraft:red_banner", + "black_banner": "minecraft:black_banner", + "end_crystal": "minecraft:end_crystal", + "chorus_fruit": "minecraft:chorus_fruit", + "popped_chorus_fruit": "minecraft:popped_chorus_fruit", + "beetroot": "minecraft:beetroot", + "beetroot_seeds": "minecraft:beetroot_seeds", + "beetroot_soup": "minecraft:beetroot_soup", + "dragon_breath": "minecraft:dragon_breath", + "splash_potion": "minecraft:splash_potion", + "spectral_arrow": "minecraft:spectral_arrow", + "tipped_arrow": "minecraft:tipped_arrow", + "lingering_potion": "minecraft:lingering_potion", + "shield": "minecraft:shield", + "elytra": "minecraft:elytra", + "spruce_boat": "minecraft:spruce_boat", + "birch_boat": "minecraft:birch_boat", + "jungle_boat": "minecraft:jungle_boat", + "acacia_boat": "minecraft:acacia_boat", + "dark_oak_boat": "minecraft:dark_oak_boat", + "totem_of_undying": "minecraft:totem_of_undying", + "shulker_shell": "minecraft:shulker_shell", + "iron_nugget": "minecraft:iron_nugget", + "knowledge_book": "minecraft:knowledge_book", + "debug_stick": "minecraft:debug_stick", + "music_disc_13": "minecraft:music_disc_13", + "music_disc_cat": "minecraft:music_disc_cat", + "music_disc_blocks": "minecraft:music_disc_blocks", + "music_disc_chirp": "minecraft:music_disc_chirp", + "music_disc_far": "minecraft:music_disc_far", + "music_disc_mall": "minecraft:music_disc_mall", + "music_disc_mellohi": "minecraft:music_disc_mellohi", + "music_disc_stal": "minecraft:music_disc_stal", + "music_disc_strad": "minecraft:music_disc_strad", + "music_disc_ward": "minecraft:music_disc_ward", + "music_disc_11": "minecraft:music_disc_11", + "music_disc_wait": "minecraft:music_disc_wait", + "trident": "minecraft:trident", + "phantom_membrane": "minecraft:phantom_membrane", + "nautilus_shell": "minecraft:nautilus_shell", + "heart_of_the_sea": "minecraft:heart_of_the_sea", + }, + ),]) \ No newline at end of file diff --git a/feather/old/definitions/data/tool.ron b/feather/old/definitions/data/tool.ron new file mode 100644 index 000000000..18643179c --- /dev/null +++ b/feather/old/definitions/data/tool.ron @@ -0,0 +1,118 @@ +Multiple([ + Enum( + name: "tool", + variants: [ + "axe", + "pickaxe", + "shovel", + "hoe", + "sword", + "shears", + ] + ), + Enum( + name: "tool_material", + variants: [ + "wooden", + "stone", + "iron", + "diamond", + "golden", + ] + ), + Property( + on: "item", + name: "tool", + type: Custom("tool"), + mapping: { + "${tool_material}_${tool}": "${tool}", + "shears": "shears", + + } + ), + Property( + on: "item", + name: "tool_material", + type: Custom("tool_material"), + mapping: { + "${tool_material}_${tool}": "${tool_material}", + } + ), + Property( + on: "tool_material", + name: "dig_multiplier", + type: f64, + mapping: { + "wooden": 2, + "stone": 4, + "iron": 6, + "diamond": 8, + "golden": 12, + } + ), + Property( + on: "item", + name: "durability", + type: u32, + // https://minecraft.gamepedia.com/Item_durability + mapping: { + "leather_helmet": 55, + "leather_chestplate": 80, + "leather_leggings": 75, + "leather_boots": 65, + "golden_helmet": 77, + "golden_chestplate": 112, + "golden_leggings": 105, + "golden_boots": 91, + "chainmail_helmet": 165, + "chainmail_chestplate": 240, + "chainmail_leggings": 225, + "chainmail_boots": 195, + "iron_helmet": 165, + "iron_chestplate": 240, + "iron_leggings": 225, + "iron_boots": 195, + "diamond_helmet": 363, + "diamond_chestplate": 528, + "diamond_leggings": 495, + "diamond_boots": 429, + "golden_${tool}": 32, + "wooden_${tool}": 59, + "stone_${tool}": 131, + "iron_${tool}": 250, + "diamond_${tool}": 1561, + "fishing_rod": 64, + "flint_and_steel": 64, + "carrot_on_a_stick": 25, + "shears": 238, + "shield": 336, + "bow": 384, + "trident": 250, + "elytra": 432, + } + ), + // Defines the "best tool" to mine a block. + Property( + on: "block_kind", + name: "best_tool", + type: Custom("tool"), + mapping: { + // TODO + ["dirt", "grass_block", "sand", "red_sand"]: "shovel", + ["stone", "cobblestone", "sandstone"]: "pickaxe", + }, + ), + // Defines whether the best tool is required + // for the block to be harvested. If this is + // true, and a player is not holding + // the needed tool, then progress is slowed + // and the block yields no drops. + Property( + on: "block_kind", + name: "best_tool_required", + type: bool, + mapping: { + ["cobblestone", "stone", "sandstone"]: true, + }, + ), +]) diff --git a/feather/old/definitions/generator/Cargo.toml b/feather/old/definitions/generator/Cargo.toml new file mode 100644 index 000000000..cd570d3bf --- /dev/null +++ b/feather/old/definitions/generator/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "feather-definitions-generator" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-data = { path = "../../data" } + +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +ron = { git = "https://github.com/ron-rs/ron", rev = "0a7d83da66a4009f169967c5d2ac382a446bb76e" } +anyhow = "1.0" +walkdir = "2.3" +heck = "0.3" +itertools = "0.9" +regex = "1.3" +once_cell = "1.3" +indexmap = { version = "1.3", features = ["serde-1"] } + +syn = "1.0" +proc-macro2 = "1.0" +quote = "1.0" diff --git a/feather/old/definitions/generator/src/backend.rs b/feather/old/definitions/generator/src/backend.rs new file mode 100644 index 000000000..30c676c71 --- /dev/null +++ b/feather/old/definitions/generator/src/backend.rs @@ -0,0 +1,252 @@ +use crate::frontend::{Data, Enum, Property, Value}; +use crate::model::Type; +use anyhow::Context; +use heck::CamelCase; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use std::collections::BTreeSet; +use std::collections::HashMap; +use std::fs::File; +use std::io::Write; +use std::process::Command; +use syn::export::ToTokens; + +/// Given the `Data`, generates code. +pub fn generate(target_dir: &str, data: &Data) -> anyhow::Result<()> { + let _ = std::fs::remove_dir(target_dir); + std::fs::create_dir_all(target_dir) + .with_context(|| format!("failed to create directory `{}`", target_dir))?; + + let mut open_files = HashMap::new(); + + let mut module_names = BTreeSet::new(); + + for (file_name, fdata) in &data.files { + let path = format!("{}/{}.rs", target_dir, file_name); + module_names.insert(file_name); + + let file = match open_files.get_mut(&path) { + Some(file) => file, + None => { + let mut file = File::create(&path) + .with_context(|| format!("failed to create file `{}`", path))?; + file.write_all(b"// This file is @generated\n") + .with_context(|| format!("failed to write to file `{}`", path))?; + open_files.insert(path.clone(), file); + open_files.get_mut(&path).unwrap() + } + }; + + let tokens = fdata.enums.values().map(generate_enum).collect::<Vec<_>>(); + let tokens2 = fdata + .properties + .iter() + .map(|prop| generate_property(data, prop)) + .collect::<anyhow::Result<Vec<_>>>() + .with_context(|| format!("failed to generate properties in file `{}`", file_name))?; + + let tokens = quote! { #(#tokens)* #(#tokens2)* }; + + file.write_all(tokens.to_string().as_bytes()) + .with_context(|| format!("failed to write bytes to `{}`", path))?; + } + + // Write out mod.rs + let lib_path = format!("{}/mod.rs", target_dir); + let mut lib = File::create(&lib_path)?; + lib.write_all(b"// This file is @generated\n")?; + for module in module_names { + lib.write_all(format!("mod {}; pub use {}::*;", module, module).as_bytes())?; + } + open_files.insert(lib_path, lib); + + for (path, mut file) in open_files { + file.flush()?; + + if !Command::new("rustfmt").arg(&path).status()?.success() { + anyhow::bail!("failed to run rustfmt on file {}", path); + } + } + + Ok(()) +} + +fn generate_enum(e: &Enum) -> TokenStream { + let def = generate_enum_body(e); + + quote! { + #def + } +} + +fn generate_enum_body(e: &Enum) -> TokenStream { + let name = ident(&e.name_camel_case); + let variants: Vec<_> = e.variants_camel_case.iter().map(ident).collect(); + + quote! { + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ToPrimitive, FromPrimitive)] + pub enum #name { + #(#variants,)* + } + } +} + +impl<'a> ToTokens for Type<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let t = match self { + Type::Bool => quote! { bool }, + Type::Slice(inner) => quote! { &'static [#inner] }, + Type::U32 => quote! { u32 }, + Type::F64 => quote! { f64 }, + Type::String => quote! { &'static str }, + Type::Custom(name) => { + let name = ident(name.to_camel_case()); + quote! { crate::#name } + } + }; + tokens.extend(t); + } +} + +impl<'a> Type<'a> { + pub fn to_tokens_no_static_lifetime(&self) -> TokenStream { + match self { + Type::String => quote! { &str }, + typ => quote! { #typ }, + } + } +} + +impl Value { + fn tokens(&self, typ: &Type) -> TokenStream { + match self { + Value::Bool(x) => quote! { #x }, + Value::Slice(x) => { + let mut stream = TokenStream::new(); + let inner = if let Type::Slice(inner) = typ { + inner + } else { + panic!() + }; + + for value in x { + stream.extend(value.tokens(inner.as_ref())); + } + + stream + } + Value::U32(x) => quote! { #x }, + Value::F64(x) => quote! { #x }, + Value::String(x) => quote! { #x }, + Value::Custom(name) => { + let type_name = if let Type::Custom(x) = typ { + ident(x.to_camel_case()) + } else { + panic!() + }; + let name = ident(name.to_camel_case()); + quote! { crate::#type_name::#name } + } + } + } +} + +fn generate_property(data: &Data, property: &Property) -> anyhow::Result<TokenStream> { + let name = ident(property.on.to_camel_case()); + + let property_name = ident(&property.name); + let property_type = &property.typ; + + let e = data + .files + .values() + .filter_map(|models| models.enums.get(&property.on)) + .next() + .ok_or_else(|| anyhow::anyhow!("no enum matched the name `{}`", property.on))?; + + let mut exhaustive = property.mapping.len() == e.variants.len(); + + if let Type::Bool = property.typ { + exhaustive = true; + } + + let mut match_arms = vec![]; + for (variant, value) in &property.mapping { + let variant = ident(variant.to_camel_case()); + let value_tokens = value.tokens(&property.typ); + + let value = if exhaustive { + quote! { #value_tokens } + } else { + quote! { Some(#value_tokens) } + }; + + match_arms.push(quote! { + crate::#name::#variant => #value, + }); + } + + if !exhaustive { + match_arms.push(quote! { + _ => None, + }); + } + + if let Type::Bool = property.typ { + match_arms.push(quote! { _ => false, }); + } + + let ret = if exhaustive { + quote! { #property_type } + } else { + quote! { Option<#property_type> } + }; + + let to_prop = quote! { + pub fn #property_name(self) -> #ret { + match self { + #(#match_arms)* + } + } + }; + + let from_prop = if property.reverse { + // generate from_prop as well + let function_name = ident(format!("from_{}", property.name)); + let property_type = property_type.to_tokens_no_static_lifetime(); + + let mut match_arms = vec![]; + + for (variant, value) in &property.mapping { + let variant = ident(variant.to_camel_case()); + let value_tokens = value.tokens(&property.typ); + + match_arms.push(quote! { + #value_tokens => Some(crate::#name::#variant) + }); + } + match_arms.push(quote! { _ => None }); + + quote! { + pub fn #function_name(prop: #property_type) -> Option<#name> { + match prop { + #(#match_arms,)* + } + } + } + } else { + quote! {} + }; + + let tokens = quote! { + impl crate::#name { + #to_prop + #from_prop + } + }; + Ok(tokens) +} + +fn ident(s: impl AsRef<str>) -> Ident { + Ident::new(s.as_ref(), Span::call_site()) +} diff --git a/feather/old/definitions/generator/src/frontend.rs b/feather/old/definitions/generator/src/frontend.rs new file mode 100644 index 000000000..7e6c25e10 --- /dev/null +++ b/feather/old/definitions/generator/src/frontend.rs @@ -0,0 +1,481 @@ +//! Frontend parser for RON data files. +//! +//! Uses a query-like design inspired by rustc. + +use crate::model::{Model, ModelFile, Type}; +use anyhow::Context as _; +use heck::CamelCase; +use itertools::Either; +use once_cell::sync::Lazy; +use regex::Regex; +use std::borrow::Cow; +use std::collections::{BTreeMap, HashMap}; +use std::ops::Range; +use std::rc::Rc; + +pub struct DataFile { + pub contents: String, + pub name: String, +} + +/// Context of a running compilation. +struct Context<'a> { + /// All parsed models, taken from `files`, + /// plus the file names in which they're defined. + models: &'a [(&'a str, Model<'a>)], +} + +impl<'a> Context<'a> { + /// Performs a query. + pub fn query<Q>(&self, query: Q) -> anyhow::Result<Q::Output> + where + Q: Query<'a>, + { + // TODO: memoize query results + // if compilation becomes too slow. + query.execute(self) + } + + /// Finds an enum model matching the + /// given name. + pub fn find_enum_model(&self, name: &str) -> Option<(&'a str, &'a Model<'a>)> { + self.models + .iter() + .find(|(_, model)| match model { + Model::Enum { name: _name, .. } => *_name == name, + _ => false, + }) + .map(|(file_name, model)| (*file_name, model)) + } + + /// Finds a property model matching the given name. + pub fn find_property_model(&self, name: &str, on: &str) -> Option<&'a Model<'a>> { + self.models + .iter() + .find(|(_, model)| match model { + Model::Property { + name: _name, + on: _on, + .. + } => *_name == name && *_on == on, + _ => false, + }) + .map(|(_, model)| model) + } +} + +trait Query<'a> { + type Output; + + fn execute(&self, cx: &Context<'a>) -> anyhow::Result<Self::Output>; +} + +/// A query which compiles an enum. +#[derive(Debug)] +struct CompileEnum<'a> { + /// Name of enum to be compiled. + name: &'a str, +} + +impl<'a, 'b> Query<'a> for CompileEnum<'b> { + type Output = Enum<'a>; + + fn execute(&self, cx: &Context<'a>) -> anyhow::Result<Self::Output> { + let (_, model) = cx + .find_enum_model(self.name) + .ok_or_else(|| anyhow::anyhow!("no enum matched the name `{}`", self.name))?; + + let (name, variants) = match model { + Model::Enum { variants, name } => (*name, variants.as_slice()), + _ => unreachable!(), + }; + + let mut actual_variants = vec![]; + for variant in variants { + actual_variants.extend( + expand_expressions(cx, &[*variant], |_, _, _| true) + .with_context(|| format!("failed to expand expression `{}`", variant))? + .into_iter() + .map(|mut vec| vec.remove(0).1), + ); + } + + let e = Enum { + name, + name_camel_case: self.name.to_camel_case(), + variants_camel_case: actual_variants.iter().map(|s| s.to_camel_case()).collect(), + variants: actual_variants, + }; + + Ok(e) + } +} + +/// A query which compiles a property. +struct CompileProperty<'a> { + /// Name of the property to compile + name: &'a str, + /// Which enum this property is defined + /// for (used to avoid issues with + /// duplicate property names) + on: &'a str, +} + +impl<'a, 'b> Query<'b> for CompileProperty<'a> { + type Output = Property<'b>; + + fn execute(&self, cx: &Context<'b>) -> anyhow::Result<Self::Output> { + let model = cx + .find_property_model(self.name, self.on) + .with_context(|| format!("no property matched the name `{}`", self.name))?; + + let (on, mapping, name, typ, reverse) = match model { + Model::Property { + on, + mapping, + name, + typ, + reverse, + } => (on, mapping, name, typ, *reverse), + _ => unreachable!(), + }; + + let mapping = mapping + .iter() + .flat_map(|(keys, value)| { + keys.iter().copied().zip(std::iter::repeat_with(move || { + Value::from_ron(value.clone(), typ.clone()).unwrap() + })) + }) + .collect::<BTreeMap<_, _>>(); + + let on_enum = + Rc::new(cx.query(CompileEnum { name: *on }).with_context(|| { + format!("failed to compile `on: {}` for property {}", on, name) + })?); + + // Expand expressions + let mut actual_mapping = BTreeMap::new(); + for (key, value) in &mapping { + let expressions = if let Value::Custom(x) = value { + vec![*key, x.as_str()] + } else { + vec![*key] + }; + + let filter: Box<dyn Fn(&str) -> bool> = if let Type::Custom(enum_name) = typ { + let e = cx.query(CompileEnum { name: enum_name })?; + Box::new(move |variant| e.variants.contains(&Cow::Borrowed(variant))) + } else { + Box::new(|_| true) + }; + + let on_enum = Rc::clone(&on_enum); + let filter2 = move |variant: &str| on_enum.variants.contains(&Cow::Borrowed(variant)); + + let expanded = expand_expressions(cx, &expressions, |_, i, variant| { + if i == 0 { + filter2(variant) + } else { + filter(variant) + } + })?; + + let new_pairs = expanded.into_iter().map(|mut vec| { + let (original_expression, key) = vec.remove(0); + let value = if let Type::Custom(_) = typ { + Value::Custom(vec.remove(0).1.to_mut().clone()) + } else { + mapping[original_expression].clone() + }; + (key, value) + }); + + actual_mapping.extend(new_pairs); + } + + Ok(Property { + on, + name, + reverse, + typ: typ.clone(), + mapping: actual_mapping + .into_iter() + .map(|(mut key, value)| (Cow::from(key.to_mut().clone()), value)) + .collect(), + }) + } +} + +type ExpandResult<'a> = Vec<(&'a str, Cow<'a, str>)>; + +/// Expands one or more associated expressions in a data file. +/// +/// # Format +/// Expressions may specify an expansion clause in the form `${var}`. +/// This clause will cause the expression to expand, with each +/// new expression corresponding to a variant of the enum `var`. +/// For example, consider an `enum color { red, green, blue }`. +/// `${color}` would expand to three new expressions: `[red, green, blue]`. +/// Similarly, `${color}_wool` would expand to the expressions `[red_wool, green_wool, blue_wool]`. +/// +/// When there are multiple expansion clauses in a single expression, +/// then all pairs of variant names will be evauluated. For example, +/// let's add an `enum animal { dog, cat, chicken }`. With this context, +/// `${color}_${animal}` expands to the expressions +/// +/// [red_dog, green_dog, blue_dog, red_cat, green_cat, blue_cat, +/// red_chicken, green_chicken, blue_chicken]. +/// +/// Multiple expressions may exist in the same context. For example, consider +/// the case of property mappings. A mapping might look like this: +/// `"${animal}_${color}": "${color}"`. The result of this would +/// be that for each expanded value, the two `color` clauses will +/// _match_ rather than expanding to all possible combinations of two colors. +/// +/// # Filters +/// An optional filter function may be specified which filters +/// the expanded expressions by some predicate. We use this +/// to filter expressions by those which point to valid enum variants, +/// for convenience. +fn expand_expressions<'a>( + cx: &Context<'a>, + expressions: &[&'a str], + mut filter: impl FnMut(&Context<'a>, usize, &str) -> bool, +) -> anyhow::Result<Vec<ExpandResult<'a>>> { + // Determine the locations of expansion clauses in the expressions. + // This is currently handled using regexes, which is unlikely to be optimal. + static EXPR_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("\\$\\{[^}]+}").unwrap()); + + #[derive(Debug, PartialEq, Eq, Hash, Clone)] + struct MatchLocation { + /// The index into `expressions` of this match + expr: usize, + /// The byte range of characters in the expression + /// which from an expansion clause + range: Range<usize>, + } + + // Compute the locations of expansion clauses. + let mut matches = vec![]; + for (i, expression) in expressions.iter().copied().enumerate() { + let mut offset = 0; + while let Some(m) = EXPR_REGEX.find(&expression[offset..]) { + let location = MatchLocation { + expr: i, + range: Range { + start: m.start() + offset, + end: m.end() + offset, + }, + }; + matches.push(location); + offset += m.end(); + } + } + + // Determine the variables being expanded in each clause. + // This is a mapping from variable name => match locations for this variable. + let mut variables: HashMap<&'a str, Vec<MatchLocation>> = HashMap::new(); + for m in &matches { + let variable: &'a str = &(expressions[m.expr])[m.range.start + 2..m.range.end - 1]; + variables.entry(variable).or_default().push(m.clone()); + } + + // Perform expansion. + let mut results: Vec<Vec<(&'a str, Cow<'a, str>)>> = vec![expressions + .iter() + .copied() + .zip(expressions.iter().copied().map(Cow::from)) + .collect()]; + + for (variable, _) in variables { + // Determine the variants of the enum being expanded. + let e = cx + .query(CompileEnum { name: variable }) + .with_context(|| format!("failed to compile enum `{}`", variable))?; + let variants = e.variants.as_slice(); + + // Expand the pattern in `results` + // to include each variant. + let replace_pattern = Rc::new(format!("${{{}}}", variable)); + results = results + .into_iter() + .flat_map(|mut result| { + let replace_pattern = Rc::clone(&replace_pattern); + variants.iter().map(move |variant| { + result + .iter_mut() + .map(|(original, result)| { + ( + *original, + result + .to_mut() + .clone() + .replace(replace_pattern.as_str(), variant) + .into(), + ) + }) + .collect() + }) + }) + .collect(); + } + + results.retain(|result_set| { + result_set + .iter() + .enumerate() + .all(|(i, (_, res))| filter(cx, i, res)) + }); + + Ok(results) +} + +/// Creates a `Data` from a slice +/// of data files. +pub fn from_slice(files: &[DataFile]) -> anyhow::Result<Data> { + let models: Vec<_> = files + .iter() + .map(parse_file) + .collect::<anyhow::Result<Vec<_>>>() + .context("failed to parse data files")? + .into_iter() + .flatten() + .collect(); + + // The borrow checker has stopped me, and I'm tired. + // This is a build script. Memory leaks are fine. + // FIXME + let models = Box::leak(models.into_boxed_slice()); + + let cx = Context { models }; + + let mut data = Data::default(); + for (file_name, model) in cx.models { + if let Model::Enum { name, .. } = model { + let e = cx.query(CompileEnum { name: *name }).with_context(|| { + format!( + "failed to compile enum `{}` defined in `{}`", + name, file_name + ) + })?; + data.files + .entry(*file_name) + .or_insert_with(|| FileData { + file_name: *file_name, + ..Default::default() + }) + .enums + .insert(e.name, e); + } else if let Model::Property { name, on, .. } = model { + let p = cx + .query(CompileProperty { + name: *name, + on: *on, + }) + .with_context(|| { + format!( + "failed to compile property `{}` defined in `{}`", + name, file_name + ) + })?; + data.files + .entry(*file_name) + .or_insert_with(|| FileData { + file_name: *file_name, + ..Default::default() + }) + .properties + .push(p); + } + } + + Ok(data) +} + +fn parse_file<'a>( + file: &'a DataFile, +) -> anyhow::Result<impl Iterator<Item = (&'a str, Model)> + 'a> { + Ok( + match crate::model::from_str(&file.contents) + .with_context(|| format!("failed to parse file `{}`", file.name))? + { + ModelFile::Single(model) => Either::Left(std::iter::once((file.name.as_str(), model))), + ModelFile::Multiple(models) => { + Either::Right(std::iter::repeat(file.name.as_str()).zip(models)) + } + }, + ) +} + +#[derive(Default, Debug)] +pub struct Data<'a> { + /// Mapping from file name => file contents + pub files: BTreeMap<&'a str, FileData<'a>>, +} + +#[derive(Debug, Default)] +pub struct FileData<'a> { + /// File name (without extension) + pub file_name: &'a str, + /// The enums defined in this file + /// + /// Mapping from enum names => enum + pub enums: BTreeMap<&'a str, Enum<'a>>, + /// The properties defined in this file + pub properties: Vec<Property<'a>>, +} + +#[derive(Debug, Default)] +pub struct Enum<'a> { + pub name: &'a str, + pub name_camel_case: String, + + pub variants: Vec<Cow<'a, str>>, + pub variants_camel_case: Vec<String>, +} + +#[derive(Debug)] +pub struct Property<'a> { + pub on: &'a str, + pub name: &'a str, + pub typ: Type<'a>, + pub reverse: bool, + /// Mapping from variant names => values + pub mapping: BTreeMap<Cow<'a, str>, Value>, +} + +#[derive(Clone, Debug)] +pub enum Value { + U32(u32), + F64(f64), + String(String), + Slice(Vec<Value>), + Bool(bool), + /// custom type - name of enum variant + Custom(String), +} + +impl Value { + pub fn from_ron(r: ron::Value, typ: Type) -> anyhow::Result<Self> { + use ron::Value as Ron; + + Ok(match r { + Ron::Number(n) => match typ { + Type::U32 => Value::U32(n.as_i64().unwrap() as u32), + Type::F64 => Value::F64(n.as_f64().unwrap_or_else(|| n.as_i64().unwrap() as f64)), + t => anyhow::bail!("value {:?} is not a valid instance of type {:?}", t, r), + }, + Ron::String(s) if typ == Type::String => Value::String(s), + Ron::String(s) => Value::Custom(s), + Ron::Seq(values) => Value::Slice( + values + .into_iter() + .map(|v| Value::from_ron(v, typ.clone())) + .collect::<anyhow::Result<Vec<_>>>()?, + ), + Ron::Bool(x) => Value::Bool(x), + r => anyhow::bail!("value {:?} is not supported for type {:?}", r, typ), + }) + } +} diff --git a/feather/old/definitions/generator/src/generated.rs b/feather/old/definitions/generator/src/generated.rs new file mode 100644 index 000000000..25b5dd1a8 --- /dev/null +++ b/feather/old/definitions/generator/src/generated.rs @@ -0,0 +1,373 @@ +//! Writes out generated data files, such as block and item enums. + +use crate::model::{Model, ModelFile, Type, VecOrOne}; +use anyhow::Context; +use std::fs::File; +use std::io::Write; + +use indexmap::map::IndexMap; +use itertools::Itertools; +use once_cell::sync::Lazy; +use regex::Regex; +use ron::value::Number; +use serde::de::IgnoredAny; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeSet; + +pub fn write(dir: &str) -> anyhow::Result<()> { + let block = format!("{}/block.ron", dir); + let item = format!("{}/item.ron", dir); + + std::fs::create_dir_all(dir) + .with_context(|| format!("failed to create directory `{}`", dir))?; + + let block_model = + load_block_model().context("failed to load blocks.json from minecraft-data repo")?; + let collision_shape_model = load_collision_shape_model() + .context("failed to load blockCollisionShapes.json from minecraft-data repo")?; + let gblock = generate_block(&block_model, &collision_shape_model) + .context("failed to generate block data file")?; + + let model: ItemModel = serde_json::from_slice(feather_data::minecraft_data::ITEMS)?; + let gitem = generate_item(&model).context("failed to generate item data file")?; + + for (path, content) in &[(block, gblock), (item, gitem)] { + let mut file = + File::create(path).with_context(|| format!("failed to create `{}`", path))?; + let s = ron::ser::to_string_pretty(content, Default::default())?; + + file.write_all(b"// This files is @generated\n") + .and_then(|_| file.write_all(s.as_bytes())) + .with_context(|| format!("failed to write to `{}`", path))?; + file.flush()?; + } + + Ok(()) +} + +#[derive(Debug, Serialize, Deserialize)] +struct BlockModel<'a>(#[serde(borrow)] Vec<Block<'a>>); + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Block<'a> { + id: i32, + display_name: &'a str, + name: &'a str, + hardness: Option<f64>, + min_state_id: i32, + max_state_id: u32, + drops: Vec<usize>, + diggable: bool, + transparent: bool, + filter_light: u8, + emit_light: u8, + bounding_box: &'a str, + stack_size: u32, +} + +fn load_block_model() -> anyhow::Result<BlockModel<'static>> { + serde_json::from_slice(feather_data::minecraft_data::BLOCKS).map_err(anyhow::Error::from) +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct CollisionShapeModel<'a> { + #[serde(borrow)] + blocks: IndexMap<&'a str, VecOrOne<usize>>, + shapes: IgnoredAny, +} + +fn load_collision_shape_model() -> anyhow::Result<CollisionShapeModel<'static>> { + serde_json::from_slice(feather_data::minecraft_data::BLOCKCOLLISIONSHAPES) + .map_err(anyhow::Error::from) +} + +static SIMPLIFIED_REGEX: Lazy<Vec<(Regex, &'static str)>> = Lazy::new(|| { + let mut vec = Vec::new(); + + vec.push((Regex::new(r"^.*air$").unwrap(), "air")); + vec.push((Regex::new(r"^.+_planks$").unwrap(), "planks")); + vec.push((Regex::new(r"^(\w+|dark_oak)_sapling$").unwrap(), "sapling")); + vec.push((Regex::new(r"^.+_(log|wood)$").unwrap(), "log")); + vec.push((Regex::new(r"^.+_leaves$").unwrap(), "leaves")); + vec.push((Regex::new(r"^.+_bed$").unwrap(), "bed")); + vec.push((Regex::new(r"^.+_wool$").unwrap(), "wool")); + vec.push(( + Regex::new(r"^(allium|poppy|dandelion|\w+_(orchid|bluet|tulip|daisy))$").unwrap(), + "flower", + )); + vec.push(( + Regex::new(r"^(oak|spruce|birch|jungle|acacia|dark_oak)_pressure_plate$").unwrap(), + "wooden_pressure_plate", + )); + vec.push((Regex::new(r"^.+_stained_glass$").unwrap(), "stained_glass")); + vec.push(( + Regex::new(r"^(oak|spruce|birch|jungle|acacia|dark_oak)_trapdoor$").unwrap(), + "wooden_trapdoor", + )); + vec.push((Regex::new(r"^potted_.+$").unwrap(), "potted_plant")); + vec.push(( + Regex::new(r"^(oak|spruce|birch|jungle|acacia|dark_oak)_button$").unwrap(), + "wooden_button", + )); + vec.push((Regex::new(r"^(\w+_)?anvil$").unwrap(), "anvil")); + vec.push(( + Regex::new(r"^.+_glazed_terracotta$").unwrap(), + "glazed_terracotta", + )); // this will be matched first + vec.push((Regex::new(r"^.*terracotta$").unwrap(), "terracotta")); + vec.push(( + Regex::new(r"^.+_stained_glass_pane$").unwrap(), + "stained_glass_pane", + )); + vec.push((Regex::new(r"^.+_carpet$").unwrap(), "carpet")); + vec.push((Regex::new(r"^.+_wall_banner$").unwrap(), "wall_banner")); // this will be matched first + vec.push((Regex::new(r"^.+_banner$").unwrap(), "banner")); + vec.push((Regex::new(r"^.+_slab$").unwrap(), "slab")); + vec.push((Regex::new(r"^.+_stairs$").unwrap(), "stairs")); + vec.push((Regex::new(r"^.+_fence_gate$").unwrap(), "fence_gate")); + vec.push((Regex::new(r"^.+_fence$").unwrap(), "fence")); + vec.push(( + Regex::new(r"^(oak|spruce|birch|jungle|acacia|dark_oak)_door$").unwrap(), + "wooden_door", + )); + vec.push((Regex::new(r"^.*shulker_box$").unwrap(), "shulker_box")); + vec.push((Regex::new(r"^.+_concrete$").unwrap(), "concrete")); + vec.push(( + Regex::new(r"^.+_concrete_powder$").unwrap(), + "concrete_powder", + )); + vec.push((Regex::new(r"^.+_coral$").unwrap(), "coral")); + vec.push((Regex::new(r"^.+_coral_block$").unwrap(), "coral_block")); + vec.push((Regex::new(r"^.+_coral_fan$").unwrap(), "coral_fan")); + vec.push(( + Regex::new(r"^.+_coral_wall_fan$").unwrap(), + "coral_wall_fan", + )); + vec.push((Regex::new(r"^\w+_mushroom$").unwrap(), "mushroom")); + + vec +}); + +fn to_simplified_name(block_name: &str) -> Option<&'static str> { + for (regex, replacement) in SIMPLIFIED_REGEX.iter() { + if regex.is_match(block_name) { + return Some(replacement); + } + } + + None +} + +fn generate_block<'a>( + block_model: &'a BlockModel, + collision_shape_model: &'a CollisionShapeModel, +) -> anyhow::Result<ModelFile<'a>> { + let known_bounding_boxes: BTreeSet<_> = block_model + .0 + .iter() + .map(|block| block.bounding_box) + .collect(); + + let bbox = Model::Enum { + name: "block_bounding_box", + variants: known_bounding_boxes.into_iter().collect(), + }; + + let display_name = block_property( + "display_name", + true, + block_model, + |block| ron::Value::String(block.display_name.to_owned()), + Type::String, + ); + let diggable = block_property( + "diggable", + false, + block_model, + |block| ron::Value::Bool(block.diggable), + Type::Bool, + ); + let hardness = block_property( + "hardness", + false, + block_model, + |block| ron::Value::Number(Number::new(block.hardness.unwrap_or_default())), + Type::F64, + ); + let opaque = block_property( + "opaque", + false, + block_model, + |block| ron::Value::Bool(!block.transparent), + Type::Bool, + ); + let solid = block_property( + "solid", + false, + block_model, + |block| ron::Value::Bool(block.bounding_box == "block"), + Type::Bool, + ); + let full_block = Model::Property { + on: "block_kind", + name: "full_block", + reverse: false, + typ: Type::Bool, + mapping: collision_shape_model + .blocks + .iter() + .map(|(&name, cb_index)| { + ( + VecOrOne::One(name), + ron::Value::Bool(matches!(cb_index, VecOrOne::One(cb_index) if *cb_index == 1)), + ) + }) + .collect(), + }; + let to_simplified_kind = Model::Property { + on: "block_kind", + name: "to_simplified_kind", + reverse: false, + typ: Type::Custom("simplified_block_kind"), + mapping: block_model + .0 + .iter() + .map(|block| block.name) + .map(|name| { + ( + VecOrOne::One(name), + ron::Value::String(to_simplified_name(name).unwrap_or(name).to_string()), + ) + }) + .collect(), + }; + + let kind = Model::Enum { + name: "block_kind", + variants: block_model.0.iter().map(|block| block.name).collect(), + }; + + let simplified_kind = Model::Enum { + name: "simplified_block_kind", + variants: block_model + .0 + .iter() + .map(|block| block.name) + .map(|name| to_simplified_name(name).unwrap_or(name)) + .unique() + .collect(), + }; + + Ok(ModelFile::Multiple(vec![ + kind, + bbox, + display_name, + diggable, + hardness, + opaque, + solid, + full_block, + simplified_kind, + to_simplified_kind, + ])) +} + +fn block_property<'a>( + name: &'a str, + reverse: bool, + model: &BlockModel<'a>, + mut accessor: impl FnMut(&Block) -> ron::Value, + typ: Type<'a>, +) -> Model<'a> { + Model::Property { + on: "block_kind", + name, + typ, + reverse, + mapping: model + .0 + .iter() + .map(|block| (VecOrOne::One(block.name), accessor(block))) + .collect(), + } +} + +#[derive(Debug, Serialize, Deserialize)] +struct ItemModel<'a>(#[serde(borrow)] Vec<Item<'a>>); + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Item<'a> { + id: i32, + display_name: &'a str, + name: &'a str, + stack_size: u32, +} + +fn generate_item<'a>(model: &'a ItemModel) -> anyhow::Result<ModelFile<'a>> { + let item = Model::Enum { + name: "item", + variants: model.0.iter().map(|item| item.name).collect(), + }; + + let display_name = item_property( + "display_name", + false, + &model, + |item| ron::Value::String(item.display_name.to_string()), + Type::String, + ); + let stack_size = item_property( + "stack_size", + false, + &model, + |item| ron::Value::Number(ron::value::Number::new(item.stack_size as f64)), + Type::U32, + ); + + let vanilla_id = item_property( + "vanilla_id", + true, + &model, + |item| ron::Value::Number(ron::value::Number::new(item.id as f64)), + Type::U32, + ); + + let identifier = item_property( + "identifier", + true, + &model, + |item| ron::Value::String(format!("minecraft:{}", item.name)), + Type::String, + ); + + Ok(ModelFile::Multiple(vec![ + item, + display_name, + stack_size, + vanilla_id, + identifier, + ])) +} + +fn item_property<'a>( + name: &'a str, + reverse: bool, + model: &'a ItemModel, + mut accessor: impl FnMut(&Item) -> ron::Value, + typ: Type<'a>, +) -> Model<'a> { + Model::Property { + on: "item", + name, + typ, + reverse, + mapping: model + .0 + .iter() + .map(|item| (VecOrOne::One(item.name), accessor(item))) + .collect(), + } +} diff --git a/feather/old/definitions/generator/src/main.rs b/feather/old/definitions/generator/src/main.rs new file mode 100644 index 000000000..d84a4a744 --- /dev/null +++ b/feather/old/definitions/generator/src/main.rs @@ -0,0 +1,65 @@ +use anyhow::Context; +use std::fs::File; +use std::io::Read; +use std::path::Path; +use walkdir::WalkDir; + +mod backend; +mod frontend; +mod generated; +mod model; + +use std::path::PathBuf; + +fn main() { + let mut data_path = PathBuf::new(); + data_path.push(env!("CARGO_MANIFEST_DIR")); + let mut target_path = data_path.clone(); + + data_path.push("../data"); + target_path.push("../src/generated"); + + if let Err(e) = load_directory(&data_path, target_path.as_os_str().to_str().unwrap()) { + panic!("{:?}", e); + } +} + +pub fn load_directory(dir: impl AsRef<Path>, target_dir: &str) -> anyhow::Result<()> { + let dir = dir.as_ref(); + + generated::write(&format!("{}/generated", dir.display())) + .context("failed to write generated data")?; + + let mut files = vec![]; + for entry in WalkDir::new(dir) { + let entry = entry.context("failed to open DirEntry")?; + + if entry.file_type().is_dir() { + continue; + } + + let mut name = entry + .path() + .file_stem() + .ok_or_else(|| { + anyhow::anyhow!("failed to get file stem for `{}`", entry.path().display()) + })? + .to_string_lossy(); + let mut contents = String::new(); + let mut file = File::open(entry.path()) + .with_context(|| format!("failed to open file `{}`", entry.path().to_string_lossy()))?; + + file.read_to_string(&mut contents) + .with_context(|| format!("failed to read file `{}`", entry.path().to_string_lossy()))?; + + files.push(frontend::DataFile { + name: name.to_mut().clone(), + contents, + }); + } + + let data = frontend::from_slice(&files).context("failed to load data")?; + backend::generate(target_dir, &data).context("failed to generate code for data")?; + + Ok(()) +} diff --git a/feather/old/definitions/generator/src/model.rs b/feather/old/definitions/generator/src/model.rs new file mode 100644 index 000000000..e302658f3 --- /dev/null +++ b/feather/old/definitions/generator/src/model.rs @@ -0,0 +1,61 @@ +use indexmap::map::IndexMap; +use itertools::Either; +use serde::{Deserialize, Serialize}; + +/// Loads a model file. +pub fn from_str(s: &str) -> anyhow::Result<ModelFile> { + ron::de::from_str(s).map_err(anyhow::Error::from) +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum ModelFile<'a> { + Single(#[serde(borrow)] Model<'a>), + Multiple(#[serde(borrow)] Vec<Model<'a>>), +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Model<'a> { + Enum { + name: &'a str, + variants: Vec<&'a str>, + }, + Property { + on: &'a str, + name: &'a str, + #[serde(default)] + reverse: bool, + #[serde(rename = "type")] + typ: Type<'a>, + mapping: IndexMap<VecOrOne<&'a str>, ron::Value>, + }, +} + +#[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq)] +#[serde(untagged)] +pub enum VecOrOne<T> { + Vec(Vec<T>), + One(T), +} + +impl<T> VecOrOne<T> { + pub fn iter<'a>(&'a self) -> impl Iterator<Item = &T> + 'a { + match self { + VecOrOne::Vec(v) => Either::Left(v.iter()), + VecOrOne::One(v) => Either::Right(std::iter::once(v)), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Type<'a> { + Slice(Box<Type<'a>>), + #[serde(rename = "u32")] + U32, + #[serde(rename = "f64")] + F64, + #[serde(rename = "string")] + String, + #[serde(rename = "bool")] + Bool, + Custom(&'a str), +} diff --git a/feather/old/definitions/rebuild.sh b/feather/old/definitions/rebuild.sh new file mode 100755 index 000000000..af5ccd6f4 --- /dev/null +++ b/feather/old/definitions/rebuild.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +cargo run --bin feather-definitions-generator \ No newline at end of file diff --git a/feather/old/definitions/src/generated/block.rs b/feather/old/definitions/src/generated/block.rs new file mode 100644 index 000000000..e61c924e8 --- /dev/null +++ b/feather/old/definitions/src/generated/block.rs @@ -0,0 +1,5750 @@ +// This file is @generated +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ToPrimitive, FromPrimitive)] +pub enum BlockBoundingBox { + Block, + Empty, +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ToPrimitive, FromPrimitive)] +pub enum BlockKind { + Air, + Stone, + Granite, + PolishedGranite, + Diorite, + PolishedDiorite, + Andesite, + PolishedAndesite, + GrassBlock, + Dirt, + CoarseDirt, + Podzol, + Cobblestone, + OakPlanks, + SprucePlanks, + BirchPlanks, + JunglePlanks, + AcaciaPlanks, + DarkOakPlanks, + OakSapling, + SpruceSapling, + BirchSapling, + JungleSapling, + AcaciaSapling, + DarkOakSapling, + Bedrock, + Water, + Lava, + Sand, + RedSand, + Gravel, + GoldOre, + IronOre, + CoalOre, + OakLog, + SpruceLog, + BirchLog, + JungleLog, + AcaciaLog, + DarkOakLog, + StrippedSpruceLog, + StrippedBirchLog, + StrippedJungleLog, + StrippedAcaciaLog, + StrippedDarkOakLog, + StrippedOakLog, + OakWood, + SpruceWood, + BirchWood, + JungleWood, + AcaciaWood, + DarkOakWood, + StrippedOakWood, + StrippedSpruceWood, + StrippedBirchWood, + StrippedJungleWood, + StrippedAcaciaWood, + StrippedDarkOakWood, + OakLeaves, + SpruceLeaves, + BirchLeaves, + JungleLeaves, + AcaciaLeaves, + DarkOakLeaves, + Sponge, + WetSponge, + Glass, + LapisOre, + LapisBlock, + Dispenser, + Sandstone, + ChiseledSandstone, + CutSandstone, + NoteBlock, + WhiteBed, + OrangeBed, + MagentaBed, + LightBlueBed, + YellowBed, + LimeBed, + PinkBed, + GrayBed, + LightGrayBed, + CyanBed, + PurpleBed, + BlueBed, + BrownBed, + GreenBed, + RedBed, + BlackBed, + PoweredRail, + DetectorRail, + StickyPiston, + Cobweb, + Grass, + Fern, + DeadBush, + Seagrass, + TallSeagrass, + Piston, + PistonHead, + WhiteWool, + OrangeWool, + MagentaWool, + LightBlueWool, + YellowWool, + LimeWool, + PinkWool, + GrayWool, + LightGrayWool, + CyanWool, + PurpleWool, + BlueWool, + BrownWool, + GreenWool, + RedWool, + BlackWool, + MovingPiston, + Dandelion, + Poppy, + BlueOrchid, + Allium, + AzureBluet, + RedTulip, + OrangeTulip, + WhiteTulip, + PinkTulip, + OxeyeDaisy, + BrownMushroom, + RedMushroom, + GoldBlock, + IronBlock, + Bricks, + Tnt, + Bookshelf, + MossyCobblestone, + Obsidian, + Torch, + WallTorch, + Fire, + Spawner, + OakStairs, + Chest, + RedstoneWire, + DiamondOre, + DiamondBlock, + CraftingTable, + Wheat, + Farmland, + Furnace, + Sign, + OakDoor, + Ladder, + Rail, + CobblestoneStairs, + WallSign, + Lever, + StonePressurePlate, + IronDoor, + OakPressurePlate, + SprucePressurePlate, + BirchPressurePlate, + JunglePressurePlate, + AcaciaPressurePlate, + DarkOakPressurePlate, + RedstoneOre, + RedstoneTorch, + RedstoneWallTorch, + StoneButton, + Snow, + Ice, + SnowBlock, + Cactus, + Clay, + SugarCane, + Jukebox, + OakFence, + Pumpkin, + Netherrack, + SoulSand, + Glowstone, + NetherPortal, + CarvedPumpkin, + JackOLantern, + Cake, + Repeater, + WhiteStainedGlass, + OrangeStainedGlass, + MagentaStainedGlass, + LightBlueStainedGlass, + YellowStainedGlass, + LimeStainedGlass, + PinkStainedGlass, + GrayStainedGlass, + LightGrayStainedGlass, + CyanStainedGlass, + PurpleStainedGlass, + BlueStainedGlass, + BrownStainedGlass, + GreenStainedGlass, + RedStainedGlass, + BlackStainedGlass, + OakTrapdoor, + SpruceTrapdoor, + BirchTrapdoor, + JungleTrapdoor, + AcaciaTrapdoor, + DarkOakTrapdoor, + InfestedStone, + InfestedCobblestone, + InfestedStoneBricks, + InfestedMossyStoneBricks, + InfestedCrackedStoneBricks, + InfestedChiseledStoneBricks, + StoneBricks, + MossyStoneBricks, + CrackedStoneBricks, + ChiseledStoneBricks, + BrownMushroomBlock, + RedMushroomBlock, + MushroomStem, + IronBars, + GlassPane, + Melon, + AttachedPumpkinStem, + AttachedMelonStem, + PumpkinStem, + MelonStem, + Vine, + OakFenceGate, + BrickStairs, + StoneBrickStairs, + Mycelium, + LilyPad, + NetherBricks, + NetherBrickFence, + NetherBrickStairs, + NetherWart, + EnchantingTable, + BrewingStand, + Cauldron, + EndPortal, + EndPortalFrame, + EndStone, + DragonEgg, + RedstoneLamp, + Cocoa, + SandstoneStairs, + EmeraldOre, + EnderChest, + TripwireHook, + Tripwire, + EmeraldBlock, + SpruceStairs, + BirchStairs, + JungleStairs, + CommandBlock, + Beacon, + CobblestoneWall, + MossyCobblestoneWall, + FlowerPot, + PottedOakSapling, + PottedSpruceSapling, + PottedBirchSapling, + PottedJungleSapling, + PottedAcaciaSapling, + PottedDarkOakSapling, + PottedFern, + PottedDandelion, + PottedPoppy, + PottedBlueOrchid, + PottedAllium, + PottedAzureBluet, + PottedRedTulip, + PottedOrangeTulip, + PottedWhiteTulip, + PottedPinkTulip, + PottedOxeyeDaisy, + PottedRedMushroom, + PottedBrownMushroom, + PottedDeadBush, + PottedCactus, + Carrots, + Potatoes, + OakButton, + SpruceButton, + BirchButton, + JungleButton, + AcaciaButton, + DarkOakButton, + SkeletonWallSkull, + SkeletonSkull, + WitherSkeletonWallSkull, + WitherSkeletonSkull, + ZombieWallHead, + ZombieHead, + PlayerWallHead, + PlayerHead, + CreeperWallHead, + CreeperHead, + DragonWallHead, + DragonHead, + Anvil, + ChippedAnvil, + DamagedAnvil, + TrappedChest, + LightWeightedPressurePlate, + HeavyWeightedPressurePlate, + Comparator, + DaylightDetector, + RedstoneBlock, + NetherQuartzOre, + Hopper, + QuartzBlock, + ChiseledQuartzBlock, + QuartzPillar, + QuartzStairs, + ActivatorRail, + Dropper, + WhiteTerracotta, + OrangeTerracotta, + MagentaTerracotta, + LightBlueTerracotta, + YellowTerracotta, + LimeTerracotta, + PinkTerracotta, + GrayTerracotta, + LightGrayTerracotta, + CyanTerracotta, + PurpleTerracotta, + BlueTerracotta, + BrownTerracotta, + GreenTerracotta, + RedTerracotta, + BlackTerracotta, + WhiteStainedGlassPane, + OrangeStainedGlassPane, + MagentaStainedGlassPane, + LightBlueStainedGlassPane, + YellowStainedGlassPane, + LimeStainedGlassPane, + PinkStainedGlassPane, + GrayStainedGlassPane, + LightGrayStainedGlassPane, + CyanStainedGlassPane, + PurpleStainedGlassPane, + BlueStainedGlassPane, + BrownStainedGlassPane, + GreenStainedGlassPane, + RedStainedGlassPane, + BlackStainedGlassPane, + AcaciaStairs, + DarkOakStairs, + SlimeBlock, + Barrier, + IronTrapdoor, + Prismarine, + PrismarineBricks, + DarkPrismarine, + PrismarineStairs, + PrismarineBrickStairs, + DarkPrismarineStairs, + PrismarineSlab, + PrismarineBrickSlab, + DarkPrismarineSlab, + SeaLantern, + HayBlock, + WhiteCarpet, + OrangeCarpet, + MagentaCarpet, + LightBlueCarpet, + YellowCarpet, + LimeCarpet, + PinkCarpet, + GrayCarpet, + LightGrayCarpet, + CyanCarpet, + PurpleCarpet, + BlueCarpet, + BrownCarpet, + GreenCarpet, + RedCarpet, + BlackCarpet, + Terracotta, + CoalBlock, + PackedIce, + Sunflower, + Lilac, + RoseBush, + Peony, + TallGrass, + LargeFern, + WhiteBanner, + OrangeBanner, + MagentaBanner, + LightBlueBanner, + YellowBanner, + LimeBanner, + PinkBanner, + GrayBanner, + LightGrayBanner, + CyanBanner, + PurpleBanner, + BlueBanner, + BrownBanner, + GreenBanner, + RedBanner, + BlackBanner, + WhiteWallBanner, + OrangeWallBanner, + MagentaWallBanner, + LightBlueWallBanner, + YellowWallBanner, + LimeWallBanner, + PinkWallBanner, + GrayWallBanner, + LightGrayWallBanner, + CyanWallBanner, + PurpleWallBanner, + BlueWallBanner, + BrownWallBanner, + GreenWallBanner, + RedWallBanner, + BlackWallBanner, + RedSandstone, + ChiseledRedSandstone, + CutRedSandstone, + RedSandstoneStairs, + OakSlab, + SpruceSlab, + BirchSlab, + JungleSlab, + AcaciaSlab, + DarkOakSlab, + StoneSlab, + SandstoneSlab, + PetrifiedOakSlab, + CobblestoneSlab, + BrickSlab, + StoneBrickSlab, + NetherBrickSlab, + QuartzSlab, + RedSandstoneSlab, + PurpurSlab, + SmoothStone, + SmoothSandstone, + SmoothQuartz, + SmoothRedSandstone, + SpruceFenceGate, + BirchFenceGate, + JungleFenceGate, + AcaciaFenceGate, + DarkOakFenceGate, + SpruceFence, + BirchFence, + JungleFence, + AcaciaFence, + DarkOakFence, + SpruceDoor, + BirchDoor, + JungleDoor, + AcaciaDoor, + DarkOakDoor, + EndRod, + ChorusPlant, + ChorusFlower, + PurpurBlock, + PurpurPillar, + PurpurStairs, + EndStoneBricks, + Beetroots, + GrassPath, + EndGateway, + RepeatingCommandBlock, + ChainCommandBlock, + FrostedIce, + MagmaBlock, + NetherWartBlock, + RedNetherBricks, + BoneBlock, + StructureVoid, + Observer, + ShulkerBox, + WhiteShulkerBox, + OrangeShulkerBox, + MagentaShulkerBox, + LightBlueShulkerBox, + YellowShulkerBox, + LimeShulkerBox, + PinkShulkerBox, + GrayShulkerBox, + LightGrayShulkerBox, + CyanShulkerBox, + PurpleShulkerBox, + BlueShulkerBox, + BrownShulkerBox, + GreenShulkerBox, + RedShulkerBox, + BlackShulkerBox, + WhiteGlazedTerracotta, + OrangeGlazedTerracotta, + MagentaGlazedTerracotta, + LightBlueGlazedTerracotta, + YellowGlazedTerracotta, + LimeGlazedTerracotta, + PinkGlazedTerracotta, + GrayGlazedTerracotta, + LightGrayGlazedTerracotta, + CyanGlazedTerracotta, + PurpleGlazedTerracotta, + BlueGlazedTerracotta, + BrownGlazedTerracotta, + GreenGlazedTerracotta, + RedGlazedTerracotta, + BlackGlazedTerracotta, + WhiteConcrete, + OrangeConcrete, + MagentaConcrete, + LightBlueConcrete, + YellowConcrete, + LimeConcrete, + PinkConcrete, + GrayConcrete, + LightGrayConcrete, + CyanConcrete, + PurpleConcrete, + BlueConcrete, + BrownConcrete, + GreenConcrete, + RedConcrete, + BlackConcrete, + WhiteConcretePowder, + OrangeConcretePowder, + MagentaConcretePowder, + LightBlueConcretePowder, + YellowConcretePowder, + LimeConcretePowder, + PinkConcretePowder, + GrayConcretePowder, + LightGrayConcretePowder, + CyanConcretePowder, + PurpleConcretePowder, + BlueConcretePowder, + BrownConcretePowder, + GreenConcretePowder, + RedConcretePowder, + BlackConcretePowder, + Kelp, + KelpPlant, + DriedKelpBlock, + TurtleEgg, + DeadTubeCoralBlock, + DeadBrainCoralBlock, + DeadBubbleCoralBlock, + DeadFireCoralBlock, + DeadHornCoralBlock, + TubeCoralBlock, + BrainCoralBlock, + BubbleCoralBlock, + FireCoralBlock, + HornCoralBlock, + DeadTubeCoral, + DeadBrainCoral, + DeadBubbleCoral, + DeadFireCoral, + DeadHornCoral, + TubeCoral, + BrainCoral, + BubbleCoral, + FireCoral, + HornCoral, + DeadTubeCoralWallFan, + DeadBrainCoralWallFan, + DeadBubbleCoralWallFan, + DeadFireCoralWallFan, + DeadHornCoralWallFan, + TubeCoralWallFan, + BrainCoralWallFan, + BubbleCoralWallFan, + FireCoralWallFan, + HornCoralWallFan, + DeadTubeCoralFan, + DeadBrainCoralFan, + DeadBubbleCoralFan, + DeadFireCoralFan, + DeadHornCoralFan, + TubeCoralFan, + BrainCoralFan, + BubbleCoralFan, + FireCoralFan, + HornCoralFan, + SeaPickle, + BlueIce, + Conduit, + VoidAir, + CaveAir, + BubbleColumn, + StructureBlock, +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ToPrimitive, FromPrimitive)] +pub enum SimplifiedBlockKind { + Air, + Stone, + Granite, + PolishedGranite, + Diorite, + PolishedDiorite, + Andesite, + PolishedAndesite, + GrassBlock, + Dirt, + CoarseDirt, + Podzol, + Cobblestone, + Planks, + Sapling, + Bedrock, + Water, + Lava, + Sand, + RedSand, + Gravel, + GoldOre, + IronOre, + CoalOre, + Log, + Leaves, + Sponge, + WetSponge, + Glass, + LapisOre, + LapisBlock, + Dispenser, + Sandstone, + ChiseledSandstone, + CutSandstone, + NoteBlock, + Bed, + PoweredRail, + DetectorRail, + StickyPiston, + Cobweb, + Grass, + Fern, + DeadBush, + Seagrass, + TallSeagrass, + Piston, + PistonHead, + Wool, + MovingPiston, + Flower, + Mushroom, + GoldBlock, + IronBlock, + Bricks, + Tnt, + Bookshelf, + MossyCobblestone, + Obsidian, + Torch, + WallTorch, + Fire, + Spawner, + Stairs, + Chest, + RedstoneWire, + DiamondOre, + DiamondBlock, + CraftingTable, + Wheat, + Farmland, + Furnace, + Sign, + WoodenDoor, + Ladder, + Rail, + WallSign, + Lever, + StonePressurePlate, + IronDoor, + WoodenPressurePlate, + RedstoneOre, + RedstoneTorch, + RedstoneWallTorch, + StoneButton, + Snow, + Ice, + SnowBlock, + Cactus, + Clay, + SugarCane, + Jukebox, + Fence, + Pumpkin, + Netherrack, + SoulSand, + Glowstone, + NetherPortal, + CarvedPumpkin, + JackOLantern, + Cake, + Repeater, + StainedGlass, + WoodenTrapdoor, + InfestedStone, + InfestedCobblestone, + InfestedStoneBricks, + InfestedMossyStoneBricks, + InfestedCrackedStoneBricks, + InfestedChiseledStoneBricks, + StoneBricks, + MossyStoneBricks, + CrackedStoneBricks, + ChiseledStoneBricks, + BrownMushroomBlock, + RedMushroomBlock, + MushroomStem, + IronBars, + GlassPane, + Melon, + AttachedPumpkinStem, + AttachedMelonStem, + PumpkinStem, + MelonStem, + Vine, + FenceGate, + Mycelium, + LilyPad, + NetherBricks, + NetherWart, + EnchantingTable, + BrewingStand, + Cauldron, + EndPortal, + EndPortalFrame, + EndStone, + DragonEgg, + RedstoneLamp, + Cocoa, + EmeraldOre, + EnderChest, + TripwireHook, + Tripwire, + EmeraldBlock, + CommandBlock, + Beacon, + CobblestoneWall, + MossyCobblestoneWall, + FlowerPot, + PottedPlant, + Carrots, + Potatoes, + WoodenButton, + SkeletonWallSkull, + SkeletonSkull, + WitherSkeletonWallSkull, + WitherSkeletonSkull, + ZombieWallHead, + ZombieHead, + PlayerWallHead, + PlayerHead, + CreeperWallHead, + CreeperHead, + DragonWallHead, + DragonHead, + Anvil, + TrappedChest, + LightWeightedPressurePlate, + HeavyWeightedPressurePlate, + Comparator, + DaylightDetector, + RedstoneBlock, + NetherQuartzOre, + Hopper, + QuartzBlock, + ChiseledQuartzBlock, + QuartzPillar, + ActivatorRail, + Dropper, + Terracotta, + StainedGlassPane, + SlimeBlock, + Barrier, + IronTrapdoor, + Prismarine, + PrismarineBricks, + DarkPrismarine, + Slab, + SeaLantern, + HayBlock, + Carpet, + CoalBlock, + PackedIce, + Sunflower, + Lilac, + RoseBush, + Peony, + TallGrass, + LargeFern, + Banner, + WallBanner, + RedSandstone, + ChiseledRedSandstone, + CutRedSandstone, + SmoothStone, + SmoothSandstone, + SmoothQuartz, + SmoothRedSandstone, + EndRod, + ChorusPlant, + ChorusFlower, + PurpurBlock, + PurpurPillar, + EndStoneBricks, + Beetroots, + GrassPath, + EndGateway, + RepeatingCommandBlock, + ChainCommandBlock, + FrostedIce, + MagmaBlock, + NetherWartBlock, + RedNetherBricks, + BoneBlock, + StructureVoid, + Observer, + ShulkerBox, + GlazedTerracotta, + Concrete, + ConcretePowder, + Kelp, + KelpPlant, + DriedKelpBlock, + TurtleEgg, + CoralBlock, + Coral, + CoralWallFan, + CoralFan, + SeaPickle, + BlueIce, + Conduit, + BubbleColumn, + StructureBlock, +} +impl crate::BlockKind { + pub fn display_name(self) -> &'static str { + match self { + crate::BlockKind::AcaciaButton => "Acacia Button", + crate::BlockKind::AcaciaDoor => "Acacia Door", + crate::BlockKind::AcaciaFence => "Acacia Fence", + crate::BlockKind::AcaciaFenceGate => "Acacia Fence Gate", + crate::BlockKind::AcaciaLeaves => "Acacia Leaves", + crate::BlockKind::AcaciaLog => "Acacia Log", + crate::BlockKind::AcaciaPlanks => "Acacia Planks", + crate::BlockKind::AcaciaPressurePlate => "Acacia Pressure Plate", + crate::BlockKind::AcaciaSapling => "Acacia Sapling", + crate::BlockKind::AcaciaSlab => "Acacia Slab", + crate::BlockKind::AcaciaStairs => "Acacia Stairs", + crate::BlockKind::AcaciaTrapdoor => "Acacia Trapdoor", + crate::BlockKind::AcaciaWood => "Acacia Wood", + crate::BlockKind::ActivatorRail => "Activator Rail", + crate::BlockKind::Air => "Air", + crate::BlockKind::Allium => "Allium", + crate::BlockKind::Andesite => "Andesite", + crate::BlockKind::Anvil => "Anvil", + crate::BlockKind::AttachedMelonStem => "Attached Melon Stem", + crate::BlockKind::AttachedPumpkinStem => "Attached Pumpkin Stem", + crate::BlockKind::AzureBluet => "Azure Bluet", + crate::BlockKind::Barrier => "Barrier", + crate::BlockKind::Beacon => "Beacon", + crate::BlockKind::Bedrock => "Bedrock", + crate::BlockKind::Beetroots => "Beetroots", + crate::BlockKind::BirchButton => "Birch Button", + crate::BlockKind::BirchDoor => "Birch Door", + crate::BlockKind::BirchFence => "Birch Fence", + crate::BlockKind::BirchFenceGate => "Birch Fence Gate", + crate::BlockKind::BirchLeaves => "Birch Leaves", + crate::BlockKind::BirchLog => "Birch Log", + crate::BlockKind::BirchPlanks => "Birch Planks", + crate::BlockKind::BirchPressurePlate => "Birch Pressure Plate", + crate::BlockKind::BirchSapling => "Birch Sapling", + crate::BlockKind::BirchSlab => "Birch Slab", + crate::BlockKind::BirchStairs => "Birch Stairs", + crate::BlockKind::BirchTrapdoor => "Birch Trapdoor", + crate::BlockKind::BirchWood => "Birch Wood", + crate::BlockKind::BlackBanner => "Black Banner", + crate::BlockKind::BlackBed => "Black Bed", + crate::BlockKind::BlackCarpet => "Black Carpet", + crate::BlockKind::BlackConcrete => "Black Concrete", + crate::BlockKind::BlackConcretePowder => "Black Concrete Powder", + crate::BlockKind::BlackGlazedTerracotta => "Black Glazed Terracotta", + crate::BlockKind::BlackShulkerBox => "Black Shulker Box", + crate::BlockKind::BlackStainedGlass => "Black Stained Glass", + crate::BlockKind::BlackStainedGlassPane => "Black Stained Glass Pane", + crate::BlockKind::BlackTerracotta => "Black Terracotta", + crate::BlockKind::BlackWallBanner => "Black wall banner", + crate::BlockKind::BlackWool => "Black Wool", + crate::BlockKind::BlueBanner => "Blue Banner", + crate::BlockKind::BlueBed => "Blue Bed", + crate::BlockKind::BlueCarpet => "Blue Carpet", + crate::BlockKind::BlueConcrete => "Blue Concrete", + crate::BlockKind::BlueConcretePowder => "Blue Concrete Powder", + crate::BlockKind::BlueGlazedTerracotta => "Blue Glazed Terracotta", + crate::BlockKind::BlueIce => "Blue Ice", + crate::BlockKind::BlueOrchid => "Blue Orchid", + crate::BlockKind::BlueShulkerBox => "Blue Shulker Box", + crate::BlockKind::BlueStainedGlass => "Blue Stained Glass", + crate::BlockKind::BlueStainedGlassPane => "Blue Stained Glass Pane", + crate::BlockKind::BlueTerracotta => "Blue Terracotta", + crate::BlockKind::BlueWallBanner => "Blue wall banner", + crate::BlockKind::BlueWool => "Blue Wool", + crate::BlockKind::BoneBlock => "Bone Block", + crate::BlockKind::Bookshelf => "Bookshelf", + crate::BlockKind::BrainCoral => "Brain Coral", + crate::BlockKind::BrainCoralBlock => "Brain Coral Block", + crate::BlockKind::BrainCoralFan => "Brain Coral Fan", + crate::BlockKind::BrainCoralWallFan => "Brain Coral Wall Fan", + crate::BlockKind::BrewingStand => "Brewing Stand", + crate::BlockKind::BrickSlab => "Brick Slab", + crate::BlockKind::BrickStairs => "Brick Stairs", + crate::BlockKind::Bricks => "Bricks", + crate::BlockKind::BrownBanner => "Brown Banner", + crate::BlockKind::BrownBed => "Brown Bed", + crate::BlockKind::BrownCarpet => "Brown Carpet", + crate::BlockKind::BrownConcrete => "Brown Concrete", + crate::BlockKind::BrownConcretePowder => "Brown Concrete Powder", + crate::BlockKind::BrownGlazedTerracotta => "Brown Glazed Terracotta", + crate::BlockKind::BrownMushroom => "Brown Mushroom", + crate::BlockKind::BrownMushroomBlock => "Brown Mushroom Block", + crate::BlockKind::BrownShulkerBox => "Brown Shulker Box", + crate::BlockKind::BrownStainedGlass => "Brown Stained Glass", + crate::BlockKind::BrownStainedGlassPane => "Brown Stained Glass Pane", + crate::BlockKind::BrownTerracotta => "Brown Terracotta", + crate::BlockKind::BrownWallBanner => "Brown wall banner", + crate::BlockKind::BrownWool => "Brown Wool", + crate::BlockKind::BubbleColumn => "Bubble Column", + crate::BlockKind::BubbleCoral => "Bubble Coral", + crate::BlockKind::BubbleCoralBlock => "Bubble Coral Block", + crate::BlockKind::BubbleCoralFan => "Bubble Coral Fan", + crate::BlockKind::BubbleCoralWallFan => "Bubble Coral Wall Fan", + crate::BlockKind::Cactus => "Cactus", + crate::BlockKind::Cake => "Cake", + crate::BlockKind::Carrots => "Carrots", + crate::BlockKind::CarvedPumpkin => "Carved Pumpkin", + crate::BlockKind::Cauldron => "Cauldron", + crate::BlockKind::CaveAir => "Cave Air", + crate::BlockKind::ChainCommandBlock => "Chain Command Block", + crate::BlockKind::Chest => "Chest", + crate::BlockKind::ChippedAnvil => "Chipped Anvil", + crate::BlockKind::ChiseledQuartzBlock => "Chiseled Quartz Block", + crate::BlockKind::ChiseledRedSandstone => "Chiseled Red Sandstone", + crate::BlockKind::ChiseledSandstone => "Chiseled Sandstone", + crate::BlockKind::ChiseledStoneBricks => "Chiseled Stone Bricks", + crate::BlockKind::ChorusFlower => "Chorus Flower", + crate::BlockKind::ChorusPlant => "Chorus Plant", + crate::BlockKind::Clay => "Clay", + crate::BlockKind::CoalBlock => "Block of Coal", + crate::BlockKind::CoalOre => "Coal Ore", + crate::BlockKind::CoarseDirt => "Coarse Dirt", + crate::BlockKind::Cobblestone => "Cobblestone", + crate::BlockKind::CobblestoneSlab => "Cobblestone Slab", + crate::BlockKind::CobblestoneStairs => "Cobblestone Stairs", + crate::BlockKind::CobblestoneWall => "Cobblestone Wall", + crate::BlockKind::Cobweb => "Cobweb", + crate::BlockKind::Cocoa => "Cocoa", + crate::BlockKind::CommandBlock => "Command Block", + crate::BlockKind::Comparator => "Redstone Comparator", + crate::BlockKind::Conduit => "Conduit", + crate::BlockKind::CrackedStoneBricks => "Cracked Stone Bricks", + crate::BlockKind::CraftingTable => "Crafting Table", + crate::BlockKind::CreeperHead => "Creeper Head", + crate::BlockKind::CreeperWallHead => "Creeper Wall Head", + crate::BlockKind::CutRedSandstone => "Cut Red Sandstone", + crate::BlockKind::CutSandstone => "Cut Sandstone", + crate::BlockKind::CyanBanner => "Cyan Banner", + crate::BlockKind::CyanBed => "Cyan Bed", + crate::BlockKind::CyanCarpet => "Cyan Carpet", + crate::BlockKind::CyanConcrete => "Cyan Concrete", + crate::BlockKind::CyanConcretePowder => "Cyan Concrete Powder", + crate::BlockKind::CyanGlazedTerracotta => "Cyan Glazed Terracotta", + crate::BlockKind::CyanShulkerBox => "Cyan Shulker Box", + crate::BlockKind::CyanStainedGlass => "Cyan Stained Glass", + crate::BlockKind::CyanStainedGlassPane => "Cyan Stained Glass Pane", + crate::BlockKind::CyanTerracotta => "Cyan Terracotta", + crate::BlockKind::CyanWallBanner => "Cyan wall banner", + crate::BlockKind::CyanWool => "Cyan Wool", + crate::BlockKind::DamagedAnvil => "Damaged Anvil", + crate::BlockKind::Dandelion => "Dandelion", + crate::BlockKind::DarkOakButton => "Dark Oak Button", + crate::BlockKind::DarkOakDoor => "Dark Oak Door", + crate::BlockKind::DarkOakFence => "Dark Oak Fence", + crate::BlockKind::DarkOakFenceGate => "Dark Oak Fence Gate", + crate::BlockKind::DarkOakLeaves => "Dark Oak Leaves", + crate::BlockKind::DarkOakLog => "Dark Oak Log", + crate::BlockKind::DarkOakPlanks => "Dark Oak Planks", + crate::BlockKind::DarkOakPressurePlate => "Dark Oak Pressure Plate", + crate::BlockKind::DarkOakSapling => "Dark Oak Sapling", + crate::BlockKind::DarkOakSlab => "Dark Oak Slab", + crate::BlockKind::DarkOakStairs => "Dark Oak Stairs", + crate::BlockKind::DarkOakTrapdoor => "Dark Oak Trapdoor", + crate::BlockKind::DarkOakWood => "Dark Oak Wood", + crate::BlockKind::DarkPrismarine => "Dark Prismarine", + crate::BlockKind::DarkPrismarineSlab => "Dark Prismarine Slab", + crate::BlockKind::DarkPrismarineStairs => "Dark Prismarine Stairs", + crate::BlockKind::DaylightDetector => "Daylight Detector", + crate::BlockKind::DeadBrainCoral => "Dead Brain Coral", + crate::BlockKind::DeadBrainCoralBlock => "Dead Brain Coral Block", + crate::BlockKind::DeadBrainCoralFan => "Dead Brain Coral Fan", + crate::BlockKind::DeadBrainCoralWallFan => "Dead Brain Coral Wall Fan", + crate::BlockKind::DeadBubbleCoral => "Dead Bubble Coral", + crate::BlockKind::DeadBubbleCoralBlock => "Dead Bubble Coral Block", + crate::BlockKind::DeadBubbleCoralFan => "Dead Bubble Coral Fan", + crate::BlockKind::DeadBubbleCoralWallFan => "Dead Bubble Coral Wall Fan", + crate::BlockKind::DeadBush => "Dead Bush", + crate::BlockKind::DeadFireCoral => "Dead Fire Coral", + crate::BlockKind::DeadFireCoralBlock => "Dead Fire Coral Block", + crate::BlockKind::DeadFireCoralFan => "Dead Fire Coral Fan", + crate::BlockKind::DeadFireCoralWallFan => "Dead Fire Coral Wall Fan", + crate::BlockKind::DeadHornCoral => "Dead Horn Coral", + crate::BlockKind::DeadHornCoralBlock => "Dead Horn Coral Block", + crate::BlockKind::DeadHornCoralFan => "Dead Horn Coral Fan", + crate::BlockKind::DeadHornCoralWallFan => "Dead Horn Coral Wall Fan", + crate::BlockKind::DeadTubeCoral => "Dead Tube Coral", + crate::BlockKind::DeadTubeCoralBlock => "Dead Tube Coral Block", + crate::BlockKind::DeadTubeCoralFan => "Dead Tube Coral Fan", + crate::BlockKind::DeadTubeCoralWallFan => "Dead Tube Coral Wall Fan", + crate::BlockKind::DetectorRail => "Detector Rail", + crate::BlockKind::DiamondBlock => "Block of Diamond", + crate::BlockKind::DiamondOre => "Diamond Ore", + crate::BlockKind::Diorite => "Diorite", + crate::BlockKind::Dirt => "Dirt", + crate::BlockKind::Dispenser => "Dispenser", + crate::BlockKind::DragonEgg => "Dragon Egg", + crate::BlockKind::DragonHead => "Dragon Head", + crate::BlockKind::DragonWallHead => "Dragon Wall Head", + crate::BlockKind::DriedKelpBlock => "Dried Kelp Block", + crate::BlockKind::Dropper => "Dropper", + crate::BlockKind::EmeraldBlock => "Block of Emerald", + crate::BlockKind::EmeraldOre => "Emerald Ore", + crate::BlockKind::EnchantingTable => "Enchanting Table", + crate::BlockKind::EndGateway => "End Gateway", + crate::BlockKind::EndPortal => "End Portal", + crate::BlockKind::EndPortalFrame => "End Portal Frame", + crate::BlockKind::EndRod => "End Rod", + crate::BlockKind::EndStone => "End Stone", + crate::BlockKind::EndStoneBricks => "End Stone Bricks", + crate::BlockKind::EnderChest => "Ender Chest", + crate::BlockKind::Farmland => "Farmland", + crate::BlockKind::Fern => "Fern", + crate::BlockKind::Fire => "Fire", + crate::BlockKind::FireCoral => "Fire Coral", + crate::BlockKind::FireCoralBlock => "Fire Coral Block", + crate::BlockKind::FireCoralFan => "Fire Coral Fan", + crate::BlockKind::FireCoralWallFan => "Fire Coral Wall Fan", + crate::BlockKind::FlowerPot => "Flower Pot", + crate::BlockKind::FrostedIce => "Frosted Ice", + crate::BlockKind::Furnace => "Furnace", + crate::BlockKind::Glass => "Glass", + crate::BlockKind::GlassPane => "Glass Pane", + crate::BlockKind::Glowstone => "Glowstone", + crate::BlockKind::GoldBlock => "Block of Gold", + crate::BlockKind::GoldOre => "Gold Ore", + crate::BlockKind::Granite => "Granite", + crate::BlockKind::Grass => "Grass", + crate::BlockKind::GrassBlock => "Grass Block", + crate::BlockKind::GrassPath => "Grass Path", + crate::BlockKind::Gravel => "Gravel", + crate::BlockKind::GrayBanner => "Gray Banner", + crate::BlockKind::GrayBed => "Gray Bed", + crate::BlockKind::GrayCarpet => "Gray Carpet", + crate::BlockKind::GrayConcrete => "Gray Concrete", + crate::BlockKind::GrayConcretePowder => "Gray Concrete Powder", + crate::BlockKind::GrayGlazedTerracotta => "Gray Glazed Terracotta", + crate::BlockKind::GrayShulkerBox => "Gray Shulker Box", + crate::BlockKind::GrayStainedGlass => "Gray Stained Glass", + crate::BlockKind::GrayStainedGlassPane => "Gray Stained Glass Pane", + crate::BlockKind::GrayTerracotta => "Gray Terracotta", + crate::BlockKind::GrayWallBanner => "Gray wall banner", + crate::BlockKind::GrayWool => "Gray Wool", + crate::BlockKind::GreenBanner => "Green Banner", + crate::BlockKind::GreenBed => "Green Bed", + crate::BlockKind::GreenCarpet => "Green Carpet", + crate::BlockKind::GreenConcrete => "Green Concrete", + crate::BlockKind::GreenConcretePowder => "Green Concrete Powder", + crate::BlockKind::GreenGlazedTerracotta => "Green Glazed Terracotta", + crate::BlockKind::GreenShulkerBox => "Green Shulker Box", + crate::BlockKind::GreenStainedGlass => "Green Stained Glass", + crate::BlockKind::GreenStainedGlassPane => "Green Stained Glass Pane", + crate::BlockKind::GreenTerracotta => "Green Terracotta", + crate::BlockKind::GreenWallBanner => "Green wall banner", + crate::BlockKind::GreenWool => "Green Wool", + crate::BlockKind::HayBlock => "Hay Bale", + crate::BlockKind::HeavyWeightedPressurePlate => "Heavy Weighted Pressure Plate", + crate::BlockKind::Hopper => "Hopper", + crate::BlockKind::HornCoral => "Horn Coral", + crate::BlockKind::HornCoralBlock => "Horn Coral Block", + crate::BlockKind::HornCoralFan => "Horn Coral Fan", + crate::BlockKind::HornCoralWallFan => "Horn Coral Wall Fan", + crate::BlockKind::Ice => "Ice", + crate::BlockKind::InfestedChiseledStoneBricks => "Infested Chiseled Stone Bricks", + crate::BlockKind::InfestedCobblestone => "Infested Cobblestone", + crate::BlockKind::InfestedCrackedStoneBricks => "Infested Cracked Stone Bricks", + crate::BlockKind::InfestedMossyStoneBricks => "Infested Mossy Stone Bricks", + crate::BlockKind::InfestedStone => "Infested Stone", + crate::BlockKind::InfestedStoneBricks => "Infested Stone Bricks", + crate::BlockKind::IronBars => "Iron Bars", + crate::BlockKind::IronBlock => "Block of Iron", + crate::BlockKind::IronDoor => "Iron Door", + crate::BlockKind::IronOre => "Iron Ore", + crate::BlockKind::IronTrapdoor => "Iron Trapdoor", + crate::BlockKind::JackOLantern => "Jack o'Lantern", + crate::BlockKind::Jukebox => "Jukebox", + crate::BlockKind::JungleButton => "Jungle Button", + crate::BlockKind::JungleDoor => "Jungle Door", + crate::BlockKind::JungleFence => "Jungle Fence", + crate::BlockKind::JungleFenceGate => "Jungle Fence Gate", + crate::BlockKind::JungleLeaves => "Jungle Leaves", + crate::BlockKind::JungleLog => "Jungle Log", + crate::BlockKind::JunglePlanks => "Jungle Planks", + crate::BlockKind::JunglePressurePlate => "Jungle Pressure Plate", + crate::BlockKind::JungleSapling => "Jungle Sapling", + crate::BlockKind::JungleSlab => "Jungle Slab", + crate::BlockKind::JungleStairs => "Jungle Stairs", + crate::BlockKind::JungleTrapdoor => "Jungle Trapdoor", + crate::BlockKind::JungleWood => "Jungle Wood", + crate::BlockKind::Kelp => "Kelp", + crate::BlockKind::KelpPlant => "Kelp Plant", + crate::BlockKind::Ladder => "Ladder", + crate::BlockKind::LapisBlock => "Lapis Lazuli Block", + crate::BlockKind::LapisOre => "Lapis Lazuli Ore", + crate::BlockKind::LargeFern => "Large Fern", + crate::BlockKind::Lava => "Lava", + crate::BlockKind::Lever => "Lever", + crate::BlockKind::LightBlueBanner => "Light Blue Banner", + crate::BlockKind::LightBlueBed => "Light Blue Bed", + crate::BlockKind::LightBlueCarpet => "Light Blue Carpet", + crate::BlockKind::LightBlueConcrete => "Light Blue Concrete", + crate::BlockKind::LightBlueConcretePowder => "Light Blue Concrete Powder", + crate::BlockKind::LightBlueGlazedTerracotta => "Light Blue Glazed Terracotta", + crate::BlockKind::LightBlueShulkerBox => "Light Blue Shulker Box", + crate::BlockKind::LightBlueStainedGlass => "Light Blue Stained Glass", + crate::BlockKind::LightBlueStainedGlassPane => "Light Blue Stained Glass Pane", + crate::BlockKind::LightBlueTerracotta => "Light Blue Terracotta", + crate::BlockKind::LightBlueWallBanner => "Light blue wall banner", + crate::BlockKind::LightBlueWool => "Light Blue Wool", + crate::BlockKind::LightGrayBanner => "Light Gray Banner", + crate::BlockKind::LightGrayBed => "Light Gray Bed", + crate::BlockKind::LightGrayCarpet => "Light Gray Carpet", + crate::BlockKind::LightGrayConcrete => "Light Gray Concrete", + crate::BlockKind::LightGrayConcretePowder => "Light Gray Concrete Powder", + crate::BlockKind::LightGrayGlazedTerracotta => "Light Gray Glazed Terracotta", + crate::BlockKind::LightGrayShulkerBox => "Light Gray Shulker Box", + crate::BlockKind::LightGrayStainedGlass => "Light Gray Stained Glass", + crate::BlockKind::LightGrayStainedGlassPane => "Light Gray Stained Glass Pane", + crate::BlockKind::LightGrayTerracotta => "Light Gray Terracotta", + crate::BlockKind::LightGrayWallBanner => "Light gray wall banner", + crate::BlockKind::LightGrayWool => "Light Gray Wool", + crate::BlockKind::LightWeightedPressurePlate => "Light Weighted Pressure Plate", + crate::BlockKind::Lilac => "Lilac", + crate::BlockKind::LilyPad => "Lily Pad", + crate::BlockKind::LimeBanner => "Lime Banner", + crate::BlockKind::LimeBed => "Lime Bed", + crate::BlockKind::LimeCarpet => "Lime Carpet", + crate::BlockKind::LimeConcrete => "Lime Concrete", + crate::BlockKind::LimeConcretePowder => "Lime Concrete Powder", + crate::BlockKind::LimeGlazedTerracotta => "Lime Glazed Terracotta", + crate::BlockKind::LimeShulkerBox => "Lime Shulker Box", + crate::BlockKind::LimeStainedGlass => "Lime Stained Glass", + crate::BlockKind::LimeStainedGlassPane => "Lime Stained Glass Pane", + crate::BlockKind::LimeTerracotta => "Lime Terracotta", + crate::BlockKind::LimeWallBanner => "Lime wall banner", + crate::BlockKind::LimeWool => "Lime Wool", + crate::BlockKind::MagentaBanner => "Magenta Banner", + crate::BlockKind::MagentaBed => "Magenta Bed", + crate::BlockKind::MagentaCarpet => "Magenta Carpet", + crate::BlockKind::MagentaConcrete => "Magenta Concrete", + crate::BlockKind::MagentaConcretePowder => "Magenta Concrete Powder", + crate::BlockKind::MagentaGlazedTerracotta => "Magenta Glazed Terracotta", + crate::BlockKind::MagentaShulkerBox => "Magenta Shulker Box", + crate::BlockKind::MagentaStainedGlass => "Magenta Stained Glass", + crate::BlockKind::MagentaStainedGlassPane => "Magenta Stained Glass Pane", + crate::BlockKind::MagentaTerracotta => "Magenta Terracotta", + crate::BlockKind::MagentaWallBanner => "Magenta wall banner", + crate::BlockKind::MagentaWool => "Magenta Wool", + crate::BlockKind::MagmaBlock => "Magma Block", + crate::BlockKind::Melon => "Melon", + crate::BlockKind::MelonStem => "Melon Stem", + crate::BlockKind::MossyCobblestone => "Mossy Cobblestone", + crate::BlockKind::MossyCobblestoneWall => "Mossy Cobblestone Wall", + crate::BlockKind::MossyStoneBricks => "Mossy Stone Bricks", + crate::BlockKind::MovingPiston => "Moving Piston", + crate::BlockKind::MushroomStem => "Mushroom Stem", + crate::BlockKind::Mycelium => "Mycelium", + crate::BlockKind::NetherBrickFence => "Nether Brick Fence", + crate::BlockKind::NetherBrickSlab => "Nether Brick Slab", + crate::BlockKind::NetherBrickStairs => "Nether Brick Stairs", + crate::BlockKind::NetherBricks => "Nether Bricks", + crate::BlockKind::NetherPortal => "Nether Portal", + crate::BlockKind::NetherQuartzOre => "Nether Quartz Ore", + crate::BlockKind::NetherWart => "Nether Wart", + crate::BlockKind::NetherWartBlock => "Nether Wart Block", + crate::BlockKind::Netherrack => "Netherrack", + crate::BlockKind::NoteBlock => "Note Block", + crate::BlockKind::OakButton => "Oak Button", + crate::BlockKind::OakDoor => "Oak Door", + crate::BlockKind::OakFence => "Oak Fence", + crate::BlockKind::OakFenceGate => "Oak Fence Gate", + crate::BlockKind::OakLeaves => "Oak Leaves", + crate::BlockKind::OakLog => "Oak Log", + crate::BlockKind::OakPlanks => "Oak Planks", + crate::BlockKind::OakPressurePlate => "Oak Pressure Plate", + crate::BlockKind::OakSapling => "Oak Sapling", + crate::BlockKind::OakSlab => "Oak Slab", + crate::BlockKind::OakStairs => "Oak Stairs", + crate::BlockKind::OakTrapdoor => "Oak Trapdoor", + crate::BlockKind::OakWood => "Oak Wood", + crate::BlockKind::Observer => "Observer", + crate::BlockKind::Obsidian => "Obsidian", + crate::BlockKind::OrangeBanner => "Orange Banner", + crate::BlockKind::OrangeBed => "Orange Bed", + crate::BlockKind::OrangeCarpet => "Orange Carpet", + crate::BlockKind::OrangeConcrete => "Orange Concrete", + crate::BlockKind::OrangeConcretePowder => "Orange Concrete Powder", + crate::BlockKind::OrangeGlazedTerracotta => "Orange Glazed Terracotta", + crate::BlockKind::OrangeShulkerBox => "Orange Shulker Box", + crate::BlockKind::OrangeStainedGlass => "Orange Stained Glass", + crate::BlockKind::OrangeStainedGlassPane => "Orange Stained Glass Pane", + crate::BlockKind::OrangeTerracotta => "Orange Terracotta", + crate::BlockKind::OrangeTulip => "Orange Tulip", + crate::BlockKind::OrangeWallBanner => "Orange wall banner", + crate::BlockKind::OrangeWool => "Orange Wool", + crate::BlockKind::OxeyeDaisy => "Oxeye Daisy", + crate::BlockKind::PackedIce => "Packed Ice", + crate::BlockKind::Peony => "Peony", + crate::BlockKind::PetrifiedOakSlab => "Petrified Oak Slab", + crate::BlockKind::PinkBanner => "Pink Banner", + crate::BlockKind::PinkBed => "Pink Bed", + crate::BlockKind::PinkCarpet => "Pink Carpet", + crate::BlockKind::PinkConcrete => "Pink Concrete", + crate::BlockKind::PinkConcretePowder => "Pink Concrete Powder", + crate::BlockKind::PinkGlazedTerracotta => "Pink Glazed Terracotta", + crate::BlockKind::PinkShulkerBox => "Pink Shulker Box", + crate::BlockKind::PinkStainedGlass => "Pink Stained Glass", + crate::BlockKind::PinkStainedGlassPane => "Pink Stained Glass Pane", + crate::BlockKind::PinkTerracotta => "Pink Terracotta", + crate::BlockKind::PinkTulip => "Pink Tulip", + crate::BlockKind::PinkWallBanner => "Pink wall banner", + crate::BlockKind::PinkWool => "Pink Wool", + crate::BlockKind::Piston => "Piston", + crate::BlockKind::PistonHead => "Piston Head", + crate::BlockKind::PlayerHead => "Player Head", + crate::BlockKind::PlayerWallHead => "Player Wall Head", + crate::BlockKind::Podzol => "Podzol", + crate::BlockKind::PolishedAndesite => "Polished Andesite", + crate::BlockKind::PolishedDiorite => "Polished Diorite", + crate::BlockKind::PolishedGranite => "Polished Granite", + crate::BlockKind::Poppy => "Poppy", + crate::BlockKind::Potatoes => "Potatoes", + crate::BlockKind::PottedAcaciaSapling => "Potted Acacia Sapling", + crate::BlockKind::PottedAllium => "Potted Allium", + crate::BlockKind::PottedAzureBluet => "Potted Azure Bluet", + crate::BlockKind::PottedBirchSapling => "Potted Birch Sapling", + crate::BlockKind::PottedBlueOrchid => "Potted Blue Orchid", + crate::BlockKind::PottedBrownMushroom => "Potted Brown Mushroom", + crate::BlockKind::PottedCactus => "Potted Cactus", + crate::BlockKind::PottedDandelion => "Potted Dandelion", + crate::BlockKind::PottedDarkOakSapling => "Potted Dark Oak Sapling", + crate::BlockKind::PottedDeadBush => "Potted Dead Bush", + crate::BlockKind::PottedFern => "Potted Fern", + crate::BlockKind::PottedJungleSapling => "Potted Jungle Sapling", + crate::BlockKind::PottedOakSapling => "Potted Oak Sapling", + crate::BlockKind::PottedOrangeTulip => "Potted Orange Tulip", + crate::BlockKind::PottedOxeyeDaisy => "Potted Oxeye Daisy", + crate::BlockKind::PottedPinkTulip => "Potted Pink Tulip", + crate::BlockKind::PottedPoppy => "Potted Poppy", + crate::BlockKind::PottedRedMushroom => "Potted Red Mushroom", + crate::BlockKind::PottedRedTulip => "Potted Red Tulip", + crate::BlockKind::PottedSpruceSapling => "Potted Spruce Sapling", + crate::BlockKind::PottedWhiteTulip => "Potted White Tulip", + crate::BlockKind::PoweredRail => "Powered Rail", + crate::BlockKind::Prismarine => "Prismarine", + crate::BlockKind::PrismarineBrickSlab => "Prismarine Brick Slab", + crate::BlockKind::PrismarineBrickStairs => "Prismarine Brick Stairs", + crate::BlockKind::PrismarineBricks => "Prismarine Bricks", + crate::BlockKind::PrismarineSlab => "Prismarine Slab", + crate::BlockKind::PrismarineStairs => "Prismarine Stairs", + crate::BlockKind::Pumpkin => "Pumpkin", + crate::BlockKind::PumpkinStem => "Pumpkin Stem", + crate::BlockKind::PurpleBanner => "Purple Banner", + crate::BlockKind::PurpleBed => "Purple Bed", + crate::BlockKind::PurpleCarpet => "Purple Carpet", + crate::BlockKind::PurpleConcrete => "Purple Concrete", + crate::BlockKind::PurpleConcretePowder => "Purple Concrete Powder", + crate::BlockKind::PurpleGlazedTerracotta => "Purple Glazed Terracotta", + crate::BlockKind::PurpleShulkerBox => "Purple Shulker Box", + crate::BlockKind::PurpleStainedGlass => "Purple Stained Glass", + crate::BlockKind::PurpleStainedGlassPane => "Purple Stained Glass Pane", + crate::BlockKind::PurpleTerracotta => "Purple Terracotta", + crate::BlockKind::PurpleWallBanner => "Purple wall banner", + crate::BlockKind::PurpleWool => "Purple Wool", + crate::BlockKind::PurpurBlock => "Purpur Block", + crate::BlockKind::PurpurPillar => "Purpur Pillar", + crate::BlockKind::PurpurSlab => "Purpur Slab", + crate::BlockKind::PurpurStairs => "Purpur Stairs", + crate::BlockKind::QuartzBlock => "Block of Quartz", + crate::BlockKind::QuartzPillar => "Quartz Pillar", + crate::BlockKind::QuartzSlab => "Quartz Slab", + crate::BlockKind::QuartzStairs => "Quartz Stairs", + crate::BlockKind::Rail => "Rail", + crate::BlockKind::RedBanner => "Red Banner", + crate::BlockKind::RedBed => "Red Bed", + crate::BlockKind::RedCarpet => "Red Carpet", + crate::BlockKind::RedConcrete => "Red Concrete", + crate::BlockKind::RedConcretePowder => "Red Concrete Powder", + crate::BlockKind::RedGlazedTerracotta => "Red Glazed Terracotta", + crate::BlockKind::RedMushroom => "Red Mushroom", + crate::BlockKind::RedMushroomBlock => "Red Mushroom Block", + crate::BlockKind::RedNetherBricks => "Red Nether Bricks", + crate::BlockKind::RedSand => "Red Sand", + crate::BlockKind::RedSandstone => "Red Sandstone", + crate::BlockKind::RedSandstoneSlab => "Red Sandstone Slab", + crate::BlockKind::RedSandstoneStairs => "Red Sandstone Stairs", + crate::BlockKind::RedShulkerBox => "Red Shulker Box", + crate::BlockKind::RedStainedGlass => "Red Stained Glass", + crate::BlockKind::RedStainedGlassPane => "Red Stained Glass Pane", + crate::BlockKind::RedTerracotta => "Red Terracotta", + crate::BlockKind::RedTulip => "Red Tulip", + crate::BlockKind::RedWallBanner => "Red wall banner", + crate::BlockKind::RedWool => "Red Wool", + crate::BlockKind::RedstoneBlock => "Block of Redstone", + crate::BlockKind::RedstoneLamp => "Redstone Lamp", + crate::BlockKind::RedstoneOre => "Redstone Ore", + crate::BlockKind::RedstoneTorch => "Redstone Torch", + crate::BlockKind::RedstoneWallTorch => "Redstone Wall Torch", + crate::BlockKind::RedstoneWire => "Redstone Dust", + crate::BlockKind::Repeater => "Redstone Repeater", + crate::BlockKind::RepeatingCommandBlock => "Repeating Command Block", + crate::BlockKind::RoseBush => "Rose Bush", + crate::BlockKind::Sand => "Sand", + crate::BlockKind::Sandstone => "Sandstone", + crate::BlockKind::SandstoneSlab => "Sandstone Slab", + crate::BlockKind::SandstoneStairs => "Sandstone Stairs", + crate::BlockKind::SeaLantern => "Sea Lantern", + crate::BlockKind::SeaPickle => "Sea Pickle", + crate::BlockKind::Seagrass => "Seagrass", + crate::BlockKind::ShulkerBox => "Shulker Box", + crate::BlockKind::Sign => "Sign", + crate::BlockKind::SkeletonSkull => "Skeleton Skull", + crate::BlockKind::SkeletonWallSkull => "Skeleton Wall Skull", + crate::BlockKind::SlimeBlock => "Slime Block", + crate::BlockKind::SmoothQuartz => "Smooth Quartz", + crate::BlockKind::SmoothRedSandstone => "Smooth Red Sandstone", + crate::BlockKind::SmoothSandstone => "Smooth Sandstone", + crate::BlockKind::SmoothStone => "Smooth Stone", + crate::BlockKind::Snow => "Snow", + crate::BlockKind::SnowBlock => "Snow Block", + crate::BlockKind::SoulSand => "Soul Sand", + crate::BlockKind::Spawner => "Spawner", + crate::BlockKind::Sponge => "Sponge", + crate::BlockKind::SpruceButton => "Spruce Button", + crate::BlockKind::SpruceDoor => "Spruce Door", + crate::BlockKind::SpruceFence => "Spruce Fence", + crate::BlockKind::SpruceFenceGate => "Spruce Fence Gate", + crate::BlockKind::SpruceLeaves => "Spruce Leaves", + crate::BlockKind::SpruceLog => "Spruce Log", + crate::BlockKind::SprucePlanks => "Spruce Planks", + crate::BlockKind::SprucePressurePlate => "Spruce Pressure Plate", + crate::BlockKind::SpruceSapling => "Spruce Sapling", + crate::BlockKind::SpruceSlab => "Spruce Slab", + crate::BlockKind::SpruceStairs => "Spruce Stairs", + crate::BlockKind::SpruceTrapdoor => "Spruce Trapdoor", + crate::BlockKind::SpruceWood => "Spruce Wood", + crate::BlockKind::StickyPiston => "Sticky Piston", + crate::BlockKind::Stone => "Stone", + crate::BlockKind::StoneBrickSlab => "Stone Brick Slab", + crate::BlockKind::StoneBrickStairs => "Stone Brick Stairs", + crate::BlockKind::StoneBricks => "Stone Bricks", + crate::BlockKind::StoneButton => "Stone Button", + crate::BlockKind::StonePressurePlate => "Stone Pressure Plate", + crate::BlockKind::StoneSlab => "Stone Slab", + crate::BlockKind::StrippedAcaciaLog => "Stripped Acacia Log", + crate::BlockKind::StrippedAcaciaWood => "Stripped Acacia Wood", + crate::BlockKind::StrippedBirchLog => "Stripped Birch Log", + crate::BlockKind::StrippedBirchWood => "Stripped Birch Wood", + crate::BlockKind::StrippedDarkOakLog => "Stripped Dark Oak Log", + crate::BlockKind::StrippedDarkOakWood => "Stripped Dark Oak Wood", + crate::BlockKind::StrippedJungleLog => "Stripped Jungle Log", + crate::BlockKind::StrippedJungleWood => "Stripped Jungle Wood", + crate::BlockKind::StrippedOakLog => "Stripped Oak Log", + crate::BlockKind::StrippedOakWood => "Stripped Oak Wood", + crate::BlockKind::StrippedSpruceLog => "Stripped Spruce Log", + crate::BlockKind::StrippedSpruceWood => "Stripped Spruce Wood", + crate::BlockKind::StructureBlock => "Structure Block", + crate::BlockKind::StructureVoid => "Structure Void", + crate::BlockKind::SugarCane => "Sugar Cane", + crate::BlockKind::Sunflower => "Sunflower", + crate::BlockKind::TallGrass => "Tall Grass", + crate::BlockKind::TallSeagrass => "Tall Seagrass", + crate::BlockKind::Terracotta => "Terracotta", + crate::BlockKind::Tnt => "TNT", + crate::BlockKind::Torch => "Torch", + crate::BlockKind::TrappedChest => "Trapped Chest", + crate::BlockKind::Tripwire => "Tripwire", + crate::BlockKind::TripwireHook => "Tripwire Hook", + crate::BlockKind::TubeCoral => "Tube Coral", + crate::BlockKind::TubeCoralBlock => "Tube Coral Block", + crate::BlockKind::TubeCoralFan => "Tube Coral Fan", + crate::BlockKind::TubeCoralWallFan => "Tube Coral Wall Fan", + crate::BlockKind::TurtleEgg => "Turtle Egg", + crate::BlockKind::Vine => "Vines", + crate::BlockKind::VoidAir => "Void Air", + crate::BlockKind::WallSign => "Wall Sign", + crate::BlockKind::WallTorch => "Wall Torch", + crate::BlockKind::Water => "Water", + crate::BlockKind::WetSponge => "Wet Sponge", + crate::BlockKind::Wheat => "Wheat Crops", + crate::BlockKind::WhiteBanner => "White Banner", + crate::BlockKind::WhiteBed => "White Bed", + crate::BlockKind::WhiteCarpet => "White Carpet", + crate::BlockKind::WhiteConcrete => "White Concrete", + crate::BlockKind::WhiteConcretePowder => "White Concrete Powder", + crate::BlockKind::WhiteGlazedTerracotta => "White Glazed Terracotta", + crate::BlockKind::WhiteShulkerBox => "White Shulker Box", + crate::BlockKind::WhiteStainedGlass => "White Stained Glass", + crate::BlockKind::WhiteStainedGlassPane => "White Stained Glass Pane", + crate::BlockKind::WhiteTerracotta => "White Terracotta", + crate::BlockKind::WhiteTulip => "White Tulip", + crate::BlockKind::WhiteWallBanner => "White wall banner", + crate::BlockKind::WhiteWool => "White Wool", + crate::BlockKind::WitherSkeletonSkull => "Wither Skeleton Skull", + crate::BlockKind::WitherSkeletonWallSkull => "Wither Skeleton Wall Skull", + crate::BlockKind::YellowBanner => "Yellow Banner", + crate::BlockKind::YellowBed => "Yellow Bed", + crate::BlockKind::YellowCarpet => "Yellow Carpet", + crate::BlockKind::YellowConcrete => "Yellow Concrete", + crate::BlockKind::YellowConcretePowder => "Yellow Concrete Powder", + crate::BlockKind::YellowGlazedTerracotta => "Yellow Glazed Terracotta", + crate::BlockKind::YellowShulkerBox => "Yellow Shulker Box", + crate::BlockKind::YellowStainedGlass => "Yellow Stained Glass", + crate::BlockKind::YellowStainedGlassPane => "Yellow Stained Glass Pane", + crate::BlockKind::YellowTerracotta => "Yellow Terracotta", + crate::BlockKind::YellowWallBanner => "Yellow wall banner", + crate::BlockKind::YellowWool => "Yellow Wool", + crate::BlockKind::ZombieHead => "Zombie Head", + crate::BlockKind::ZombieWallHead => "Zombie Wall Head", + } + } + pub fn from_display_name(prop: &str) -> Option<BlockKind> { + match prop { + "Acacia Button" => Some(crate::BlockKind::AcaciaButton), + "Acacia Door" => Some(crate::BlockKind::AcaciaDoor), + "Acacia Fence" => Some(crate::BlockKind::AcaciaFence), + "Acacia Fence Gate" => Some(crate::BlockKind::AcaciaFenceGate), + "Acacia Leaves" => Some(crate::BlockKind::AcaciaLeaves), + "Acacia Log" => Some(crate::BlockKind::AcaciaLog), + "Acacia Planks" => Some(crate::BlockKind::AcaciaPlanks), + "Acacia Pressure Plate" => Some(crate::BlockKind::AcaciaPressurePlate), + "Acacia Sapling" => Some(crate::BlockKind::AcaciaSapling), + "Acacia Slab" => Some(crate::BlockKind::AcaciaSlab), + "Acacia Stairs" => Some(crate::BlockKind::AcaciaStairs), + "Acacia Trapdoor" => Some(crate::BlockKind::AcaciaTrapdoor), + "Acacia Wood" => Some(crate::BlockKind::AcaciaWood), + "Activator Rail" => Some(crate::BlockKind::ActivatorRail), + "Air" => Some(crate::BlockKind::Air), + "Allium" => Some(crate::BlockKind::Allium), + "Andesite" => Some(crate::BlockKind::Andesite), + "Anvil" => Some(crate::BlockKind::Anvil), + "Attached Melon Stem" => Some(crate::BlockKind::AttachedMelonStem), + "Attached Pumpkin Stem" => Some(crate::BlockKind::AttachedPumpkinStem), + "Azure Bluet" => Some(crate::BlockKind::AzureBluet), + "Barrier" => Some(crate::BlockKind::Barrier), + "Beacon" => Some(crate::BlockKind::Beacon), + "Bedrock" => Some(crate::BlockKind::Bedrock), + "Beetroots" => Some(crate::BlockKind::Beetroots), + "Birch Button" => Some(crate::BlockKind::BirchButton), + "Birch Door" => Some(crate::BlockKind::BirchDoor), + "Birch Fence" => Some(crate::BlockKind::BirchFence), + "Birch Fence Gate" => Some(crate::BlockKind::BirchFenceGate), + "Birch Leaves" => Some(crate::BlockKind::BirchLeaves), + "Birch Log" => Some(crate::BlockKind::BirchLog), + "Birch Planks" => Some(crate::BlockKind::BirchPlanks), + "Birch Pressure Plate" => Some(crate::BlockKind::BirchPressurePlate), + "Birch Sapling" => Some(crate::BlockKind::BirchSapling), + "Birch Slab" => Some(crate::BlockKind::BirchSlab), + "Birch Stairs" => Some(crate::BlockKind::BirchStairs), + "Birch Trapdoor" => Some(crate::BlockKind::BirchTrapdoor), + "Birch Wood" => Some(crate::BlockKind::BirchWood), + "Black Banner" => Some(crate::BlockKind::BlackBanner), + "Black Bed" => Some(crate::BlockKind::BlackBed), + "Black Carpet" => Some(crate::BlockKind::BlackCarpet), + "Black Concrete" => Some(crate::BlockKind::BlackConcrete), + "Black Concrete Powder" => Some(crate::BlockKind::BlackConcretePowder), + "Black Glazed Terracotta" => Some(crate::BlockKind::BlackGlazedTerracotta), + "Black Shulker Box" => Some(crate::BlockKind::BlackShulkerBox), + "Black Stained Glass" => Some(crate::BlockKind::BlackStainedGlass), + "Black Stained Glass Pane" => Some(crate::BlockKind::BlackStainedGlassPane), + "Black Terracotta" => Some(crate::BlockKind::BlackTerracotta), + "Black wall banner" => Some(crate::BlockKind::BlackWallBanner), + "Black Wool" => Some(crate::BlockKind::BlackWool), + "Blue Banner" => Some(crate::BlockKind::BlueBanner), + "Blue Bed" => Some(crate::BlockKind::BlueBed), + "Blue Carpet" => Some(crate::BlockKind::BlueCarpet), + "Blue Concrete" => Some(crate::BlockKind::BlueConcrete), + "Blue Concrete Powder" => Some(crate::BlockKind::BlueConcretePowder), + "Blue Glazed Terracotta" => Some(crate::BlockKind::BlueGlazedTerracotta), + "Blue Ice" => Some(crate::BlockKind::BlueIce), + "Blue Orchid" => Some(crate::BlockKind::BlueOrchid), + "Blue Shulker Box" => Some(crate::BlockKind::BlueShulkerBox), + "Blue Stained Glass" => Some(crate::BlockKind::BlueStainedGlass), + "Blue Stained Glass Pane" => Some(crate::BlockKind::BlueStainedGlassPane), + "Blue Terracotta" => Some(crate::BlockKind::BlueTerracotta), + "Blue wall banner" => Some(crate::BlockKind::BlueWallBanner), + "Blue Wool" => Some(crate::BlockKind::BlueWool), + "Bone Block" => Some(crate::BlockKind::BoneBlock), + "Bookshelf" => Some(crate::BlockKind::Bookshelf), + "Brain Coral" => Some(crate::BlockKind::BrainCoral), + "Brain Coral Block" => Some(crate::BlockKind::BrainCoralBlock), + "Brain Coral Fan" => Some(crate::BlockKind::BrainCoralFan), + "Brain Coral Wall Fan" => Some(crate::BlockKind::BrainCoralWallFan), + "Brewing Stand" => Some(crate::BlockKind::BrewingStand), + "Brick Slab" => Some(crate::BlockKind::BrickSlab), + "Brick Stairs" => Some(crate::BlockKind::BrickStairs), + "Bricks" => Some(crate::BlockKind::Bricks), + "Brown Banner" => Some(crate::BlockKind::BrownBanner), + "Brown Bed" => Some(crate::BlockKind::BrownBed), + "Brown Carpet" => Some(crate::BlockKind::BrownCarpet), + "Brown Concrete" => Some(crate::BlockKind::BrownConcrete), + "Brown Concrete Powder" => Some(crate::BlockKind::BrownConcretePowder), + "Brown Glazed Terracotta" => Some(crate::BlockKind::BrownGlazedTerracotta), + "Brown Mushroom" => Some(crate::BlockKind::BrownMushroom), + "Brown Mushroom Block" => Some(crate::BlockKind::BrownMushroomBlock), + "Brown Shulker Box" => Some(crate::BlockKind::BrownShulkerBox), + "Brown Stained Glass" => Some(crate::BlockKind::BrownStainedGlass), + "Brown Stained Glass Pane" => Some(crate::BlockKind::BrownStainedGlassPane), + "Brown Terracotta" => Some(crate::BlockKind::BrownTerracotta), + "Brown wall banner" => Some(crate::BlockKind::BrownWallBanner), + "Brown Wool" => Some(crate::BlockKind::BrownWool), + "Bubble Column" => Some(crate::BlockKind::BubbleColumn), + "Bubble Coral" => Some(crate::BlockKind::BubbleCoral), + "Bubble Coral Block" => Some(crate::BlockKind::BubbleCoralBlock), + "Bubble Coral Fan" => Some(crate::BlockKind::BubbleCoralFan), + "Bubble Coral Wall Fan" => Some(crate::BlockKind::BubbleCoralWallFan), + "Cactus" => Some(crate::BlockKind::Cactus), + "Cake" => Some(crate::BlockKind::Cake), + "Carrots" => Some(crate::BlockKind::Carrots), + "Carved Pumpkin" => Some(crate::BlockKind::CarvedPumpkin), + "Cauldron" => Some(crate::BlockKind::Cauldron), + "Cave Air" => Some(crate::BlockKind::CaveAir), + "Chain Command Block" => Some(crate::BlockKind::ChainCommandBlock), + "Chest" => Some(crate::BlockKind::Chest), + "Chipped Anvil" => Some(crate::BlockKind::ChippedAnvil), + "Chiseled Quartz Block" => Some(crate::BlockKind::ChiseledQuartzBlock), + "Chiseled Red Sandstone" => Some(crate::BlockKind::ChiseledRedSandstone), + "Chiseled Sandstone" => Some(crate::BlockKind::ChiseledSandstone), + "Chiseled Stone Bricks" => Some(crate::BlockKind::ChiseledStoneBricks), + "Chorus Flower" => Some(crate::BlockKind::ChorusFlower), + "Chorus Plant" => Some(crate::BlockKind::ChorusPlant), + "Clay" => Some(crate::BlockKind::Clay), + "Block of Coal" => Some(crate::BlockKind::CoalBlock), + "Coal Ore" => Some(crate::BlockKind::CoalOre), + "Coarse Dirt" => Some(crate::BlockKind::CoarseDirt), + "Cobblestone" => Some(crate::BlockKind::Cobblestone), + "Cobblestone Slab" => Some(crate::BlockKind::CobblestoneSlab), + "Cobblestone Stairs" => Some(crate::BlockKind::CobblestoneStairs), + "Cobblestone Wall" => Some(crate::BlockKind::CobblestoneWall), + "Cobweb" => Some(crate::BlockKind::Cobweb), + "Cocoa" => Some(crate::BlockKind::Cocoa), + "Command Block" => Some(crate::BlockKind::CommandBlock), + "Redstone Comparator" => Some(crate::BlockKind::Comparator), + "Conduit" => Some(crate::BlockKind::Conduit), + "Cracked Stone Bricks" => Some(crate::BlockKind::CrackedStoneBricks), + "Crafting Table" => Some(crate::BlockKind::CraftingTable), + "Creeper Head" => Some(crate::BlockKind::CreeperHead), + "Creeper Wall Head" => Some(crate::BlockKind::CreeperWallHead), + "Cut Red Sandstone" => Some(crate::BlockKind::CutRedSandstone), + "Cut Sandstone" => Some(crate::BlockKind::CutSandstone), + "Cyan Banner" => Some(crate::BlockKind::CyanBanner), + "Cyan Bed" => Some(crate::BlockKind::CyanBed), + "Cyan Carpet" => Some(crate::BlockKind::CyanCarpet), + "Cyan Concrete" => Some(crate::BlockKind::CyanConcrete), + "Cyan Concrete Powder" => Some(crate::BlockKind::CyanConcretePowder), + "Cyan Glazed Terracotta" => Some(crate::BlockKind::CyanGlazedTerracotta), + "Cyan Shulker Box" => Some(crate::BlockKind::CyanShulkerBox), + "Cyan Stained Glass" => Some(crate::BlockKind::CyanStainedGlass), + "Cyan Stained Glass Pane" => Some(crate::BlockKind::CyanStainedGlassPane), + "Cyan Terracotta" => Some(crate::BlockKind::CyanTerracotta), + "Cyan wall banner" => Some(crate::BlockKind::CyanWallBanner), + "Cyan Wool" => Some(crate::BlockKind::CyanWool), + "Damaged Anvil" => Some(crate::BlockKind::DamagedAnvil), + "Dandelion" => Some(crate::BlockKind::Dandelion), + "Dark Oak Button" => Some(crate::BlockKind::DarkOakButton), + "Dark Oak Door" => Some(crate::BlockKind::DarkOakDoor), + "Dark Oak Fence" => Some(crate::BlockKind::DarkOakFence), + "Dark Oak Fence Gate" => Some(crate::BlockKind::DarkOakFenceGate), + "Dark Oak Leaves" => Some(crate::BlockKind::DarkOakLeaves), + "Dark Oak Log" => Some(crate::BlockKind::DarkOakLog), + "Dark Oak Planks" => Some(crate::BlockKind::DarkOakPlanks), + "Dark Oak Pressure Plate" => Some(crate::BlockKind::DarkOakPressurePlate), + "Dark Oak Sapling" => Some(crate::BlockKind::DarkOakSapling), + "Dark Oak Slab" => Some(crate::BlockKind::DarkOakSlab), + "Dark Oak Stairs" => Some(crate::BlockKind::DarkOakStairs), + "Dark Oak Trapdoor" => Some(crate::BlockKind::DarkOakTrapdoor), + "Dark Oak Wood" => Some(crate::BlockKind::DarkOakWood), + "Dark Prismarine" => Some(crate::BlockKind::DarkPrismarine), + "Dark Prismarine Slab" => Some(crate::BlockKind::DarkPrismarineSlab), + "Dark Prismarine Stairs" => Some(crate::BlockKind::DarkPrismarineStairs), + "Daylight Detector" => Some(crate::BlockKind::DaylightDetector), + "Dead Brain Coral" => Some(crate::BlockKind::DeadBrainCoral), + "Dead Brain Coral Block" => Some(crate::BlockKind::DeadBrainCoralBlock), + "Dead Brain Coral Fan" => Some(crate::BlockKind::DeadBrainCoralFan), + "Dead Brain Coral Wall Fan" => Some(crate::BlockKind::DeadBrainCoralWallFan), + "Dead Bubble Coral" => Some(crate::BlockKind::DeadBubbleCoral), + "Dead Bubble Coral Block" => Some(crate::BlockKind::DeadBubbleCoralBlock), + "Dead Bubble Coral Fan" => Some(crate::BlockKind::DeadBubbleCoralFan), + "Dead Bubble Coral Wall Fan" => Some(crate::BlockKind::DeadBubbleCoralWallFan), + "Dead Bush" => Some(crate::BlockKind::DeadBush), + "Dead Fire Coral" => Some(crate::BlockKind::DeadFireCoral), + "Dead Fire Coral Block" => Some(crate::BlockKind::DeadFireCoralBlock), + "Dead Fire Coral Fan" => Some(crate::BlockKind::DeadFireCoralFan), + "Dead Fire Coral Wall Fan" => Some(crate::BlockKind::DeadFireCoralWallFan), + "Dead Horn Coral" => Some(crate::BlockKind::DeadHornCoral), + "Dead Horn Coral Block" => Some(crate::BlockKind::DeadHornCoralBlock), + "Dead Horn Coral Fan" => Some(crate::BlockKind::DeadHornCoralFan), + "Dead Horn Coral Wall Fan" => Some(crate::BlockKind::DeadHornCoralWallFan), + "Dead Tube Coral" => Some(crate::BlockKind::DeadTubeCoral), + "Dead Tube Coral Block" => Some(crate::BlockKind::DeadTubeCoralBlock), + "Dead Tube Coral Fan" => Some(crate::BlockKind::DeadTubeCoralFan), + "Dead Tube Coral Wall Fan" => Some(crate::BlockKind::DeadTubeCoralWallFan), + "Detector Rail" => Some(crate::BlockKind::DetectorRail), + "Block of Diamond" => Some(crate::BlockKind::DiamondBlock), + "Diamond Ore" => Some(crate::BlockKind::DiamondOre), + "Diorite" => Some(crate::BlockKind::Diorite), + "Dirt" => Some(crate::BlockKind::Dirt), + "Dispenser" => Some(crate::BlockKind::Dispenser), + "Dragon Egg" => Some(crate::BlockKind::DragonEgg), + "Dragon Head" => Some(crate::BlockKind::DragonHead), + "Dragon Wall Head" => Some(crate::BlockKind::DragonWallHead), + "Dried Kelp Block" => Some(crate::BlockKind::DriedKelpBlock), + "Dropper" => Some(crate::BlockKind::Dropper), + "Block of Emerald" => Some(crate::BlockKind::EmeraldBlock), + "Emerald Ore" => Some(crate::BlockKind::EmeraldOre), + "Enchanting Table" => Some(crate::BlockKind::EnchantingTable), + "End Gateway" => Some(crate::BlockKind::EndGateway), + "End Portal" => Some(crate::BlockKind::EndPortal), + "End Portal Frame" => Some(crate::BlockKind::EndPortalFrame), + "End Rod" => Some(crate::BlockKind::EndRod), + "End Stone" => Some(crate::BlockKind::EndStone), + "End Stone Bricks" => Some(crate::BlockKind::EndStoneBricks), + "Ender Chest" => Some(crate::BlockKind::EnderChest), + "Farmland" => Some(crate::BlockKind::Farmland), + "Fern" => Some(crate::BlockKind::Fern), + "Fire" => Some(crate::BlockKind::Fire), + "Fire Coral" => Some(crate::BlockKind::FireCoral), + "Fire Coral Block" => Some(crate::BlockKind::FireCoralBlock), + "Fire Coral Fan" => Some(crate::BlockKind::FireCoralFan), + "Fire Coral Wall Fan" => Some(crate::BlockKind::FireCoralWallFan), + "Flower Pot" => Some(crate::BlockKind::FlowerPot), + "Frosted Ice" => Some(crate::BlockKind::FrostedIce), + "Furnace" => Some(crate::BlockKind::Furnace), + "Glass" => Some(crate::BlockKind::Glass), + "Glass Pane" => Some(crate::BlockKind::GlassPane), + "Glowstone" => Some(crate::BlockKind::Glowstone), + "Block of Gold" => Some(crate::BlockKind::GoldBlock), + "Gold Ore" => Some(crate::BlockKind::GoldOre), + "Granite" => Some(crate::BlockKind::Granite), + "Grass" => Some(crate::BlockKind::Grass), + "Grass Block" => Some(crate::BlockKind::GrassBlock), + "Grass Path" => Some(crate::BlockKind::GrassPath), + "Gravel" => Some(crate::BlockKind::Gravel), + "Gray Banner" => Some(crate::BlockKind::GrayBanner), + "Gray Bed" => Some(crate::BlockKind::GrayBed), + "Gray Carpet" => Some(crate::BlockKind::GrayCarpet), + "Gray Concrete" => Some(crate::BlockKind::GrayConcrete), + "Gray Concrete Powder" => Some(crate::BlockKind::GrayConcretePowder), + "Gray Glazed Terracotta" => Some(crate::BlockKind::GrayGlazedTerracotta), + "Gray Shulker Box" => Some(crate::BlockKind::GrayShulkerBox), + "Gray Stained Glass" => Some(crate::BlockKind::GrayStainedGlass), + "Gray Stained Glass Pane" => Some(crate::BlockKind::GrayStainedGlassPane), + "Gray Terracotta" => Some(crate::BlockKind::GrayTerracotta), + "Gray wall banner" => Some(crate::BlockKind::GrayWallBanner), + "Gray Wool" => Some(crate::BlockKind::GrayWool), + "Green Banner" => Some(crate::BlockKind::GreenBanner), + "Green Bed" => Some(crate::BlockKind::GreenBed), + "Green Carpet" => Some(crate::BlockKind::GreenCarpet), + "Green Concrete" => Some(crate::BlockKind::GreenConcrete), + "Green Concrete Powder" => Some(crate::BlockKind::GreenConcretePowder), + "Green Glazed Terracotta" => Some(crate::BlockKind::GreenGlazedTerracotta), + "Green Shulker Box" => Some(crate::BlockKind::GreenShulkerBox), + "Green Stained Glass" => Some(crate::BlockKind::GreenStainedGlass), + "Green Stained Glass Pane" => Some(crate::BlockKind::GreenStainedGlassPane), + "Green Terracotta" => Some(crate::BlockKind::GreenTerracotta), + "Green wall banner" => Some(crate::BlockKind::GreenWallBanner), + "Green Wool" => Some(crate::BlockKind::GreenWool), + "Hay Bale" => Some(crate::BlockKind::HayBlock), + "Heavy Weighted Pressure Plate" => Some(crate::BlockKind::HeavyWeightedPressurePlate), + "Hopper" => Some(crate::BlockKind::Hopper), + "Horn Coral" => Some(crate::BlockKind::HornCoral), + "Horn Coral Block" => Some(crate::BlockKind::HornCoralBlock), + "Horn Coral Fan" => Some(crate::BlockKind::HornCoralFan), + "Horn Coral Wall Fan" => Some(crate::BlockKind::HornCoralWallFan), + "Ice" => Some(crate::BlockKind::Ice), + "Infested Chiseled Stone Bricks" => Some(crate::BlockKind::InfestedChiseledStoneBricks), + "Infested Cobblestone" => Some(crate::BlockKind::InfestedCobblestone), + "Infested Cracked Stone Bricks" => Some(crate::BlockKind::InfestedCrackedStoneBricks), + "Infested Mossy Stone Bricks" => Some(crate::BlockKind::InfestedMossyStoneBricks), + "Infested Stone" => Some(crate::BlockKind::InfestedStone), + "Infested Stone Bricks" => Some(crate::BlockKind::InfestedStoneBricks), + "Iron Bars" => Some(crate::BlockKind::IronBars), + "Block of Iron" => Some(crate::BlockKind::IronBlock), + "Iron Door" => Some(crate::BlockKind::IronDoor), + "Iron Ore" => Some(crate::BlockKind::IronOre), + "Iron Trapdoor" => Some(crate::BlockKind::IronTrapdoor), + "Jack o'Lantern" => Some(crate::BlockKind::JackOLantern), + "Jukebox" => Some(crate::BlockKind::Jukebox), + "Jungle Button" => Some(crate::BlockKind::JungleButton), + "Jungle Door" => Some(crate::BlockKind::JungleDoor), + "Jungle Fence" => Some(crate::BlockKind::JungleFence), + "Jungle Fence Gate" => Some(crate::BlockKind::JungleFenceGate), + "Jungle Leaves" => Some(crate::BlockKind::JungleLeaves), + "Jungle Log" => Some(crate::BlockKind::JungleLog), + "Jungle Planks" => Some(crate::BlockKind::JunglePlanks), + "Jungle Pressure Plate" => Some(crate::BlockKind::JunglePressurePlate), + "Jungle Sapling" => Some(crate::BlockKind::JungleSapling), + "Jungle Slab" => Some(crate::BlockKind::JungleSlab), + "Jungle Stairs" => Some(crate::BlockKind::JungleStairs), + "Jungle Trapdoor" => Some(crate::BlockKind::JungleTrapdoor), + "Jungle Wood" => Some(crate::BlockKind::JungleWood), + "Kelp" => Some(crate::BlockKind::Kelp), + "Kelp Plant" => Some(crate::BlockKind::KelpPlant), + "Ladder" => Some(crate::BlockKind::Ladder), + "Lapis Lazuli Block" => Some(crate::BlockKind::LapisBlock), + "Lapis Lazuli Ore" => Some(crate::BlockKind::LapisOre), + "Large Fern" => Some(crate::BlockKind::LargeFern), + "Lava" => Some(crate::BlockKind::Lava), + "Lever" => Some(crate::BlockKind::Lever), + "Light Blue Banner" => Some(crate::BlockKind::LightBlueBanner), + "Light Blue Bed" => Some(crate::BlockKind::LightBlueBed), + "Light Blue Carpet" => Some(crate::BlockKind::LightBlueCarpet), + "Light Blue Concrete" => Some(crate::BlockKind::LightBlueConcrete), + "Light Blue Concrete Powder" => Some(crate::BlockKind::LightBlueConcretePowder), + "Light Blue Glazed Terracotta" => Some(crate::BlockKind::LightBlueGlazedTerracotta), + "Light Blue Shulker Box" => Some(crate::BlockKind::LightBlueShulkerBox), + "Light Blue Stained Glass" => Some(crate::BlockKind::LightBlueStainedGlass), + "Light Blue Stained Glass Pane" => Some(crate::BlockKind::LightBlueStainedGlassPane), + "Light Blue Terracotta" => Some(crate::BlockKind::LightBlueTerracotta), + "Light blue wall banner" => Some(crate::BlockKind::LightBlueWallBanner), + "Light Blue Wool" => Some(crate::BlockKind::LightBlueWool), + "Light Gray Banner" => Some(crate::BlockKind::LightGrayBanner), + "Light Gray Bed" => Some(crate::BlockKind::LightGrayBed), + "Light Gray Carpet" => Some(crate::BlockKind::LightGrayCarpet), + "Light Gray Concrete" => Some(crate::BlockKind::LightGrayConcrete), + "Light Gray Concrete Powder" => Some(crate::BlockKind::LightGrayConcretePowder), + "Light Gray Glazed Terracotta" => Some(crate::BlockKind::LightGrayGlazedTerracotta), + "Light Gray Shulker Box" => Some(crate::BlockKind::LightGrayShulkerBox), + "Light Gray Stained Glass" => Some(crate::BlockKind::LightGrayStainedGlass), + "Light Gray Stained Glass Pane" => Some(crate::BlockKind::LightGrayStainedGlassPane), + "Light Gray Terracotta" => Some(crate::BlockKind::LightGrayTerracotta), + "Light gray wall banner" => Some(crate::BlockKind::LightGrayWallBanner), + "Light Gray Wool" => Some(crate::BlockKind::LightGrayWool), + "Light Weighted Pressure Plate" => Some(crate::BlockKind::LightWeightedPressurePlate), + "Lilac" => Some(crate::BlockKind::Lilac), + "Lily Pad" => Some(crate::BlockKind::LilyPad), + "Lime Banner" => Some(crate::BlockKind::LimeBanner), + "Lime Bed" => Some(crate::BlockKind::LimeBed), + "Lime Carpet" => Some(crate::BlockKind::LimeCarpet), + "Lime Concrete" => Some(crate::BlockKind::LimeConcrete), + "Lime Concrete Powder" => Some(crate::BlockKind::LimeConcretePowder), + "Lime Glazed Terracotta" => Some(crate::BlockKind::LimeGlazedTerracotta), + "Lime Shulker Box" => Some(crate::BlockKind::LimeShulkerBox), + "Lime Stained Glass" => Some(crate::BlockKind::LimeStainedGlass), + "Lime Stained Glass Pane" => Some(crate::BlockKind::LimeStainedGlassPane), + "Lime Terracotta" => Some(crate::BlockKind::LimeTerracotta), + "Lime wall banner" => Some(crate::BlockKind::LimeWallBanner), + "Lime Wool" => Some(crate::BlockKind::LimeWool), + "Magenta Banner" => Some(crate::BlockKind::MagentaBanner), + "Magenta Bed" => Some(crate::BlockKind::MagentaBed), + "Magenta Carpet" => Some(crate::BlockKind::MagentaCarpet), + "Magenta Concrete" => Some(crate::BlockKind::MagentaConcrete), + "Magenta Concrete Powder" => Some(crate::BlockKind::MagentaConcretePowder), + "Magenta Glazed Terracotta" => Some(crate::BlockKind::MagentaGlazedTerracotta), + "Magenta Shulker Box" => Some(crate::BlockKind::MagentaShulkerBox), + "Magenta Stained Glass" => Some(crate::BlockKind::MagentaStainedGlass), + "Magenta Stained Glass Pane" => Some(crate::BlockKind::MagentaStainedGlassPane), + "Magenta Terracotta" => Some(crate::BlockKind::MagentaTerracotta), + "Magenta wall banner" => Some(crate::BlockKind::MagentaWallBanner), + "Magenta Wool" => Some(crate::BlockKind::MagentaWool), + "Magma Block" => Some(crate::BlockKind::MagmaBlock), + "Melon" => Some(crate::BlockKind::Melon), + "Melon Stem" => Some(crate::BlockKind::MelonStem), + "Mossy Cobblestone" => Some(crate::BlockKind::MossyCobblestone), + "Mossy Cobblestone Wall" => Some(crate::BlockKind::MossyCobblestoneWall), + "Mossy Stone Bricks" => Some(crate::BlockKind::MossyStoneBricks), + "Moving Piston" => Some(crate::BlockKind::MovingPiston), + "Mushroom Stem" => Some(crate::BlockKind::MushroomStem), + "Mycelium" => Some(crate::BlockKind::Mycelium), + "Nether Brick Fence" => Some(crate::BlockKind::NetherBrickFence), + "Nether Brick Slab" => Some(crate::BlockKind::NetherBrickSlab), + "Nether Brick Stairs" => Some(crate::BlockKind::NetherBrickStairs), + "Nether Bricks" => Some(crate::BlockKind::NetherBricks), + "Nether Portal" => Some(crate::BlockKind::NetherPortal), + "Nether Quartz Ore" => Some(crate::BlockKind::NetherQuartzOre), + "Nether Wart" => Some(crate::BlockKind::NetherWart), + "Nether Wart Block" => Some(crate::BlockKind::NetherWartBlock), + "Netherrack" => Some(crate::BlockKind::Netherrack), + "Note Block" => Some(crate::BlockKind::NoteBlock), + "Oak Button" => Some(crate::BlockKind::OakButton), + "Oak Door" => Some(crate::BlockKind::OakDoor), + "Oak Fence" => Some(crate::BlockKind::OakFence), + "Oak Fence Gate" => Some(crate::BlockKind::OakFenceGate), + "Oak Leaves" => Some(crate::BlockKind::OakLeaves), + "Oak Log" => Some(crate::BlockKind::OakLog), + "Oak Planks" => Some(crate::BlockKind::OakPlanks), + "Oak Pressure Plate" => Some(crate::BlockKind::OakPressurePlate), + "Oak Sapling" => Some(crate::BlockKind::OakSapling), + "Oak Slab" => Some(crate::BlockKind::OakSlab), + "Oak Stairs" => Some(crate::BlockKind::OakStairs), + "Oak Trapdoor" => Some(crate::BlockKind::OakTrapdoor), + "Oak Wood" => Some(crate::BlockKind::OakWood), + "Observer" => Some(crate::BlockKind::Observer), + "Obsidian" => Some(crate::BlockKind::Obsidian), + "Orange Banner" => Some(crate::BlockKind::OrangeBanner), + "Orange Bed" => Some(crate::BlockKind::OrangeBed), + "Orange Carpet" => Some(crate::BlockKind::OrangeCarpet), + "Orange Concrete" => Some(crate::BlockKind::OrangeConcrete), + "Orange Concrete Powder" => Some(crate::BlockKind::OrangeConcretePowder), + "Orange Glazed Terracotta" => Some(crate::BlockKind::OrangeGlazedTerracotta), + "Orange Shulker Box" => Some(crate::BlockKind::OrangeShulkerBox), + "Orange Stained Glass" => Some(crate::BlockKind::OrangeStainedGlass), + "Orange Stained Glass Pane" => Some(crate::BlockKind::OrangeStainedGlassPane), + "Orange Terracotta" => Some(crate::BlockKind::OrangeTerracotta), + "Orange Tulip" => Some(crate::BlockKind::OrangeTulip), + "Orange wall banner" => Some(crate::BlockKind::OrangeWallBanner), + "Orange Wool" => Some(crate::BlockKind::OrangeWool), + "Oxeye Daisy" => Some(crate::BlockKind::OxeyeDaisy), + "Packed Ice" => Some(crate::BlockKind::PackedIce), + "Peony" => Some(crate::BlockKind::Peony), + "Petrified Oak Slab" => Some(crate::BlockKind::PetrifiedOakSlab), + "Pink Banner" => Some(crate::BlockKind::PinkBanner), + "Pink Bed" => Some(crate::BlockKind::PinkBed), + "Pink Carpet" => Some(crate::BlockKind::PinkCarpet), + "Pink Concrete" => Some(crate::BlockKind::PinkConcrete), + "Pink Concrete Powder" => Some(crate::BlockKind::PinkConcretePowder), + "Pink Glazed Terracotta" => Some(crate::BlockKind::PinkGlazedTerracotta), + "Pink Shulker Box" => Some(crate::BlockKind::PinkShulkerBox), + "Pink Stained Glass" => Some(crate::BlockKind::PinkStainedGlass), + "Pink Stained Glass Pane" => Some(crate::BlockKind::PinkStainedGlassPane), + "Pink Terracotta" => Some(crate::BlockKind::PinkTerracotta), + "Pink Tulip" => Some(crate::BlockKind::PinkTulip), + "Pink wall banner" => Some(crate::BlockKind::PinkWallBanner), + "Pink Wool" => Some(crate::BlockKind::PinkWool), + "Piston" => Some(crate::BlockKind::Piston), + "Piston Head" => Some(crate::BlockKind::PistonHead), + "Player Head" => Some(crate::BlockKind::PlayerHead), + "Player Wall Head" => Some(crate::BlockKind::PlayerWallHead), + "Podzol" => Some(crate::BlockKind::Podzol), + "Polished Andesite" => Some(crate::BlockKind::PolishedAndesite), + "Polished Diorite" => Some(crate::BlockKind::PolishedDiorite), + "Polished Granite" => Some(crate::BlockKind::PolishedGranite), + "Poppy" => Some(crate::BlockKind::Poppy), + "Potatoes" => Some(crate::BlockKind::Potatoes), + "Potted Acacia Sapling" => Some(crate::BlockKind::PottedAcaciaSapling), + "Potted Allium" => Some(crate::BlockKind::PottedAllium), + "Potted Azure Bluet" => Some(crate::BlockKind::PottedAzureBluet), + "Potted Birch Sapling" => Some(crate::BlockKind::PottedBirchSapling), + "Potted Blue Orchid" => Some(crate::BlockKind::PottedBlueOrchid), + "Potted Brown Mushroom" => Some(crate::BlockKind::PottedBrownMushroom), + "Potted Cactus" => Some(crate::BlockKind::PottedCactus), + "Potted Dandelion" => Some(crate::BlockKind::PottedDandelion), + "Potted Dark Oak Sapling" => Some(crate::BlockKind::PottedDarkOakSapling), + "Potted Dead Bush" => Some(crate::BlockKind::PottedDeadBush), + "Potted Fern" => Some(crate::BlockKind::PottedFern), + "Potted Jungle Sapling" => Some(crate::BlockKind::PottedJungleSapling), + "Potted Oak Sapling" => Some(crate::BlockKind::PottedOakSapling), + "Potted Orange Tulip" => Some(crate::BlockKind::PottedOrangeTulip), + "Potted Oxeye Daisy" => Some(crate::BlockKind::PottedOxeyeDaisy), + "Potted Pink Tulip" => Some(crate::BlockKind::PottedPinkTulip), + "Potted Poppy" => Some(crate::BlockKind::PottedPoppy), + "Potted Red Mushroom" => Some(crate::BlockKind::PottedRedMushroom), + "Potted Red Tulip" => Some(crate::BlockKind::PottedRedTulip), + "Potted Spruce Sapling" => Some(crate::BlockKind::PottedSpruceSapling), + "Potted White Tulip" => Some(crate::BlockKind::PottedWhiteTulip), + "Powered Rail" => Some(crate::BlockKind::PoweredRail), + "Prismarine" => Some(crate::BlockKind::Prismarine), + "Prismarine Brick Slab" => Some(crate::BlockKind::PrismarineBrickSlab), + "Prismarine Brick Stairs" => Some(crate::BlockKind::PrismarineBrickStairs), + "Prismarine Bricks" => Some(crate::BlockKind::PrismarineBricks), + "Prismarine Slab" => Some(crate::BlockKind::PrismarineSlab), + "Prismarine Stairs" => Some(crate::BlockKind::PrismarineStairs), + "Pumpkin" => Some(crate::BlockKind::Pumpkin), + "Pumpkin Stem" => Some(crate::BlockKind::PumpkinStem), + "Purple Banner" => Some(crate::BlockKind::PurpleBanner), + "Purple Bed" => Some(crate::BlockKind::PurpleBed), + "Purple Carpet" => Some(crate::BlockKind::PurpleCarpet), + "Purple Concrete" => Some(crate::BlockKind::PurpleConcrete), + "Purple Concrete Powder" => Some(crate::BlockKind::PurpleConcretePowder), + "Purple Glazed Terracotta" => Some(crate::BlockKind::PurpleGlazedTerracotta), + "Purple Shulker Box" => Some(crate::BlockKind::PurpleShulkerBox), + "Purple Stained Glass" => Some(crate::BlockKind::PurpleStainedGlass), + "Purple Stained Glass Pane" => Some(crate::BlockKind::PurpleStainedGlassPane), + "Purple Terracotta" => Some(crate::BlockKind::PurpleTerracotta), + "Purple wall banner" => Some(crate::BlockKind::PurpleWallBanner), + "Purple Wool" => Some(crate::BlockKind::PurpleWool), + "Purpur Block" => Some(crate::BlockKind::PurpurBlock), + "Purpur Pillar" => Some(crate::BlockKind::PurpurPillar), + "Purpur Slab" => Some(crate::BlockKind::PurpurSlab), + "Purpur Stairs" => Some(crate::BlockKind::PurpurStairs), + "Block of Quartz" => Some(crate::BlockKind::QuartzBlock), + "Quartz Pillar" => Some(crate::BlockKind::QuartzPillar), + "Quartz Slab" => Some(crate::BlockKind::QuartzSlab), + "Quartz Stairs" => Some(crate::BlockKind::QuartzStairs), + "Rail" => Some(crate::BlockKind::Rail), + "Red Banner" => Some(crate::BlockKind::RedBanner), + "Red Bed" => Some(crate::BlockKind::RedBed), + "Red Carpet" => Some(crate::BlockKind::RedCarpet), + "Red Concrete" => Some(crate::BlockKind::RedConcrete), + "Red Concrete Powder" => Some(crate::BlockKind::RedConcretePowder), + "Red Glazed Terracotta" => Some(crate::BlockKind::RedGlazedTerracotta), + "Red Mushroom" => Some(crate::BlockKind::RedMushroom), + "Red Mushroom Block" => Some(crate::BlockKind::RedMushroomBlock), + "Red Nether Bricks" => Some(crate::BlockKind::RedNetherBricks), + "Red Sand" => Some(crate::BlockKind::RedSand), + "Red Sandstone" => Some(crate::BlockKind::RedSandstone), + "Red Sandstone Slab" => Some(crate::BlockKind::RedSandstoneSlab), + "Red Sandstone Stairs" => Some(crate::BlockKind::RedSandstoneStairs), + "Red Shulker Box" => Some(crate::BlockKind::RedShulkerBox), + "Red Stained Glass" => Some(crate::BlockKind::RedStainedGlass), + "Red Stained Glass Pane" => Some(crate::BlockKind::RedStainedGlassPane), + "Red Terracotta" => Some(crate::BlockKind::RedTerracotta), + "Red Tulip" => Some(crate::BlockKind::RedTulip), + "Red wall banner" => Some(crate::BlockKind::RedWallBanner), + "Red Wool" => Some(crate::BlockKind::RedWool), + "Block of Redstone" => Some(crate::BlockKind::RedstoneBlock), + "Redstone Lamp" => Some(crate::BlockKind::RedstoneLamp), + "Redstone Ore" => Some(crate::BlockKind::RedstoneOre), + "Redstone Torch" => Some(crate::BlockKind::RedstoneTorch), + "Redstone Wall Torch" => Some(crate::BlockKind::RedstoneWallTorch), + "Redstone Dust" => Some(crate::BlockKind::RedstoneWire), + "Redstone Repeater" => Some(crate::BlockKind::Repeater), + "Repeating Command Block" => Some(crate::BlockKind::RepeatingCommandBlock), + "Rose Bush" => Some(crate::BlockKind::RoseBush), + "Sand" => Some(crate::BlockKind::Sand), + "Sandstone" => Some(crate::BlockKind::Sandstone), + "Sandstone Slab" => Some(crate::BlockKind::SandstoneSlab), + "Sandstone Stairs" => Some(crate::BlockKind::SandstoneStairs), + "Sea Lantern" => Some(crate::BlockKind::SeaLantern), + "Sea Pickle" => Some(crate::BlockKind::SeaPickle), + "Seagrass" => Some(crate::BlockKind::Seagrass), + "Shulker Box" => Some(crate::BlockKind::ShulkerBox), + "Sign" => Some(crate::BlockKind::Sign), + "Skeleton Skull" => Some(crate::BlockKind::SkeletonSkull), + "Skeleton Wall Skull" => Some(crate::BlockKind::SkeletonWallSkull), + "Slime Block" => Some(crate::BlockKind::SlimeBlock), + "Smooth Quartz" => Some(crate::BlockKind::SmoothQuartz), + "Smooth Red Sandstone" => Some(crate::BlockKind::SmoothRedSandstone), + "Smooth Sandstone" => Some(crate::BlockKind::SmoothSandstone), + "Smooth Stone" => Some(crate::BlockKind::SmoothStone), + "Snow" => Some(crate::BlockKind::Snow), + "Snow Block" => Some(crate::BlockKind::SnowBlock), + "Soul Sand" => Some(crate::BlockKind::SoulSand), + "Spawner" => Some(crate::BlockKind::Spawner), + "Sponge" => Some(crate::BlockKind::Sponge), + "Spruce Button" => Some(crate::BlockKind::SpruceButton), + "Spruce Door" => Some(crate::BlockKind::SpruceDoor), + "Spruce Fence" => Some(crate::BlockKind::SpruceFence), + "Spruce Fence Gate" => Some(crate::BlockKind::SpruceFenceGate), + "Spruce Leaves" => Some(crate::BlockKind::SpruceLeaves), + "Spruce Log" => Some(crate::BlockKind::SpruceLog), + "Spruce Planks" => Some(crate::BlockKind::SprucePlanks), + "Spruce Pressure Plate" => Some(crate::BlockKind::SprucePressurePlate), + "Spruce Sapling" => Some(crate::BlockKind::SpruceSapling), + "Spruce Slab" => Some(crate::BlockKind::SpruceSlab), + "Spruce Stairs" => Some(crate::BlockKind::SpruceStairs), + "Spruce Trapdoor" => Some(crate::BlockKind::SpruceTrapdoor), + "Spruce Wood" => Some(crate::BlockKind::SpruceWood), + "Sticky Piston" => Some(crate::BlockKind::StickyPiston), + "Stone" => Some(crate::BlockKind::Stone), + "Stone Brick Slab" => Some(crate::BlockKind::StoneBrickSlab), + "Stone Brick Stairs" => Some(crate::BlockKind::StoneBrickStairs), + "Stone Bricks" => Some(crate::BlockKind::StoneBricks), + "Stone Button" => Some(crate::BlockKind::StoneButton), + "Stone Pressure Plate" => Some(crate::BlockKind::StonePressurePlate), + "Stone Slab" => Some(crate::BlockKind::StoneSlab), + "Stripped Acacia Log" => Some(crate::BlockKind::StrippedAcaciaLog), + "Stripped Acacia Wood" => Some(crate::BlockKind::StrippedAcaciaWood), + "Stripped Birch Log" => Some(crate::BlockKind::StrippedBirchLog), + "Stripped Birch Wood" => Some(crate::BlockKind::StrippedBirchWood), + "Stripped Dark Oak Log" => Some(crate::BlockKind::StrippedDarkOakLog), + "Stripped Dark Oak Wood" => Some(crate::BlockKind::StrippedDarkOakWood), + "Stripped Jungle Log" => Some(crate::BlockKind::StrippedJungleLog), + "Stripped Jungle Wood" => Some(crate::BlockKind::StrippedJungleWood), + "Stripped Oak Log" => Some(crate::BlockKind::StrippedOakLog), + "Stripped Oak Wood" => Some(crate::BlockKind::StrippedOakWood), + "Stripped Spruce Log" => Some(crate::BlockKind::StrippedSpruceLog), + "Stripped Spruce Wood" => Some(crate::BlockKind::StrippedSpruceWood), + "Structure Block" => Some(crate::BlockKind::StructureBlock), + "Structure Void" => Some(crate::BlockKind::StructureVoid), + "Sugar Cane" => Some(crate::BlockKind::SugarCane), + "Sunflower" => Some(crate::BlockKind::Sunflower), + "Tall Grass" => Some(crate::BlockKind::TallGrass), + "Tall Seagrass" => Some(crate::BlockKind::TallSeagrass), + "Terracotta" => Some(crate::BlockKind::Terracotta), + "TNT" => Some(crate::BlockKind::Tnt), + "Torch" => Some(crate::BlockKind::Torch), + "Trapped Chest" => Some(crate::BlockKind::TrappedChest), + "Tripwire" => Some(crate::BlockKind::Tripwire), + "Tripwire Hook" => Some(crate::BlockKind::TripwireHook), + "Tube Coral" => Some(crate::BlockKind::TubeCoral), + "Tube Coral Block" => Some(crate::BlockKind::TubeCoralBlock), + "Tube Coral Fan" => Some(crate::BlockKind::TubeCoralFan), + "Tube Coral Wall Fan" => Some(crate::BlockKind::TubeCoralWallFan), + "Turtle Egg" => Some(crate::BlockKind::TurtleEgg), + "Vines" => Some(crate::BlockKind::Vine), + "Void Air" => Some(crate::BlockKind::VoidAir), + "Wall Sign" => Some(crate::BlockKind::WallSign), + "Wall Torch" => Some(crate::BlockKind::WallTorch), + "Water" => Some(crate::BlockKind::Water), + "Wet Sponge" => Some(crate::BlockKind::WetSponge), + "Wheat Crops" => Some(crate::BlockKind::Wheat), + "White Banner" => Some(crate::BlockKind::WhiteBanner), + "White Bed" => Some(crate::BlockKind::WhiteBed), + "White Carpet" => Some(crate::BlockKind::WhiteCarpet), + "White Concrete" => Some(crate::BlockKind::WhiteConcrete), + "White Concrete Powder" => Some(crate::BlockKind::WhiteConcretePowder), + "White Glazed Terracotta" => Some(crate::BlockKind::WhiteGlazedTerracotta), + "White Shulker Box" => Some(crate::BlockKind::WhiteShulkerBox), + "White Stained Glass" => Some(crate::BlockKind::WhiteStainedGlass), + "White Stained Glass Pane" => Some(crate::BlockKind::WhiteStainedGlassPane), + "White Terracotta" => Some(crate::BlockKind::WhiteTerracotta), + "White Tulip" => Some(crate::BlockKind::WhiteTulip), + "White wall banner" => Some(crate::BlockKind::WhiteWallBanner), + "White Wool" => Some(crate::BlockKind::WhiteWool), + "Wither Skeleton Skull" => Some(crate::BlockKind::WitherSkeletonSkull), + "Wither Skeleton Wall Skull" => Some(crate::BlockKind::WitherSkeletonWallSkull), + "Yellow Banner" => Some(crate::BlockKind::YellowBanner), + "Yellow Bed" => Some(crate::BlockKind::YellowBed), + "Yellow Carpet" => Some(crate::BlockKind::YellowCarpet), + "Yellow Concrete" => Some(crate::BlockKind::YellowConcrete), + "Yellow Concrete Powder" => Some(crate::BlockKind::YellowConcretePowder), + "Yellow Glazed Terracotta" => Some(crate::BlockKind::YellowGlazedTerracotta), + "Yellow Shulker Box" => Some(crate::BlockKind::YellowShulkerBox), + "Yellow Stained Glass" => Some(crate::BlockKind::YellowStainedGlass), + "Yellow Stained Glass Pane" => Some(crate::BlockKind::YellowStainedGlassPane), + "Yellow Terracotta" => Some(crate::BlockKind::YellowTerracotta), + "Yellow wall banner" => Some(crate::BlockKind::YellowWallBanner), + "Yellow Wool" => Some(crate::BlockKind::YellowWool), + "Zombie Head" => Some(crate::BlockKind::ZombieHead), + "Zombie Wall Head" => Some(crate::BlockKind::ZombieWallHead), + _ => None, + } + } +} +impl crate::BlockKind { + pub fn diggable(self) -> bool { + match self { + crate::BlockKind::AcaciaButton => true, + crate::BlockKind::AcaciaDoor => true, + crate::BlockKind::AcaciaFence => true, + crate::BlockKind::AcaciaFenceGate => true, + crate::BlockKind::AcaciaLeaves => true, + crate::BlockKind::AcaciaLog => true, + crate::BlockKind::AcaciaPlanks => true, + crate::BlockKind::AcaciaPressurePlate => true, + crate::BlockKind::AcaciaSapling => true, + crate::BlockKind::AcaciaSlab => true, + crate::BlockKind::AcaciaStairs => true, + crate::BlockKind::AcaciaTrapdoor => true, + crate::BlockKind::AcaciaWood => true, + crate::BlockKind::ActivatorRail => true, + crate::BlockKind::Air => true, + crate::BlockKind::Allium => true, + crate::BlockKind::Andesite => true, + crate::BlockKind::Anvil => true, + crate::BlockKind::AttachedMelonStem => true, + crate::BlockKind::AttachedPumpkinStem => true, + crate::BlockKind::AzureBluet => true, + crate::BlockKind::Barrier => false, + crate::BlockKind::Beacon => true, + crate::BlockKind::Bedrock => false, + crate::BlockKind::Beetroots => true, + crate::BlockKind::BirchButton => true, + crate::BlockKind::BirchDoor => true, + crate::BlockKind::BirchFence => true, + crate::BlockKind::BirchFenceGate => true, + crate::BlockKind::BirchLeaves => true, + crate::BlockKind::BirchLog => true, + crate::BlockKind::BirchPlanks => true, + crate::BlockKind::BirchPressurePlate => true, + crate::BlockKind::BirchSapling => true, + crate::BlockKind::BirchSlab => true, + crate::BlockKind::BirchStairs => true, + crate::BlockKind::BirchTrapdoor => true, + crate::BlockKind::BirchWood => true, + crate::BlockKind::BlackBanner => true, + crate::BlockKind::BlackBed => true, + crate::BlockKind::BlackCarpet => true, + crate::BlockKind::BlackConcrete => true, + crate::BlockKind::BlackConcretePowder => true, + crate::BlockKind::BlackGlazedTerracotta => true, + crate::BlockKind::BlackShulkerBox => true, + crate::BlockKind::BlackStainedGlass => true, + crate::BlockKind::BlackStainedGlassPane => true, + crate::BlockKind::BlackTerracotta => true, + crate::BlockKind::BlackWallBanner => true, + crate::BlockKind::BlackWool => true, + crate::BlockKind::BlueBanner => true, + crate::BlockKind::BlueBed => true, + crate::BlockKind::BlueCarpet => true, + crate::BlockKind::BlueConcrete => true, + crate::BlockKind::BlueConcretePowder => true, + crate::BlockKind::BlueGlazedTerracotta => true, + crate::BlockKind::BlueIce => true, + crate::BlockKind::BlueOrchid => true, + crate::BlockKind::BlueShulkerBox => true, + crate::BlockKind::BlueStainedGlass => true, + crate::BlockKind::BlueStainedGlassPane => true, + crate::BlockKind::BlueTerracotta => true, + crate::BlockKind::BlueWallBanner => true, + crate::BlockKind::BlueWool => true, + crate::BlockKind::BoneBlock => true, + crate::BlockKind::Bookshelf => true, + crate::BlockKind::BrainCoral => true, + crate::BlockKind::BrainCoralBlock => true, + crate::BlockKind::BrainCoralFan => true, + crate::BlockKind::BrainCoralWallFan => true, + crate::BlockKind::BrewingStand => true, + crate::BlockKind::BrickSlab => true, + crate::BlockKind::BrickStairs => true, + crate::BlockKind::Bricks => true, + crate::BlockKind::BrownBanner => true, + crate::BlockKind::BrownBed => true, + crate::BlockKind::BrownCarpet => true, + crate::BlockKind::BrownConcrete => true, + crate::BlockKind::BrownConcretePowder => true, + crate::BlockKind::BrownGlazedTerracotta => true, + crate::BlockKind::BrownMushroom => true, + crate::BlockKind::BrownMushroomBlock => true, + crate::BlockKind::BrownShulkerBox => true, + crate::BlockKind::BrownStainedGlass => true, + crate::BlockKind::BrownStainedGlassPane => true, + crate::BlockKind::BrownTerracotta => true, + crate::BlockKind::BrownWallBanner => true, + crate::BlockKind::BrownWool => true, + crate::BlockKind::BubbleColumn => true, + crate::BlockKind::BubbleCoral => true, + crate::BlockKind::BubbleCoralBlock => true, + crate::BlockKind::BubbleCoralFan => true, + crate::BlockKind::BubbleCoralWallFan => true, + crate::BlockKind::Cactus => true, + crate::BlockKind::Cake => true, + crate::BlockKind::Carrots => true, + crate::BlockKind::CarvedPumpkin => true, + crate::BlockKind::Cauldron => true, + crate::BlockKind::CaveAir => true, + crate::BlockKind::ChainCommandBlock => false, + crate::BlockKind::Chest => true, + crate::BlockKind::ChippedAnvil => true, + crate::BlockKind::ChiseledQuartzBlock => true, + crate::BlockKind::ChiseledRedSandstone => true, + crate::BlockKind::ChiseledSandstone => true, + crate::BlockKind::ChiseledStoneBricks => true, + crate::BlockKind::ChorusFlower => true, + crate::BlockKind::ChorusPlant => true, + crate::BlockKind::Clay => true, + crate::BlockKind::CoalBlock => true, + crate::BlockKind::CoalOre => true, + crate::BlockKind::CoarseDirt => true, + crate::BlockKind::Cobblestone => true, + crate::BlockKind::CobblestoneSlab => true, + crate::BlockKind::CobblestoneStairs => true, + crate::BlockKind::CobblestoneWall => true, + crate::BlockKind::Cobweb => true, + crate::BlockKind::Cocoa => true, + crate::BlockKind::CommandBlock => false, + crate::BlockKind::Comparator => true, + crate::BlockKind::Conduit => true, + crate::BlockKind::CrackedStoneBricks => true, + crate::BlockKind::CraftingTable => true, + crate::BlockKind::CreeperHead => true, + crate::BlockKind::CreeperWallHead => true, + crate::BlockKind::CutRedSandstone => true, + crate::BlockKind::CutSandstone => true, + crate::BlockKind::CyanBanner => true, + crate::BlockKind::CyanBed => true, + crate::BlockKind::CyanCarpet => true, + crate::BlockKind::CyanConcrete => true, + crate::BlockKind::CyanConcretePowder => true, + crate::BlockKind::CyanGlazedTerracotta => true, + crate::BlockKind::CyanShulkerBox => true, + crate::BlockKind::CyanStainedGlass => true, + crate::BlockKind::CyanStainedGlassPane => true, + crate::BlockKind::CyanTerracotta => true, + crate::BlockKind::CyanWallBanner => true, + crate::BlockKind::CyanWool => true, + crate::BlockKind::DamagedAnvil => true, + crate::BlockKind::Dandelion => true, + crate::BlockKind::DarkOakButton => true, + crate::BlockKind::DarkOakDoor => true, + crate::BlockKind::DarkOakFence => true, + crate::BlockKind::DarkOakFenceGate => true, + crate::BlockKind::DarkOakLeaves => true, + crate::BlockKind::DarkOakLog => true, + crate::BlockKind::DarkOakPlanks => true, + crate::BlockKind::DarkOakPressurePlate => true, + crate::BlockKind::DarkOakSapling => true, + crate::BlockKind::DarkOakSlab => true, + crate::BlockKind::DarkOakStairs => true, + crate::BlockKind::DarkOakTrapdoor => true, + crate::BlockKind::DarkOakWood => true, + crate::BlockKind::DarkPrismarine => true, + crate::BlockKind::DarkPrismarineSlab => true, + crate::BlockKind::DarkPrismarineStairs => true, + crate::BlockKind::DaylightDetector => true, + crate::BlockKind::DeadBrainCoral => true, + crate::BlockKind::DeadBrainCoralBlock => true, + crate::BlockKind::DeadBrainCoralFan => true, + crate::BlockKind::DeadBrainCoralWallFan => true, + crate::BlockKind::DeadBubbleCoral => true, + crate::BlockKind::DeadBubbleCoralBlock => true, + crate::BlockKind::DeadBubbleCoralFan => true, + crate::BlockKind::DeadBubbleCoralWallFan => true, + crate::BlockKind::DeadBush => true, + crate::BlockKind::DeadFireCoral => true, + crate::BlockKind::DeadFireCoralBlock => true, + crate::BlockKind::DeadFireCoralFan => true, + crate::BlockKind::DeadFireCoralWallFan => true, + crate::BlockKind::DeadHornCoral => true, + crate::BlockKind::DeadHornCoralBlock => true, + crate::BlockKind::DeadHornCoralFan => true, + crate::BlockKind::DeadHornCoralWallFan => true, + crate::BlockKind::DeadTubeCoral => true, + crate::BlockKind::DeadTubeCoralBlock => true, + crate::BlockKind::DeadTubeCoralFan => true, + crate::BlockKind::DeadTubeCoralWallFan => true, + crate::BlockKind::DetectorRail => true, + crate::BlockKind::DiamondBlock => true, + crate::BlockKind::DiamondOre => true, + crate::BlockKind::Diorite => true, + crate::BlockKind::Dirt => true, + crate::BlockKind::Dispenser => true, + crate::BlockKind::DragonEgg => true, + crate::BlockKind::DragonHead => true, + crate::BlockKind::DragonWallHead => true, + crate::BlockKind::DriedKelpBlock => true, + crate::BlockKind::Dropper => true, + crate::BlockKind::EmeraldBlock => true, + crate::BlockKind::EmeraldOre => true, + crate::BlockKind::EnchantingTable => true, + crate::BlockKind::EndGateway => false, + crate::BlockKind::EndPortal => false, + crate::BlockKind::EndPortalFrame => false, + crate::BlockKind::EndRod => true, + crate::BlockKind::EndStone => true, + crate::BlockKind::EndStoneBricks => true, + crate::BlockKind::EnderChest => true, + crate::BlockKind::Farmland => true, + crate::BlockKind::Fern => true, + crate::BlockKind::Fire => true, + crate::BlockKind::FireCoral => true, + crate::BlockKind::FireCoralBlock => true, + crate::BlockKind::FireCoralFan => true, + crate::BlockKind::FireCoralWallFan => true, + crate::BlockKind::FlowerPot => true, + crate::BlockKind::FrostedIce => true, + crate::BlockKind::Furnace => true, + crate::BlockKind::Glass => true, + crate::BlockKind::GlassPane => true, + crate::BlockKind::Glowstone => true, + crate::BlockKind::GoldBlock => true, + crate::BlockKind::GoldOre => true, + crate::BlockKind::Granite => true, + crate::BlockKind::Grass => true, + crate::BlockKind::GrassBlock => true, + crate::BlockKind::GrassPath => true, + crate::BlockKind::Gravel => true, + crate::BlockKind::GrayBanner => true, + crate::BlockKind::GrayBed => true, + crate::BlockKind::GrayCarpet => true, + crate::BlockKind::GrayConcrete => true, + crate::BlockKind::GrayConcretePowder => true, + crate::BlockKind::GrayGlazedTerracotta => true, + crate::BlockKind::GrayShulkerBox => true, + crate::BlockKind::GrayStainedGlass => true, + crate::BlockKind::GrayStainedGlassPane => true, + crate::BlockKind::GrayTerracotta => true, + crate::BlockKind::GrayWallBanner => true, + crate::BlockKind::GrayWool => true, + crate::BlockKind::GreenBanner => true, + crate::BlockKind::GreenBed => true, + crate::BlockKind::GreenCarpet => true, + crate::BlockKind::GreenConcrete => true, + crate::BlockKind::GreenConcretePowder => true, + crate::BlockKind::GreenGlazedTerracotta => true, + crate::BlockKind::GreenShulkerBox => true, + crate::BlockKind::GreenStainedGlass => true, + crate::BlockKind::GreenStainedGlassPane => true, + crate::BlockKind::GreenTerracotta => true, + crate::BlockKind::GreenWallBanner => true, + crate::BlockKind::GreenWool => true, + crate::BlockKind::HayBlock => true, + crate::BlockKind::HeavyWeightedPressurePlate => true, + crate::BlockKind::Hopper => true, + crate::BlockKind::HornCoral => true, + crate::BlockKind::HornCoralBlock => true, + crate::BlockKind::HornCoralFan => true, + crate::BlockKind::HornCoralWallFan => true, + crate::BlockKind::Ice => true, + crate::BlockKind::InfestedChiseledStoneBricks => true, + crate::BlockKind::InfestedCobblestone => true, + crate::BlockKind::InfestedCrackedStoneBricks => true, + crate::BlockKind::InfestedMossyStoneBricks => true, + crate::BlockKind::InfestedStone => true, + crate::BlockKind::InfestedStoneBricks => true, + crate::BlockKind::IronBars => true, + crate::BlockKind::IronBlock => true, + crate::BlockKind::IronDoor => true, + crate::BlockKind::IronOre => true, + crate::BlockKind::IronTrapdoor => true, + crate::BlockKind::JackOLantern => true, + crate::BlockKind::Jukebox => true, + crate::BlockKind::JungleButton => true, + crate::BlockKind::JungleDoor => true, + crate::BlockKind::JungleFence => true, + crate::BlockKind::JungleFenceGate => true, + crate::BlockKind::JungleLeaves => true, + crate::BlockKind::JungleLog => true, + crate::BlockKind::JunglePlanks => true, + crate::BlockKind::JunglePressurePlate => true, + crate::BlockKind::JungleSapling => true, + crate::BlockKind::JungleSlab => true, + crate::BlockKind::JungleStairs => true, + crate::BlockKind::JungleTrapdoor => true, + crate::BlockKind::JungleWood => true, + crate::BlockKind::Kelp => true, + crate::BlockKind::KelpPlant => true, + crate::BlockKind::Ladder => true, + crate::BlockKind::LapisBlock => true, + crate::BlockKind::LapisOre => true, + crate::BlockKind::LargeFern => true, + crate::BlockKind::Lava => false, + crate::BlockKind::Lever => true, + crate::BlockKind::LightBlueBanner => true, + crate::BlockKind::LightBlueBed => true, + crate::BlockKind::LightBlueCarpet => true, + crate::BlockKind::LightBlueConcrete => true, + crate::BlockKind::LightBlueConcretePowder => true, + crate::BlockKind::LightBlueGlazedTerracotta => true, + crate::BlockKind::LightBlueShulkerBox => true, + crate::BlockKind::LightBlueStainedGlass => true, + crate::BlockKind::LightBlueStainedGlassPane => true, + crate::BlockKind::LightBlueTerracotta => true, + crate::BlockKind::LightBlueWallBanner => true, + crate::BlockKind::LightBlueWool => true, + crate::BlockKind::LightGrayBanner => true, + crate::BlockKind::LightGrayBed => true, + crate::BlockKind::LightGrayCarpet => true, + crate::BlockKind::LightGrayConcrete => true, + crate::BlockKind::LightGrayConcretePowder => true, + crate::BlockKind::LightGrayGlazedTerracotta => true, + crate::BlockKind::LightGrayShulkerBox => true, + crate::BlockKind::LightGrayStainedGlass => true, + crate::BlockKind::LightGrayStainedGlassPane => true, + crate::BlockKind::LightGrayTerracotta => true, + crate::BlockKind::LightGrayWallBanner => true, + crate::BlockKind::LightGrayWool => true, + crate::BlockKind::LightWeightedPressurePlate => true, + crate::BlockKind::Lilac => true, + crate::BlockKind::LilyPad => true, + crate::BlockKind::LimeBanner => true, + crate::BlockKind::LimeBed => true, + crate::BlockKind::LimeCarpet => true, + crate::BlockKind::LimeConcrete => true, + crate::BlockKind::LimeConcretePowder => true, + crate::BlockKind::LimeGlazedTerracotta => true, + crate::BlockKind::LimeShulkerBox => true, + crate::BlockKind::LimeStainedGlass => true, + crate::BlockKind::LimeStainedGlassPane => true, + crate::BlockKind::LimeTerracotta => true, + crate::BlockKind::LimeWallBanner => true, + crate::BlockKind::LimeWool => true, + crate::BlockKind::MagentaBanner => true, + crate::BlockKind::MagentaBed => true, + crate::BlockKind::MagentaCarpet => true, + crate::BlockKind::MagentaConcrete => true, + crate::BlockKind::MagentaConcretePowder => true, + crate::BlockKind::MagentaGlazedTerracotta => true, + crate::BlockKind::MagentaShulkerBox => true, + crate::BlockKind::MagentaStainedGlass => true, + crate::BlockKind::MagentaStainedGlassPane => true, + crate::BlockKind::MagentaTerracotta => true, + crate::BlockKind::MagentaWallBanner => true, + crate::BlockKind::MagentaWool => true, + crate::BlockKind::MagmaBlock => true, + crate::BlockKind::Melon => true, + crate::BlockKind::MelonStem => true, + crate::BlockKind::MossyCobblestone => true, + crate::BlockKind::MossyCobblestoneWall => true, + crate::BlockKind::MossyStoneBricks => true, + crate::BlockKind::MovingPiston => false, + crate::BlockKind::MushroomStem => true, + crate::BlockKind::Mycelium => true, + crate::BlockKind::NetherBrickFence => true, + crate::BlockKind::NetherBrickSlab => true, + crate::BlockKind::NetherBrickStairs => true, + crate::BlockKind::NetherBricks => true, + crate::BlockKind::NetherPortal => false, + crate::BlockKind::NetherQuartzOre => true, + crate::BlockKind::NetherWart => true, + crate::BlockKind::NetherWartBlock => true, + crate::BlockKind::Netherrack => true, + crate::BlockKind::NoteBlock => true, + crate::BlockKind::OakButton => true, + crate::BlockKind::OakDoor => true, + crate::BlockKind::OakFence => true, + crate::BlockKind::OakFenceGate => true, + crate::BlockKind::OakLeaves => true, + crate::BlockKind::OakLog => true, + crate::BlockKind::OakPlanks => true, + crate::BlockKind::OakPressurePlate => true, + crate::BlockKind::OakSapling => true, + crate::BlockKind::OakSlab => true, + crate::BlockKind::OakStairs => true, + crate::BlockKind::OakTrapdoor => true, + crate::BlockKind::OakWood => true, + crate::BlockKind::Observer => true, + crate::BlockKind::Obsidian => true, + crate::BlockKind::OrangeBanner => true, + crate::BlockKind::OrangeBed => true, + crate::BlockKind::OrangeCarpet => true, + crate::BlockKind::OrangeConcrete => true, + crate::BlockKind::OrangeConcretePowder => true, + crate::BlockKind::OrangeGlazedTerracotta => true, + crate::BlockKind::OrangeShulkerBox => true, + crate::BlockKind::OrangeStainedGlass => true, + crate::BlockKind::OrangeStainedGlassPane => true, + crate::BlockKind::OrangeTerracotta => true, + crate::BlockKind::OrangeTulip => true, + crate::BlockKind::OrangeWallBanner => true, + crate::BlockKind::OrangeWool => true, + crate::BlockKind::OxeyeDaisy => true, + crate::BlockKind::PackedIce => true, + crate::BlockKind::Peony => true, + crate::BlockKind::PetrifiedOakSlab => true, + crate::BlockKind::PinkBanner => true, + crate::BlockKind::PinkBed => true, + crate::BlockKind::PinkCarpet => true, + crate::BlockKind::PinkConcrete => true, + crate::BlockKind::PinkConcretePowder => true, + crate::BlockKind::PinkGlazedTerracotta => true, + crate::BlockKind::PinkShulkerBox => true, + crate::BlockKind::PinkStainedGlass => true, + crate::BlockKind::PinkStainedGlassPane => true, + crate::BlockKind::PinkTerracotta => true, + crate::BlockKind::PinkTulip => true, + crate::BlockKind::PinkWallBanner => true, + crate::BlockKind::PinkWool => true, + crate::BlockKind::Piston => true, + crate::BlockKind::PistonHead => true, + crate::BlockKind::PlayerHead => true, + crate::BlockKind::PlayerWallHead => true, + crate::BlockKind::Podzol => true, + crate::BlockKind::PolishedAndesite => true, + crate::BlockKind::PolishedDiorite => true, + crate::BlockKind::PolishedGranite => true, + crate::BlockKind::Poppy => true, + crate::BlockKind::Potatoes => true, + crate::BlockKind::PottedAcaciaSapling => true, + crate::BlockKind::PottedAllium => true, + crate::BlockKind::PottedAzureBluet => true, + crate::BlockKind::PottedBirchSapling => true, + crate::BlockKind::PottedBlueOrchid => true, + crate::BlockKind::PottedBrownMushroom => true, + crate::BlockKind::PottedCactus => true, + crate::BlockKind::PottedDandelion => true, + crate::BlockKind::PottedDarkOakSapling => true, + crate::BlockKind::PottedDeadBush => true, + crate::BlockKind::PottedFern => true, + crate::BlockKind::PottedJungleSapling => true, + crate::BlockKind::PottedOakSapling => true, + crate::BlockKind::PottedOrangeTulip => true, + crate::BlockKind::PottedOxeyeDaisy => true, + crate::BlockKind::PottedPinkTulip => true, + crate::BlockKind::PottedPoppy => true, + crate::BlockKind::PottedRedMushroom => true, + crate::BlockKind::PottedRedTulip => true, + crate::BlockKind::PottedSpruceSapling => true, + crate::BlockKind::PottedWhiteTulip => true, + crate::BlockKind::PoweredRail => true, + crate::BlockKind::Prismarine => true, + crate::BlockKind::PrismarineBrickSlab => true, + crate::BlockKind::PrismarineBrickStairs => true, + crate::BlockKind::PrismarineBricks => true, + crate::BlockKind::PrismarineSlab => true, + crate::BlockKind::PrismarineStairs => true, + crate::BlockKind::Pumpkin => true, + crate::BlockKind::PumpkinStem => true, + crate::BlockKind::PurpleBanner => true, + crate::BlockKind::PurpleBed => true, + crate::BlockKind::PurpleCarpet => true, + crate::BlockKind::PurpleConcrete => true, + crate::BlockKind::PurpleConcretePowder => true, + crate::BlockKind::PurpleGlazedTerracotta => true, + crate::BlockKind::PurpleShulkerBox => true, + crate::BlockKind::PurpleStainedGlass => true, + crate::BlockKind::PurpleStainedGlassPane => true, + crate::BlockKind::PurpleTerracotta => true, + crate::BlockKind::PurpleWallBanner => true, + crate::BlockKind::PurpleWool => true, + crate::BlockKind::PurpurBlock => true, + crate::BlockKind::PurpurPillar => true, + crate::BlockKind::PurpurSlab => true, + crate::BlockKind::PurpurStairs => true, + crate::BlockKind::QuartzBlock => true, + crate::BlockKind::QuartzPillar => true, + crate::BlockKind::QuartzSlab => true, + crate::BlockKind::QuartzStairs => true, + crate::BlockKind::Rail => true, + crate::BlockKind::RedBanner => true, + crate::BlockKind::RedBed => true, + crate::BlockKind::RedCarpet => true, + crate::BlockKind::RedConcrete => true, + crate::BlockKind::RedConcretePowder => true, + crate::BlockKind::RedGlazedTerracotta => true, + crate::BlockKind::RedMushroom => true, + crate::BlockKind::RedMushroomBlock => true, + crate::BlockKind::RedNetherBricks => true, + crate::BlockKind::RedSand => true, + crate::BlockKind::RedSandstone => true, + crate::BlockKind::RedSandstoneSlab => true, + crate::BlockKind::RedSandstoneStairs => true, + crate::BlockKind::RedShulkerBox => true, + crate::BlockKind::RedStainedGlass => true, + crate::BlockKind::RedStainedGlassPane => true, + crate::BlockKind::RedTerracotta => true, + crate::BlockKind::RedTulip => true, + crate::BlockKind::RedWallBanner => true, + crate::BlockKind::RedWool => true, + crate::BlockKind::RedstoneBlock => true, + crate::BlockKind::RedstoneLamp => true, + crate::BlockKind::RedstoneOre => true, + crate::BlockKind::RedstoneTorch => true, + crate::BlockKind::RedstoneWallTorch => true, + crate::BlockKind::RedstoneWire => true, + crate::BlockKind::Repeater => true, + crate::BlockKind::RepeatingCommandBlock => false, + crate::BlockKind::RoseBush => true, + crate::BlockKind::Sand => true, + crate::BlockKind::Sandstone => true, + crate::BlockKind::SandstoneSlab => true, + crate::BlockKind::SandstoneStairs => true, + crate::BlockKind::SeaLantern => true, + crate::BlockKind::SeaPickle => true, + crate::BlockKind::Seagrass => true, + crate::BlockKind::ShulkerBox => true, + crate::BlockKind::Sign => true, + crate::BlockKind::SkeletonSkull => true, + crate::BlockKind::SkeletonWallSkull => true, + crate::BlockKind::SlimeBlock => true, + crate::BlockKind::SmoothQuartz => true, + crate::BlockKind::SmoothRedSandstone => true, + crate::BlockKind::SmoothSandstone => true, + crate::BlockKind::SmoothStone => true, + crate::BlockKind::Snow => true, + crate::BlockKind::SnowBlock => true, + crate::BlockKind::SoulSand => true, + crate::BlockKind::Spawner => true, + crate::BlockKind::Sponge => true, + crate::BlockKind::SpruceButton => true, + crate::BlockKind::SpruceDoor => true, + crate::BlockKind::SpruceFence => true, + crate::BlockKind::SpruceFenceGate => true, + crate::BlockKind::SpruceLeaves => true, + crate::BlockKind::SpruceLog => true, + crate::BlockKind::SprucePlanks => true, + crate::BlockKind::SprucePressurePlate => true, + crate::BlockKind::SpruceSapling => true, + crate::BlockKind::SpruceSlab => true, + crate::BlockKind::SpruceStairs => true, + crate::BlockKind::SpruceTrapdoor => true, + crate::BlockKind::SpruceWood => true, + crate::BlockKind::StickyPiston => true, + crate::BlockKind::Stone => true, + crate::BlockKind::StoneBrickSlab => true, + crate::BlockKind::StoneBrickStairs => true, + crate::BlockKind::StoneBricks => true, + crate::BlockKind::StoneButton => true, + crate::BlockKind::StonePressurePlate => true, + crate::BlockKind::StoneSlab => true, + crate::BlockKind::StrippedAcaciaLog => true, + crate::BlockKind::StrippedAcaciaWood => true, + crate::BlockKind::StrippedBirchLog => true, + crate::BlockKind::StrippedBirchWood => true, + crate::BlockKind::StrippedDarkOakLog => true, + crate::BlockKind::StrippedDarkOakWood => true, + crate::BlockKind::StrippedJungleLog => true, + crate::BlockKind::StrippedJungleWood => true, + crate::BlockKind::StrippedOakLog => true, + crate::BlockKind::StrippedOakWood => true, + crate::BlockKind::StrippedSpruceLog => true, + crate::BlockKind::StrippedSpruceWood => true, + crate::BlockKind::StructureBlock => false, + crate::BlockKind::StructureVoid => true, + crate::BlockKind::SugarCane => true, + crate::BlockKind::Sunflower => true, + crate::BlockKind::TallGrass => true, + crate::BlockKind::TallSeagrass => true, + crate::BlockKind::Terracotta => true, + crate::BlockKind::Tnt => true, + crate::BlockKind::Torch => true, + crate::BlockKind::TrappedChest => true, + crate::BlockKind::Tripwire => true, + crate::BlockKind::TripwireHook => true, + crate::BlockKind::TubeCoral => true, + crate::BlockKind::TubeCoralBlock => true, + crate::BlockKind::TubeCoralFan => true, + crate::BlockKind::TubeCoralWallFan => true, + crate::BlockKind::TurtleEgg => true, + crate::BlockKind::Vine => true, + crate::BlockKind::VoidAir => true, + crate::BlockKind::WallSign => true, + crate::BlockKind::WallTorch => true, + crate::BlockKind::Water => false, + crate::BlockKind::WetSponge => true, + crate::BlockKind::Wheat => true, + crate::BlockKind::WhiteBanner => true, + crate::BlockKind::WhiteBed => true, + crate::BlockKind::WhiteCarpet => true, + crate::BlockKind::WhiteConcrete => true, + crate::BlockKind::WhiteConcretePowder => true, + crate::BlockKind::WhiteGlazedTerracotta => true, + crate::BlockKind::WhiteShulkerBox => true, + crate::BlockKind::WhiteStainedGlass => true, + crate::BlockKind::WhiteStainedGlassPane => true, + crate::BlockKind::WhiteTerracotta => true, + crate::BlockKind::WhiteTulip => true, + crate::BlockKind::WhiteWallBanner => true, + crate::BlockKind::WhiteWool => true, + crate::BlockKind::WitherSkeletonSkull => true, + crate::BlockKind::WitherSkeletonWallSkull => true, + crate::BlockKind::YellowBanner => true, + crate::BlockKind::YellowBed => true, + crate::BlockKind::YellowCarpet => true, + crate::BlockKind::YellowConcrete => true, + crate::BlockKind::YellowConcretePowder => true, + crate::BlockKind::YellowGlazedTerracotta => true, + crate::BlockKind::YellowShulkerBox => true, + crate::BlockKind::YellowStainedGlass => true, + crate::BlockKind::YellowStainedGlassPane => true, + crate::BlockKind::YellowTerracotta => true, + crate::BlockKind::YellowWallBanner => true, + crate::BlockKind::YellowWool => true, + crate::BlockKind::ZombieHead => true, + crate::BlockKind::ZombieWallHead => true, + _ => false, + } + } +} +impl crate::BlockKind { + pub fn hardness(self) -> f64 { + match self { + crate::BlockKind::AcaciaButton => 0.5f64, + crate::BlockKind::AcaciaDoor => 3f64, + crate::BlockKind::AcaciaFence => 2f64, + crate::BlockKind::AcaciaFenceGate => 2f64, + crate::BlockKind::AcaciaLeaves => 0.2f64, + crate::BlockKind::AcaciaLog => 2f64, + crate::BlockKind::AcaciaPlanks => 2f64, + crate::BlockKind::AcaciaPressurePlate => 0.5f64, + crate::BlockKind::AcaciaSapling => 0f64, + crate::BlockKind::AcaciaSlab => 2f64, + crate::BlockKind::AcaciaStairs => 2f64, + crate::BlockKind::AcaciaTrapdoor => 3f64, + crate::BlockKind::AcaciaWood => 2f64, + crate::BlockKind::ActivatorRail => 0.7f64, + crate::BlockKind::Air => 0f64, + crate::BlockKind::Allium => 0f64, + crate::BlockKind::Andesite => 1.5f64, + crate::BlockKind::Anvil => 5f64, + crate::BlockKind::AttachedMelonStem => 0f64, + crate::BlockKind::AttachedPumpkinStem => 0f64, + crate::BlockKind::AzureBluet => 0f64, + crate::BlockKind::Barrier => 0f64, + crate::BlockKind::Beacon => 3f64, + crate::BlockKind::Bedrock => 0f64, + crate::BlockKind::Beetroots => 0f64, + crate::BlockKind::BirchButton => 0.5f64, + crate::BlockKind::BirchDoor => 3f64, + crate::BlockKind::BirchFence => 2f64, + crate::BlockKind::BirchFenceGate => 2f64, + crate::BlockKind::BirchLeaves => 0.2f64, + crate::BlockKind::BirchLog => 2f64, + crate::BlockKind::BirchPlanks => 2f64, + crate::BlockKind::BirchPressurePlate => 0.5f64, + crate::BlockKind::BirchSapling => 0f64, + crate::BlockKind::BirchSlab => 2f64, + crate::BlockKind::BirchStairs => 2f64, + crate::BlockKind::BirchTrapdoor => 3f64, + crate::BlockKind::BirchWood => 2f64, + crate::BlockKind::BlackBanner => 1f64, + crate::BlockKind::BlackBed => 0.2f64, + crate::BlockKind::BlackCarpet => 0.1f64, + crate::BlockKind::BlackConcrete => 1.8f64, + crate::BlockKind::BlackConcretePowder => 0.5f64, + crate::BlockKind::BlackGlazedTerracotta => 1.4f64, + crate::BlockKind::BlackShulkerBox => 2f64, + crate::BlockKind::BlackStainedGlass => 0.3f64, + crate::BlockKind::BlackStainedGlassPane => 0.3f64, + crate::BlockKind::BlackTerracotta => 1.25f64, + crate::BlockKind::BlackWallBanner => 1f64, + crate::BlockKind::BlackWool => 0.8f64, + crate::BlockKind::BlueBanner => 1f64, + crate::BlockKind::BlueBed => 0.2f64, + crate::BlockKind::BlueCarpet => 0.1f64, + crate::BlockKind::BlueConcrete => 1.8f64, + crate::BlockKind::BlueConcretePowder => 0.5f64, + crate::BlockKind::BlueGlazedTerracotta => 1.4f64, + crate::BlockKind::BlueIce => 2.8f64, + crate::BlockKind::BlueOrchid => 0f64, + crate::BlockKind::BlueShulkerBox => 2f64, + crate::BlockKind::BlueStainedGlass => 0.3f64, + crate::BlockKind::BlueStainedGlassPane => 0.3f64, + crate::BlockKind::BlueTerracotta => 1.25f64, + crate::BlockKind::BlueWallBanner => 1f64, + crate::BlockKind::BlueWool => 0.8f64, + crate::BlockKind::BoneBlock => 2f64, + crate::BlockKind::Bookshelf => 1.5f64, + crate::BlockKind::BrainCoral => 0f64, + crate::BlockKind::BrainCoralBlock => 1.5f64, + crate::BlockKind::BrainCoralFan => 0f64, + crate::BlockKind::BrainCoralWallFan => 0f64, + crate::BlockKind::BrewingStand => 0.5f64, + crate::BlockKind::BrickSlab => 2f64, + crate::BlockKind::BrickStairs => 2f64, + crate::BlockKind::Bricks => 2f64, + crate::BlockKind::BrownBanner => 1f64, + crate::BlockKind::BrownBed => 0.2f64, + crate::BlockKind::BrownCarpet => 0.1f64, + crate::BlockKind::BrownConcrete => 1.8f64, + crate::BlockKind::BrownConcretePowder => 0.5f64, + crate::BlockKind::BrownGlazedTerracotta => 1.4f64, + crate::BlockKind::BrownMushroom => 0f64, + crate::BlockKind::BrownMushroomBlock => 0.2f64, + crate::BlockKind::BrownShulkerBox => 2f64, + crate::BlockKind::BrownStainedGlass => 0.3f64, + crate::BlockKind::BrownStainedGlassPane => 0.3f64, + crate::BlockKind::BrownTerracotta => 1.25f64, + crate::BlockKind::BrownWallBanner => 1f64, + crate::BlockKind::BrownWool => 0.8f64, + crate::BlockKind::BubbleColumn => 0f64, + crate::BlockKind::BubbleCoral => 0f64, + crate::BlockKind::BubbleCoralBlock => 1.5f64, + crate::BlockKind::BubbleCoralFan => 0f64, + crate::BlockKind::BubbleCoralWallFan => 0f64, + crate::BlockKind::Cactus => 0.4f64, + crate::BlockKind::Cake => 0.5f64, + crate::BlockKind::Carrots => 0f64, + crate::BlockKind::CarvedPumpkin => 1f64, + crate::BlockKind::Cauldron => 2f64, + crate::BlockKind::CaveAir => 0f64, + crate::BlockKind::ChainCommandBlock => 0f64, + crate::BlockKind::Chest => 2.5f64, + crate::BlockKind::ChippedAnvil => 5f64, + crate::BlockKind::ChiseledQuartzBlock => 0.8f64, + crate::BlockKind::ChiseledRedSandstone => 0.8f64, + crate::BlockKind::ChiseledSandstone => 0.8f64, + crate::BlockKind::ChiseledStoneBricks => 1.5f64, + crate::BlockKind::ChorusFlower => 0.4f64, + crate::BlockKind::ChorusPlant => 0.4f64, + crate::BlockKind::Clay => 0.6f64, + crate::BlockKind::CoalBlock => 5f64, + crate::BlockKind::CoalOre => 3f64, + crate::BlockKind::CoarseDirt => 0.5f64, + crate::BlockKind::Cobblestone => 2f64, + crate::BlockKind::CobblestoneSlab => 2f64, + crate::BlockKind::CobblestoneStairs => 2f64, + crate::BlockKind::CobblestoneWall => 2f64, + crate::BlockKind::Cobweb => 4f64, + crate::BlockKind::Cocoa => 0.2f64, + crate::BlockKind::CommandBlock => 0f64, + crate::BlockKind::Comparator => 0f64, + crate::BlockKind::Conduit => 3f64, + crate::BlockKind::CrackedStoneBricks => 1.5f64, + crate::BlockKind::CraftingTable => 2.5f64, + crate::BlockKind::CreeperHead => 1f64, + crate::BlockKind::CreeperWallHead => 1f64, + crate::BlockKind::CutRedSandstone => 0.8f64, + crate::BlockKind::CutSandstone => 0.8f64, + crate::BlockKind::CyanBanner => 1f64, + crate::BlockKind::CyanBed => 0.2f64, + crate::BlockKind::CyanCarpet => 0.1f64, + crate::BlockKind::CyanConcrete => 1.8f64, + crate::BlockKind::CyanConcretePowder => 0.5f64, + crate::BlockKind::CyanGlazedTerracotta => 1.4f64, + crate::BlockKind::CyanShulkerBox => 2f64, + crate::BlockKind::CyanStainedGlass => 0.3f64, + crate::BlockKind::CyanStainedGlassPane => 0.3f64, + crate::BlockKind::CyanTerracotta => 1.25f64, + crate::BlockKind::CyanWallBanner => 1f64, + crate::BlockKind::CyanWool => 0.8f64, + crate::BlockKind::DamagedAnvil => 5f64, + crate::BlockKind::Dandelion => 0f64, + crate::BlockKind::DarkOakButton => 0.5f64, + crate::BlockKind::DarkOakDoor => 3f64, + crate::BlockKind::DarkOakFence => 2f64, + crate::BlockKind::DarkOakFenceGate => 2f64, + crate::BlockKind::DarkOakLeaves => 0.2f64, + crate::BlockKind::DarkOakLog => 2f64, + crate::BlockKind::DarkOakPlanks => 2f64, + crate::BlockKind::DarkOakPressurePlate => 0.5f64, + crate::BlockKind::DarkOakSapling => 0f64, + crate::BlockKind::DarkOakSlab => 2f64, + crate::BlockKind::DarkOakStairs => 2f64, + crate::BlockKind::DarkOakTrapdoor => 3f64, + crate::BlockKind::DarkOakWood => 2f64, + crate::BlockKind::DarkPrismarine => 1.5f64, + crate::BlockKind::DarkPrismarineSlab => 1.5f64, + crate::BlockKind::DarkPrismarineStairs => 1.5f64, + crate::BlockKind::DaylightDetector => 0.2f64, + crate::BlockKind::DeadBrainCoral => 0f64, + crate::BlockKind::DeadBrainCoralBlock => 1.5f64, + crate::BlockKind::DeadBrainCoralFan => 0f64, + crate::BlockKind::DeadBrainCoralWallFan => 0f64, + crate::BlockKind::DeadBubbleCoral => 0f64, + crate::BlockKind::DeadBubbleCoralBlock => 1.5f64, + crate::BlockKind::DeadBubbleCoralFan => 0f64, + crate::BlockKind::DeadBubbleCoralWallFan => 0f64, + crate::BlockKind::DeadBush => 0f64, + crate::BlockKind::DeadFireCoral => 0f64, + crate::BlockKind::DeadFireCoralBlock => 1.5f64, + crate::BlockKind::DeadFireCoralFan => 0f64, + crate::BlockKind::DeadFireCoralWallFan => 0f64, + crate::BlockKind::DeadHornCoral => 0f64, + crate::BlockKind::DeadHornCoralBlock => 1.5f64, + crate::BlockKind::DeadHornCoralFan => 0f64, + crate::BlockKind::DeadHornCoralWallFan => 0f64, + crate::BlockKind::DeadTubeCoral => 0f64, + crate::BlockKind::DeadTubeCoralBlock => 1.5f64, + crate::BlockKind::DeadTubeCoralFan => 0f64, + crate::BlockKind::DeadTubeCoralWallFan => 0f64, + crate::BlockKind::DetectorRail => 0.7f64, + crate::BlockKind::DiamondBlock => 5f64, + crate::BlockKind::DiamondOre => 3f64, + crate::BlockKind::Diorite => 1.5f64, + crate::BlockKind::Dirt => 0.5f64, + crate::BlockKind::Dispenser => 3.5f64, + crate::BlockKind::DragonEgg => 3f64, + crate::BlockKind::DragonHead => 1f64, + crate::BlockKind::DragonWallHead => 1f64, + crate::BlockKind::DriedKelpBlock => 0.5f64, + crate::BlockKind::Dropper => 3.5f64, + crate::BlockKind::EmeraldBlock => 5f64, + crate::BlockKind::EmeraldOre => 3f64, + crate::BlockKind::EnchantingTable => 5f64, + crate::BlockKind::EndGateway => 0f64, + crate::BlockKind::EndPortal => 0f64, + crate::BlockKind::EndPortalFrame => 0f64, + crate::BlockKind::EndRod => 0f64, + crate::BlockKind::EndStone => 3f64, + crate::BlockKind::EndStoneBricks => 0.8f64, + crate::BlockKind::EnderChest => 22.5f64, + crate::BlockKind::Farmland => 0.6f64, + crate::BlockKind::Fern => 0f64, + crate::BlockKind::Fire => 0f64, + crate::BlockKind::FireCoral => 0f64, + crate::BlockKind::FireCoralBlock => 1.5f64, + crate::BlockKind::FireCoralFan => 0f64, + crate::BlockKind::FireCoralWallFan => 0f64, + crate::BlockKind::FlowerPot => 0f64, + crate::BlockKind::FrostedIce => 0.5f64, + crate::BlockKind::Furnace => 3.5f64, + crate::BlockKind::Glass => 0.3f64, + crate::BlockKind::GlassPane => 0.3f64, + crate::BlockKind::Glowstone => 0.3f64, + crate::BlockKind::GoldBlock => 3f64, + crate::BlockKind::GoldOre => 3f64, + crate::BlockKind::Granite => 1.5f64, + crate::BlockKind::Grass => 0f64, + crate::BlockKind::GrassBlock => 0.6f64, + crate::BlockKind::GrassPath => 0.65f64, + crate::BlockKind::Gravel => 0.6f64, + crate::BlockKind::GrayBanner => 1f64, + crate::BlockKind::GrayBed => 0.2f64, + crate::BlockKind::GrayCarpet => 0.1f64, + crate::BlockKind::GrayConcrete => 1.8f64, + crate::BlockKind::GrayConcretePowder => 0.5f64, + crate::BlockKind::GrayGlazedTerracotta => 1.4f64, + crate::BlockKind::GrayShulkerBox => 2f64, + crate::BlockKind::GrayStainedGlass => 0.3f64, + crate::BlockKind::GrayStainedGlassPane => 0.3f64, + crate::BlockKind::GrayTerracotta => 1.25f64, + crate::BlockKind::GrayWallBanner => 1f64, + crate::BlockKind::GrayWool => 0.8f64, + crate::BlockKind::GreenBanner => 1f64, + crate::BlockKind::GreenBed => 0.2f64, + crate::BlockKind::GreenCarpet => 0.1f64, + crate::BlockKind::GreenConcrete => 1.8f64, + crate::BlockKind::GreenConcretePowder => 0.5f64, + crate::BlockKind::GreenGlazedTerracotta => 1.4f64, + crate::BlockKind::GreenShulkerBox => 2f64, + crate::BlockKind::GreenStainedGlass => 0.3f64, + crate::BlockKind::GreenStainedGlassPane => 0.3f64, + crate::BlockKind::GreenTerracotta => 1.25f64, + crate::BlockKind::GreenWallBanner => 1f64, + crate::BlockKind::GreenWool => 0.8f64, + crate::BlockKind::HayBlock => 0.5f64, + crate::BlockKind::HeavyWeightedPressurePlate => 0.5f64, + crate::BlockKind::Hopper => 3f64, + crate::BlockKind::HornCoral => 0f64, + crate::BlockKind::HornCoralBlock => 1.5f64, + crate::BlockKind::HornCoralFan => 0f64, + crate::BlockKind::HornCoralWallFan => 0f64, + crate::BlockKind::Ice => 0.5f64, + crate::BlockKind::InfestedChiseledStoneBricks => 0f64, + crate::BlockKind::InfestedCobblestone => 0f64, + crate::BlockKind::InfestedCrackedStoneBricks => 0f64, + crate::BlockKind::InfestedMossyStoneBricks => 0f64, + crate::BlockKind::InfestedStone => 0f64, + crate::BlockKind::InfestedStoneBricks => 0f64, + crate::BlockKind::IronBars => 5f64, + crate::BlockKind::IronBlock => 5f64, + crate::BlockKind::IronDoor => 5f64, + crate::BlockKind::IronOre => 3f64, + crate::BlockKind::IronTrapdoor => 5f64, + crate::BlockKind::JackOLantern => 1f64, + crate::BlockKind::Jukebox => 2f64, + crate::BlockKind::JungleButton => 0.5f64, + crate::BlockKind::JungleDoor => 3f64, + crate::BlockKind::JungleFence => 2f64, + crate::BlockKind::JungleFenceGate => 2f64, + crate::BlockKind::JungleLeaves => 0.2f64, + crate::BlockKind::JungleLog => 2f64, + crate::BlockKind::JunglePlanks => 2f64, + crate::BlockKind::JunglePressurePlate => 0.5f64, + crate::BlockKind::JungleSapling => 0f64, + crate::BlockKind::JungleSlab => 2f64, + crate::BlockKind::JungleStairs => 2f64, + crate::BlockKind::JungleTrapdoor => 3f64, + crate::BlockKind::JungleWood => 2f64, + crate::BlockKind::Kelp => 0f64, + crate::BlockKind::KelpPlant => 0f64, + crate::BlockKind::Ladder => 0.4f64, + crate::BlockKind::LapisBlock => 3f64, + crate::BlockKind::LapisOre => 3f64, + crate::BlockKind::LargeFern => 0f64, + crate::BlockKind::Lava => 100f64, + crate::BlockKind::Lever => 0.5f64, + crate::BlockKind::LightBlueBanner => 1f64, + crate::BlockKind::LightBlueBed => 0.2f64, + crate::BlockKind::LightBlueCarpet => 0.1f64, + crate::BlockKind::LightBlueConcrete => 1.8f64, + crate::BlockKind::LightBlueConcretePowder => 0.5f64, + crate::BlockKind::LightBlueGlazedTerracotta => 1.4f64, + crate::BlockKind::LightBlueShulkerBox => 2f64, + crate::BlockKind::LightBlueStainedGlass => 0.3f64, + crate::BlockKind::LightBlueStainedGlassPane => 0.3f64, + crate::BlockKind::LightBlueTerracotta => 1.25f64, + crate::BlockKind::LightBlueWallBanner => 1f64, + crate::BlockKind::LightBlueWool => 0.8f64, + crate::BlockKind::LightGrayBanner => 1f64, + crate::BlockKind::LightGrayBed => 0.2f64, + crate::BlockKind::LightGrayCarpet => 0.1f64, + crate::BlockKind::LightGrayConcrete => 1.8f64, + crate::BlockKind::LightGrayConcretePowder => 0.5f64, + crate::BlockKind::LightGrayGlazedTerracotta => 1.4f64, + crate::BlockKind::LightGrayShulkerBox => 2f64, + crate::BlockKind::LightGrayStainedGlass => 0.3f64, + crate::BlockKind::LightGrayStainedGlassPane => 0.3f64, + crate::BlockKind::LightGrayTerracotta => 1.25f64, + crate::BlockKind::LightGrayWallBanner => 1f64, + crate::BlockKind::LightGrayWool => 0.8f64, + crate::BlockKind::LightWeightedPressurePlate => 0.5f64, + crate::BlockKind::Lilac => 0f64, + crate::BlockKind::LilyPad => 0f64, + crate::BlockKind::LimeBanner => 1f64, + crate::BlockKind::LimeBed => 0.2f64, + crate::BlockKind::LimeCarpet => 0.1f64, + crate::BlockKind::LimeConcrete => 1.8f64, + crate::BlockKind::LimeConcretePowder => 0.5f64, + crate::BlockKind::LimeGlazedTerracotta => 1.4f64, + crate::BlockKind::LimeShulkerBox => 2f64, + crate::BlockKind::LimeStainedGlass => 0.3f64, + crate::BlockKind::LimeStainedGlassPane => 0.3f64, + crate::BlockKind::LimeTerracotta => 1.25f64, + crate::BlockKind::LimeWallBanner => 1f64, + crate::BlockKind::LimeWool => 0.8f64, + crate::BlockKind::MagentaBanner => 1f64, + crate::BlockKind::MagentaBed => 0.2f64, + crate::BlockKind::MagentaCarpet => 0.1f64, + crate::BlockKind::MagentaConcrete => 1.8f64, + crate::BlockKind::MagentaConcretePowder => 0.5f64, + crate::BlockKind::MagentaGlazedTerracotta => 1.4f64, + crate::BlockKind::MagentaShulkerBox => 2f64, + crate::BlockKind::MagentaStainedGlass => 0.3f64, + crate::BlockKind::MagentaStainedGlassPane => 0.3f64, + crate::BlockKind::MagentaTerracotta => 1.25f64, + crate::BlockKind::MagentaWallBanner => 1f64, + crate::BlockKind::MagentaWool => 0.8f64, + crate::BlockKind::MagmaBlock => 0.5f64, + crate::BlockKind::Melon => 1f64, + crate::BlockKind::MelonStem => 0f64, + crate::BlockKind::MossyCobblestone => 2f64, + crate::BlockKind::MossyCobblestoneWall => 2f64, + crate::BlockKind::MossyStoneBricks => 1.5f64, + crate::BlockKind::MovingPiston => 0f64, + crate::BlockKind::MushroomStem => 0.2f64, + crate::BlockKind::Mycelium => 0.6f64, + crate::BlockKind::NetherBrickFence => 2f64, + crate::BlockKind::NetherBrickSlab => 2f64, + crate::BlockKind::NetherBrickStairs => 2f64, + crate::BlockKind::NetherBricks => 2f64, + crate::BlockKind::NetherPortal => 0f64, + crate::BlockKind::NetherQuartzOre => 3f64, + crate::BlockKind::NetherWart => 0f64, + crate::BlockKind::NetherWartBlock => 1f64, + crate::BlockKind::Netherrack => 0.4f64, + crate::BlockKind::NoteBlock => 0.8f64, + crate::BlockKind::OakButton => 0.5f64, + crate::BlockKind::OakDoor => 3f64, + crate::BlockKind::OakFence => 2f64, + crate::BlockKind::OakFenceGate => 2f64, + crate::BlockKind::OakLeaves => 0.2f64, + crate::BlockKind::OakLog => 2f64, + crate::BlockKind::OakPlanks => 2f64, + crate::BlockKind::OakPressurePlate => 0.5f64, + crate::BlockKind::OakSapling => 0f64, + crate::BlockKind::OakSlab => 2f64, + crate::BlockKind::OakStairs => 2f64, + crate::BlockKind::OakTrapdoor => 3f64, + crate::BlockKind::OakWood => 2f64, + crate::BlockKind::Observer => 3f64, + crate::BlockKind::Obsidian => 50f64, + crate::BlockKind::OrangeBanner => 1f64, + crate::BlockKind::OrangeBed => 0.2f64, + crate::BlockKind::OrangeCarpet => 0.1f64, + crate::BlockKind::OrangeConcrete => 1.8f64, + crate::BlockKind::OrangeConcretePowder => 0.5f64, + crate::BlockKind::OrangeGlazedTerracotta => 1.4f64, + crate::BlockKind::OrangeShulkerBox => 2f64, + crate::BlockKind::OrangeStainedGlass => 0.3f64, + crate::BlockKind::OrangeStainedGlassPane => 0.3f64, + crate::BlockKind::OrangeTerracotta => 1.25f64, + crate::BlockKind::OrangeTulip => 0f64, + crate::BlockKind::OrangeWallBanner => 1f64, + crate::BlockKind::OrangeWool => 0.8f64, + crate::BlockKind::OxeyeDaisy => 0f64, + crate::BlockKind::PackedIce => 0.5f64, + crate::BlockKind::Peony => 0f64, + crate::BlockKind::PetrifiedOakSlab => 2f64, + crate::BlockKind::PinkBanner => 1f64, + crate::BlockKind::PinkBed => 0.2f64, + crate::BlockKind::PinkCarpet => 0.1f64, + crate::BlockKind::PinkConcrete => 1.8f64, + crate::BlockKind::PinkConcretePowder => 0.5f64, + crate::BlockKind::PinkGlazedTerracotta => 1.4f64, + crate::BlockKind::PinkShulkerBox => 2f64, + crate::BlockKind::PinkStainedGlass => 0.3f64, + crate::BlockKind::PinkStainedGlassPane => 0.3f64, + crate::BlockKind::PinkTerracotta => 1.25f64, + crate::BlockKind::PinkTulip => 0f64, + crate::BlockKind::PinkWallBanner => 1f64, + crate::BlockKind::PinkWool => 0.8f64, + crate::BlockKind::Piston => 0.5f64, + crate::BlockKind::PistonHead => 0.5f64, + crate::BlockKind::PlayerHead => 1f64, + crate::BlockKind::PlayerWallHead => 1f64, + crate::BlockKind::Podzol => 0.5f64, + crate::BlockKind::PolishedAndesite => 1.5f64, + crate::BlockKind::PolishedDiorite => 1.5f64, + crate::BlockKind::PolishedGranite => 1.5f64, + crate::BlockKind::Poppy => 0f64, + crate::BlockKind::Potatoes => 0f64, + crate::BlockKind::PottedAcaciaSapling => 0f64, + crate::BlockKind::PottedAllium => 0f64, + crate::BlockKind::PottedAzureBluet => 0f64, + crate::BlockKind::PottedBirchSapling => 0f64, + crate::BlockKind::PottedBlueOrchid => 0f64, + crate::BlockKind::PottedBrownMushroom => 0f64, + crate::BlockKind::PottedCactus => 0f64, + crate::BlockKind::PottedDandelion => 0f64, + crate::BlockKind::PottedDarkOakSapling => 0f64, + crate::BlockKind::PottedDeadBush => 0f64, + crate::BlockKind::PottedFern => 0f64, + crate::BlockKind::PottedJungleSapling => 0f64, + crate::BlockKind::PottedOakSapling => 0f64, + crate::BlockKind::PottedOrangeTulip => 0f64, + crate::BlockKind::PottedOxeyeDaisy => 0f64, + crate::BlockKind::PottedPinkTulip => 0f64, + crate::BlockKind::PottedPoppy => 0f64, + crate::BlockKind::PottedRedMushroom => 0f64, + crate::BlockKind::PottedRedTulip => 0f64, + crate::BlockKind::PottedSpruceSapling => 0f64, + crate::BlockKind::PottedWhiteTulip => 0f64, + crate::BlockKind::PoweredRail => 0.7f64, + crate::BlockKind::Prismarine => 1.5f64, + crate::BlockKind::PrismarineBrickSlab => 1.5f64, + crate::BlockKind::PrismarineBrickStairs => 1.5f64, + crate::BlockKind::PrismarineBricks => 1.5f64, + crate::BlockKind::PrismarineSlab => 1.5f64, + crate::BlockKind::PrismarineStairs => 1.5f64, + crate::BlockKind::Pumpkin => 1f64, + crate::BlockKind::PumpkinStem => 0f64, + crate::BlockKind::PurpleBanner => 1f64, + crate::BlockKind::PurpleBed => 0.2f64, + crate::BlockKind::PurpleCarpet => 0.1f64, + crate::BlockKind::PurpleConcrete => 1.8f64, + crate::BlockKind::PurpleConcretePowder => 0.5f64, + crate::BlockKind::PurpleGlazedTerracotta => 1.4f64, + crate::BlockKind::PurpleShulkerBox => 2f64, + crate::BlockKind::PurpleStainedGlass => 0.3f64, + crate::BlockKind::PurpleStainedGlassPane => 0.3f64, + crate::BlockKind::PurpleTerracotta => 1.25f64, + crate::BlockKind::PurpleWallBanner => 1f64, + crate::BlockKind::PurpleWool => 0.8f64, + crate::BlockKind::PurpurBlock => 1.5f64, + crate::BlockKind::PurpurPillar => 1.5f64, + crate::BlockKind::PurpurSlab => 2f64, + crate::BlockKind::PurpurStairs => 1.5f64, + crate::BlockKind::QuartzBlock => 0.8f64, + crate::BlockKind::QuartzPillar => 0.8f64, + crate::BlockKind::QuartzSlab => 2f64, + crate::BlockKind::QuartzStairs => 0.8f64, + crate::BlockKind::Rail => 0.7f64, + crate::BlockKind::RedBanner => 1f64, + crate::BlockKind::RedBed => 0.2f64, + crate::BlockKind::RedCarpet => 0.1f64, + crate::BlockKind::RedConcrete => 1.8f64, + crate::BlockKind::RedConcretePowder => 0.5f64, + crate::BlockKind::RedGlazedTerracotta => 1.4f64, + crate::BlockKind::RedMushroom => 0f64, + crate::BlockKind::RedMushroomBlock => 0.2f64, + crate::BlockKind::RedNetherBricks => 2f64, + crate::BlockKind::RedSand => 0.5f64, + crate::BlockKind::RedSandstone => 0.8f64, + crate::BlockKind::RedSandstoneSlab => 2f64, + crate::BlockKind::RedSandstoneStairs => 0.8f64, + crate::BlockKind::RedShulkerBox => 2f64, + crate::BlockKind::RedStainedGlass => 0.3f64, + crate::BlockKind::RedStainedGlassPane => 0.3f64, + crate::BlockKind::RedTerracotta => 1.25f64, + crate::BlockKind::RedTulip => 0f64, + crate::BlockKind::RedWallBanner => 1f64, + crate::BlockKind::RedWool => 0.8f64, + crate::BlockKind::RedstoneBlock => 5f64, + crate::BlockKind::RedstoneLamp => 0.3f64, + crate::BlockKind::RedstoneOre => 3f64, + crate::BlockKind::RedstoneTorch => 0f64, + crate::BlockKind::RedstoneWallTorch => 0f64, + crate::BlockKind::RedstoneWire => 0f64, + crate::BlockKind::Repeater => 0f64, + crate::BlockKind::RepeatingCommandBlock => 0f64, + crate::BlockKind::RoseBush => 0f64, + crate::BlockKind::Sand => 0.5f64, + crate::BlockKind::Sandstone => 0.8f64, + crate::BlockKind::SandstoneSlab => 2f64, + crate::BlockKind::SandstoneStairs => 0.8f64, + crate::BlockKind::SeaLantern => 0.3f64, + crate::BlockKind::SeaPickle => 0f64, + crate::BlockKind::Seagrass => 0f64, + crate::BlockKind::ShulkerBox => 2f64, + crate::BlockKind::Sign => 1f64, + crate::BlockKind::SkeletonSkull => 1f64, + crate::BlockKind::SkeletonWallSkull => 1f64, + crate::BlockKind::SlimeBlock => 0f64, + crate::BlockKind::SmoothQuartz => 2f64, + crate::BlockKind::SmoothRedSandstone => 2f64, + crate::BlockKind::SmoothSandstone => 2f64, + crate::BlockKind::SmoothStone => 2f64, + crate::BlockKind::Snow => 0.1f64, + crate::BlockKind::SnowBlock => 0.2f64, + crate::BlockKind::SoulSand => 0.5f64, + crate::BlockKind::Spawner => 5f64, + crate::BlockKind::Sponge => 0.6f64, + crate::BlockKind::SpruceButton => 0.5f64, + crate::BlockKind::SpruceDoor => 3f64, + crate::BlockKind::SpruceFence => 2f64, + crate::BlockKind::SpruceFenceGate => 2f64, + crate::BlockKind::SpruceLeaves => 0.2f64, + crate::BlockKind::SpruceLog => 2f64, + crate::BlockKind::SprucePlanks => 2f64, + crate::BlockKind::SprucePressurePlate => 0.5f64, + crate::BlockKind::SpruceSapling => 0f64, + crate::BlockKind::SpruceSlab => 2f64, + crate::BlockKind::SpruceStairs => 2f64, + crate::BlockKind::SpruceTrapdoor => 3f64, + crate::BlockKind::SpruceWood => 2f64, + crate::BlockKind::StickyPiston => 0.5f64, + crate::BlockKind::Stone => 1.5f64, + crate::BlockKind::StoneBrickSlab => 2f64, + crate::BlockKind::StoneBrickStairs => 1.5f64, + crate::BlockKind::StoneBricks => 1.5f64, + crate::BlockKind::StoneButton => 0.5f64, + crate::BlockKind::StonePressurePlate => 0.5f64, + crate::BlockKind::StoneSlab => 2f64, + crate::BlockKind::StrippedAcaciaLog => 2f64, + crate::BlockKind::StrippedAcaciaWood => 2f64, + crate::BlockKind::StrippedBirchLog => 2f64, + crate::BlockKind::StrippedBirchWood => 2f64, + crate::BlockKind::StrippedDarkOakLog => 2f64, + crate::BlockKind::StrippedDarkOakWood => 2f64, + crate::BlockKind::StrippedJungleLog => 2f64, + crate::BlockKind::StrippedJungleWood => 2f64, + crate::BlockKind::StrippedOakLog => 2f64, + crate::BlockKind::StrippedOakWood => 2f64, + crate::BlockKind::StrippedSpruceLog => 2f64, + crate::BlockKind::StrippedSpruceWood => 2f64, + crate::BlockKind::StructureBlock => 0f64, + crate::BlockKind::StructureVoid => 0f64, + crate::BlockKind::SugarCane => 0f64, + crate::BlockKind::Sunflower => 0f64, + crate::BlockKind::TallGrass => 0f64, + crate::BlockKind::TallSeagrass => 0f64, + crate::BlockKind::Terracotta => 1.25f64, + crate::BlockKind::Tnt => 0f64, + crate::BlockKind::Torch => 0f64, + crate::BlockKind::TrappedChest => 2.5f64, + crate::BlockKind::Tripwire => 0f64, + crate::BlockKind::TripwireHook => 0f64, + crate::BlockKind::TubeCoral => 0f64, + crate::BlockKind::TubeCoralBlock => 1.5f64, + crate::BlockKind::TubeCoralFan => 0f64, + crate::BlockKind::TubeCoralWallFan => 0f64, + crate::BlockKind::TurtleEgg => 0.5f64, + crate::BlockKind::Vine => 0.2f64, + crate::BlockKind::VoidAir => 0f64, + crate::BlockKind::WallSign => 1f64, + crate::BlockKind::WallTorch => 0f64, + crate::BlockKind::Water => 100f64, + crate::BlockKind::WetSponge => 0.6f64, + crate::BlockKind::Wheat => 0f64, + crate::BlockKind::WhiteBanner => 1f64, + crate::BlockKind::WhiteBed => 0.2f64, + crate::BlockKind::WhiteCarpet => 0.1f64, + crate::BlockKind::WhiteConcrete => 1.8f64, + crate::BlockKind::WhiteConcretePowder => 0.5f64, + crate::BlockKind::WhiteGlazedTerracotta => 1.4f64, + crate::BlockKind::WhiteShulkerBox => 2f64, + crate::BlockKind::WhiteStainedGlass => 0.3f64, + crate::BlockKind::WhiteStainedGlassPane => 0.3f64, + crate::BlockKind::WhiteTerracotta => 1.25f64, + crate::BlockKind::WhiteTulip => 0f64, + crate::BlockKind::WhiteWallBanner => 1f64, + crate::BlockKind::WhiteWool => 0.8f64, + crate::BlockKind::WitherSkeletonSkull => 1f64, + crate::BlockKind::WitherSkeletonWallSkull => 1f64, + crate::BlockKind::YellowBanner => 1f64, + crate::BlockKind::YellowBed => 0.2f64, + crate::BlockKind::YellowCarpet => 0.1f64, + crate::BlockKind::YellowConcrete => 1.8f64, + crate::BlockKind::YellowConcretePowder => 0.5f64, + crate::BlockKind::YellowGlazedTerracotta => 1.4f64, + crate::BlockKind::YellowShulkerBox => 2f64, + crate::BlockKind::YellowStainedGlass => 0.3f64, + crate::BlockKind::YellowStainedGlassPane => 0.3f64, + crate::BlockKind::YellowTerracotta => 1.25f64, + crate::BlockKind::YellowWallBanner => 1f64, + crate::BlockKind::YellowWool => 0.8f64, + crate::BlockKind::ZombieHead => 1f64, + crate::BlockKind::ZombieWallHead => 1f64, + } + } +} +impl crate::BlockKind { + pub fn opaque(self) -> bool { + match self { + crate::BlockKind::AcaciaButton => false, + crate::BlockKind::AcaciaDoor => false, + crate::BlockKind::AcaciaFence => false, + crate::BlockKind::AcaciaFenceGate => false, + crate::BlockKind::AcaciaLeaves => false, + crate::BlockKind::AcaciaLog => true, + crate::BlockKind::AcaciaPlanks => true, + crate::BlockKind::AcaciaPressurePlate => false, + crate::BlockKind::AcaciaSapling => false, + crate::BlockKind::AcaciaSlab => false, + crate::BlockKind::AcaciaStairs => false, + crate::BlockKind::AcaciaTrapdoor => false, + crate::BlockKind::AcaciaWood => true, + crate::BlockKind::ActivatorRail => false, + crate::BlockKind::Air => false, + crate::BlockKind::Allium => true, + crate::BlockKind::Andesite => true, + crate::BlockKind::Anvil => false, + crate::BlockKind::AttachedMelonStem => false, + crate::BlockKind::AttachedPumpkinStem => false, + crate::BlockKind::AzureBluet => true, + crate::BlockKind::Barrier => false, + crate::BlockKind::Beacon => false, + crate::BlockKind::Bedrock => true, + crate::BlockKind::Beetroots => false, + crate::BlockKind::BirchButton => false, + crate::BlockKind::BirchDoor => false, + crate::BlockKind::BirchFence => false, + crate::BlockKind::BirchFenceGate => false, + crate::BlockKind::BirchLeaves => false, + crate::BlockKind::BirchLog => true, + crate::BlockKind::BirchPlanks => true, + crate::BlockKind::BirchPressurePlate => false, + crate::BlockKind::BirchSapling => false, + crate::BlockKind::BirchSlab => false, + crate::BlockKind::BirchStairs => false, + crate::BlockKind::BirchTrapdoor => false, + crate::BlockKind::BirchWood => true, + crate::BlockKind::BlackBanner => false, + crate::BlockKind::BlackBed => false, + crate::BlockKind::BlackCarpet => false, + crate::BlockKind::BlackConcrete => true, + crate::BlockKind::BlackConcretePowder => true, + crate::BlockKind::BlackGlazedTerracotta => true, + crate::BlockKind::BlackShulkerBox => false, + crate::BlockKind::BlackStainedGlass => false, + crate::BlockKind::BlackStainedGlassPane => false, + crate::BlockKind::BlackTerracotta => true, + crate::BlockKind::BlackWallBanner => false, + crate::BlockKind::BlackWool => true, + crate::BlockKind::BlueBanner => false, + crate::BlockKind::BlueBed => false, + crate::BlockKind::BlueCarpet => false, + crate::BlockKind::BlueConcrete => true, + crate::BlockKind::BlueConcretePowder => true, + crate::BlockKind::BlueGlazedTerracotta => true, + crate::BlockKind::BlueIce => true, + crate::BlockKind::BlueOrchid => false, + crate::BlockKind::BlueShulkerBox => false, + crate::BlockKind::BlueStainedGlass => false, + crate::BlockKind::BlueStainedGlassPane => false, + crate::BlockKind::BlueTerracotta => true, + crate::BlockKind::BlueWallBanner => false, + crate::BlockKind::BlueWool => true, + crate::BlockKind::BoneBlock => true, + crate::BlockKind::Bookshelf => true, + crate::BlockKind::BrainCoral => false, + crate::BlockKind::BrainCoralBlock => true, + crate::BlockKind::BrainCoralFan => false, + crate::BlockKind::BrainCoralWallFan => false, + crate::BlockKind::BrewingStand => false, + crate::BlockKind::BrickSlab => false, + crate::BlockKind::BrickStairs => false, + crate::BlockKind::Bricks => true, + crate::BlockKind::BrownBanner => false, + crate::BlockKind::BrownBed => false, + crate::BlockKind::BrownCarpet => false, + crate::BlockKind::BrownConcrete => true, + crate::BlockKind::BrownConcretePowder => true, + crate::BlockKind::BrownGlazedTerracotta => true, + crate::BlockKind::BrownMushroom => true, + crate::BlockKind::BrownMushroomBlock => true, + crate::BlockKind::BrownShulkerBox => false, + crate::BlockKind::BrownStainedGlass => false, + crate::BlockKind::BrownStainedGlassPane => false, + crate::BlockKind::BrownTerracotta => true, + crate::BlockKind::BrownWallBanner => false, + crate::BlockKind::BrownWool => true, + crate::BlockKind::BubbleColumn => false, + crate::BlockKind::BubbleCoral => false, + crate::BlockKind::BubbleCoralBlock => true, + crate::BlockKind::BubbleCoralFan => false, + crate::BlockKind::BubbleCoralWallFan => false, + crate::BlockKind::Cactus => false, + crate::BlockKind::Cake => false, + crate::BlockKind::Carrots => true, + crate::BlockKind::CarvedPumpkin => false, + crate::BlockKind::Cauldron => false, + crate::BlockKind::CaveAir => false, + crate::BlockKind::ChainCommandBlock => true, + crate::BlockKind::Chest => false, + crate::BlockKind::ChippedAnvil => false, + crate::BlockKind::ChiseledQuartzBlock => true, + crate::BlockKind::ChiseledRedSandstone => true, + crate::BlockKind::ChiseledSandstone => true, + crate::BlockKind::ChiseledStoneBricks => true, + crate::BlockKind::ChorusFlower => false, + crate::BlockKind::ChorusPlant => false, + crate::BlockKind::Clay => true, + crate::BlockKind::CoalBlock => true, + crate::BlockKind::CoalOre => true, + crate::BlockKind::CoarseDirt => true, + crate::BlockKind::Cobblestone => true, + crate::BlockKind::CobblestoneSlab => false, + crate::BlockKind::CobblestoneStairs => false, + crate::BlockKind::CobblestoneWall => false, + crate::BlockKind::Cobweb => false, + crate::BlockKind::Cocoa => false, + crate::BlockKind::CommandBlock => true, + crate::BlockKind::Comparator => false, + crate::BlockKind::Conduit => true, + crate::BlockKind::CrackedStoneBricks => true, + crate::BlockKind::CraftingTable => true, + crate::BlockKind::CreeperHead => false, + crate::BlockKind::CreeperWallHead => false, + crate::BlockKind::CutRedSandstone => true, + crate::BlockKind::CutSandstone => true, + crate::BlockKind::CyanBanner => false, + crate::BlockKind::CyanBed => false, + crate::BlockKind::CyanCarpet => false, + crate::BlockKind::CyanConcrete => true, + crate::BlockKind::CyanConcretePowder => true, + crate::BlockKind::CyanGlazedTerracotta => true, + crate::BlockKind::CyanShulkerBox => false, + crate::BlockKind::CyanStainedGlass => false, + crate::BlockKind::CyanStainedGlassPane => false, + crate::BlockKind::CyanTerracotta => true, + crate::BlockKind::CyanWallBanner => false, + crate::BlockKind::CyanWool => true, + crate::BlockKind::DamagedAnvil => false, + crate::BlockKind::Dandelion => true, + crate::BlockKind::DarkOakButton => false, + crate::BlockKind::DarkOakDoor => false, + crate::BlockKind::DarkOakFence => false, + crate::BlockKind::DarkOakFenceGate => false, + crate::BlockKind::DarkOakLeaves => false, + crate::BlockKind::DarkOakLog => true, + crate::BlockKind::DarkOakPlanks => true, + crate::BlockKind::DarkOakPressurePlate => false, + crate::BlockKind::DarkOakSapling => false, + crate::BlockKind::DarkOakSlab => false, + crate::BlockKind::DarkOakStairs => false, + crate::BlockKind::DarkOakTrapdoor => false, + crate::BlockKind::DarkOakWood => true, + crate::BlockKind::DarkPrismarine => true, + crate::BlockKind::DarkPrismarineSlab => false, + crate::BlockKind::DarkPrismarineStairs => false, + crate::BlockKind::DaylightDetector => false, + crate::BlockKind::DeadBrainCoral => false, + crate::BlockKind::DeadBrainCoralBlock => true, + crate::BlockKind::DeadBrainCoralFan => false, + crate::BlockKind::DeadBrainCoralWallFan => false, + crate::BlockKind::DeadBubbleCoral => false, + crate::BlockKind::DeadBubbleCoralBlock => true, + crate::BlockKind::DeadBubbleCoralFan => false, + crate::BlockKind::DeadBubbleCoralWallFan => false, + crate::BlockKind::DeadBush => false, + crate::BlockKind::DeadFireCoral => false, + crate::BlockKind::DeadFireCoralBlock => true, + crate::BlockKind::DeadFireCoralFan => false, + crate::BlockKind::DeadFireCoralWallFan => false, + crate::BlockKind::DeadHornCoral => false, + crate::BlockKind::DeadHornCoralBlock => true, + crate::BlockKind::DeadHornCoralFan => false, + crate::BlockKind::DeadHornCoralWallFan => false, + crate::BlockKind::DeadTubeCoral => false, + crate::BlockKind::DeadTubeCoralBlock => true, + crate::BlockKind::DeadTubeCoralFan => false, + crate::BlockKind::DeadTubeCoralWallFan => false, + crate::BlockKind::DetectorRail => false, + crate::BlockKind::DiamondBlock => true, + crate::BlockKind::DiamondOre => true, + crate::BlockKind::Diorite => true, + crate::BlockKind::Dirt => true, + crate::BlockKind::Dispenser => true, + crate::BlockKind::DragonEgg => false, + crate::BlockKind::DragonHead => false, + crate::BlockKind::DragonWallHead => false, + crate::BlockKind::DriedKelpBlock => true, + crate::BlockKind::Dropper => true, + crate::BlockKind::EmeraldBlock => true, + crate::BlockKind::EmeraldOre => true, + crate::BlockKind::EnchantingTable => false, + crate::BlockKind::EndGateway => true, + crate::BlockKind::EndPortal => false, + crate::BlockKind::EndPortalFrame => false, + crate::BlockKind::EndRod => true, + crate::BlockKind::EndStone => true, + crate::BlockKind::EndStoneBricks => true, + crate::BlockKind::EnderChest => false, + crate::BlockKind::Farmland => false, + crate::BlockKind::Fern => false, + crate::BlockKind::Fire => false, + crate::BlockKind::FireCoral => false, + crate::BlockKind::FireCoralBlock => true, + crate::BlockKind::FireCoralFan => false, + crate::BlockKind::FireCoralWallFan => false, + crate::BlockKind::FlowerPot => false, + crate::BlockKind::FrostedIce => false, + crate::BlockKind::Furnace => false, + crate::BlockKind::Glass => false, + crate::BlockKind::GlassPane => false, + crate::BlockKind::Glowstone => false, + crate::BlockKind::GoldBlock => true, + crate::BlockKind::GoldOre => true, + crate::BlockKind::Granite => true, + crate::BlockKind::Grass => true, + crate::BlockKind::GrassBlock => true, + crate::BlockKind::GrassPath => false, + crate::BlockKind::Gravel => true, + crate::BlockKind::GrayBanner => false, + crate::BlockKind::GrayBed => false, + crate::BlockKind::GrayCarpet => false, + crate::BlockKind::GrayConcrete => true, + crate::BlockKind::GrayConcretePowder => true, + crate::BlockKind::GrayGlazedTerracotta => true, + crate::BlockKind::GrayShulkerBox => false, + crate::BlockKind::GrayStainedGlass => false, + crate::BlockKind::GrayStainedGlassPane => false, + crate::BlockKind::GrayTerracotta => true, + crate::BlockKind::GrayWallBanner => false, + crate::BlockKind::GrayWool => true, + crate::BlockKind::GreenBanner => false, + crate::BlockKind::GreenBed => false, + crate::BlockKind::GreenCarpet => false, + crate::BlockKind::GreenConcrete => true, + crate::BlockKind::GreenConcretePowder => true, + crate::BlockKind::GreenGlazedTerracotta => true, + crate::BlockKind::GreenShulkerBox => false, + crate::BlockKind::GreenStainedGlass => false, + crate::BlockKind::GreenStainedGlassPane => false, + crate::BlockKind::GreenTerracotta => true, + crate::BlockKind::GreenWallBanner => false, + crate::BlockKind::GreenWool => true, + crate::BlockKind::HayBlock => true, + crate::BlockKind::HeavyWeightedPressurePlate => false, + crate::BlockKind::Hopper => false, + crate::BlockKind::HornCoral => false, + crate::BlockKind::HornCoralBlock => true, + crate::BlockKind::HornCoralFan => false, + crate::BlockKind::HornCoralWallFan => false, + crate::BlockKind::Ice => false, + crate::BlockKind::InfestedChiseledStoneBricks => true, + crate::BlockKind::InfestedCobblestone => true, + crate::BlockKind::InfestedCrackedStoneBricks => true, + crate::BlockKind::InfestedMossyStoneBricks => true, + crate::BlockKind::InfestedStone => true, + crate::BlockKind::InfestedStoneBricks => true, + crate::BlockKind::IronBars => false, + crate::BlockKind::IronBlock => true, + crate::BlockKind::IronDoor => false, + crate::BlockKind::IronOre => true, + crate::BlockKind::IronTrapdoor => false, + crate::BlockKind::JackOLantern => false, + crate::BlockKind::Jukebox => true, + crate::BlockKind::JungleButton => false, + crate::BlockKind::JungleDoor => false, + crate::BlockKind::JungleFence => false, + crate::BlockKind::JungleFenceGate => false, + crate::BlockKind::JungleLeaves => false, + crate::BlockKind::JungleLog => true, + crate::BlockKind::JunglePlanks => true, + crate::BlockKind::JunglePressurePlate => false, + crate::BlockKind::JungleSapling => false, + crate::BlockKind::JungleSlab => false, + crate::BlockKind::JungleStairs => false, + crate::BlockKind::JungleTrapdoor => false, + crate::BlockKind::JungleWood => true, + crate::BlockKind::Kelp => false, + crate::BlockKind::KelpPlant => false, + crate::BlockKind::Ladder => false, + crate::BlockKind::LapisBlock => true, + crate::BlockKind::LapisOre => true, + crate::BlockKind::LargeFern => false, + crate::BlockKind::Lava => false, + crate::BlockKind::Lever => false, + crate::BlockKind::LightBlueBanner => false, + crate::BlockKind::LightBlueBed => false, + crate::BlockKind::LightBlueCarpet => false, + crate::BlockKind::LightBlueConcrete => true, + crate::BlockKind::LightBlueConcretePowder => true, + crate::BlockKind::LightBlueGlazedTerracotta => true, + crate::BlockKind::LightBlueShulkerBox => false, + crate::BlockKind::LightBlueStainedGlass => false, + crate::BlockKind::LightBlueStainedGlassPane => false, + crate::BlockKind::LightBlueTerracotta => true, + crate::BlockKind::LightBlueWallBanner => false, + crate::BlockKind::LightBlueWool => true, + crate::BlockKind::LightGrayBanner => false, + crate::BlockKind::LightGrayBed => false, + crate::BlockKind::LightGrayCarpet => false, + crate::BlockKind::LightGrayConcrete => true, + crate::BlockKind::LightGrayConcretePowder => true, + crate::BlockKind::LightGrayGlazedTerracotta => true, + crate::BlockKind::LightGrayShulkerBox => false, + crate::BlockKind::LightGrayStainedGlass => false, + crate::BlockKind::LightGrayStainedGlassPane => false, + crate::BlockKind::LightGrayTerracotta => true, + crate::BlockKind::LightGrayWallBanner => false, + crate::BlockKind::LightGrayWool => true, + crate::BlockKind::LightWeightedPressurePlate => false, + crate::BlockKind::Lilac => false, + crate::BlockKind::LilyPad => false, + crate::BlockKind::LimeBanner => false, + crate::BlockKind::LimeBed => false, + crate::BlockKind::LimeCarpet => false, + crate::BlockKind::LimeConcrete => true, + crate::BlockKind::LimeConcretePowder => true, + crate::BlockKind::LimeGlazedTerracotta => true, + crate::BlockKind::LimeShulkerBox => false, + crate::BlockKind::LimeStainedGlass => false, + crate::BlockKind::LimeStainedGlassPane => false, + crate::BlockKind::LimeTerracotta => true, + crate::BlockKind::LimeWallBanner => false, + crate::BlockKind::LimeWool => true, + crate::BlockKind::MagentaBanner => false, + crate::BlockKind::MagentaBed => false, + crate::BlockKind::MagentaCarpet => false, + crate::BlockKind::MagentaConcrete => true, + crate::BlockKind::MagentaConcretePowder => true, + crate::BlockKind::MagentaGlazedTerracotta => true, + crate::BlockKind::MagentaShulkerBox => false, + crate::BlockKind::MagentaStainedGlass => false, + crate::BlockKind::MagentaStainedGlassPane => false, + crate::BlockKind::MagentaTerracotta => true, + crate::BlockKind::MagentaWallBanner => false, + crate::BlockKind::MagentaWool => true, + crate::BlockKind::MagmaBlock => true, + crate::BlockKind::Melon => false, + crate::BlockKind::MelonStem => false, + crate::BlockKind::MossyCobblestone => true, + crate::BlockKind::MossyCobblestoneWall => false, + crate::BlockKind::MossyStoneBricks => true, + crate::BlockKind::MovingPiston => false, + crate::BlockKind::MushroomStem => true, + crate::BlockKind::Mycelium => true, + crate::BlockKind::NetherBrickFence => false, + crate::BlockKind::NetherBrickSlab => false, + crate::BlockKind::NetherBrickStairs => false, + crate::BlockKind::NetherBricks => true, + crate::BlockKind::NetherPortal => false, + crate::BlockKind::NetherQuartzOre => true, + crate::BlockKind::NetherWart => false, + crate::BlockKind::NetherWartBlock => true, + crate::BlockKind::Netherrack => true, + crate::BlockKind::NoteBlock => true, + crate::BlockKind::OakButton => false, + crate::BlockKind::OakDoor => false, + crate::BlockKind::OakFence => false, + crate::BlockKind::OakFenceGate => false, + crate::BlockKind::OakLeaves => false, + crate::BlockKind::OakLog => true, + crate::BlockKind::OakPlanks => true, + crate::BlockKind::OakPressurePlate => false, + crate::BlockKind::OakSapling => false, + crate::BlockKind::OakSlab => false, + crate::BlockKind::OakStairs => false, + crate::BlockKind::OakTrapdoor => false, + crate::BlockKind::OakWood => true, + crate::BlockKind::Observer => false, + crate::BlockKind::Obsidian => true, + crate::BlockKind::OrangeBanner => false, + crate::BlockKind::OrangeBed => false, + crate::BlockKind::OrangeCarpet => false, + crate::BlockKind::OrangeConcrete => true, + crate::BlockKind::OrangeConcretePowder => true, + crate::BlockKind::OrangeGlazedTerracotta => true, + crate::BlockKind::OrangeShulkerBox => false, + crate::BlockKind::OrangeStainedGlass => false, + crate::BlockKind::OrangeStainedGlassPane => false, + crate::BlockKind::OrangeTerracotta => true, + crate::BlockKind::OrangeTulip => false, + crate::BlockKind::OrangeWallBanner => false, + crate::BlockKind::OrangeWool => true, + crate::BlockKind::OxeyeDaisy => true, + crate::BlockKind::PackedIce => true, + crate::BlockKind::Peony => true, + crate::BlockKind::PetrifiedOakSlab => false, + crate::BlockKind::PinkBanner => false, + crate::BlockKind::PinkBed => false, + crate::BlockKind::PinkCarpet => false, + crate::BlockKind::PinkConcrete => true, + crate::BlockKind::PinkConcretePowder => true, + crate::BlockKind::PinkGlazedTerracotta => true, + crate::BlockKind::PinkShulkerBox => false, + crate::BlockKind::PinkStainedGlass => false, + crate::BlockKind::PinkStainedGlassPane => false, + crate::BlockKind::PinkTerracotta => true, + crate::BlockKind::PinkTulip => false, + crate::BlockKind::PinkWallBanner => false, + crate::BlockKind::PinkWool => true, + crate::BlockKind::Piston => false, + crate::BlockKind::PistonHead => false, + crate::BlockKind::PlayerHead => false, + crate::BlockKind::PlayerWallHead => false, + crate::BlockKind::Podzol => true, + crate::BlockKind::PolishedAndesite => true, + crate::BlockKind::PolishedDiorite => true, + crate::BlockKind::PolishedGranite => true, + crate::BlockKind::Poppy => true, + crate::BlockKind::Potatoes => true, + crate::BlockKind::PottedAcaciaSapling => false, + crate::BlockKind::PottedAllium => false, + crate::BlockKind::PottedAzureBluet => false, + crate::BlockKind::PottedBirchSapling => false, + crate::BlockKind::PottedBlueOrchid => false, + crate::BlockKind::PottedBrownMushroom => false, + crate::BlockKind::PottedCactus => false, + crate::BlockKind::PottedDandelion => false, + crate::BlockKind::PottedDarkOakSapling => false, + crate::BlockKind::PottedDeadBush => false, + crate::BlockKind::PottedFern => false, + crate::BlockKind::PottedJungleSapling => false, + crate::BlockKind::PottedOakSapling => false, + crate::BlockKind::PottedOrangeTulip => false, + crate::BlockKind::PottedOxeyeDaisy => false, + crate::BlockKind::PottedPinkTulip => false, + crate::BlockKind::PottedPoppy => false, + crate::BlockKind::PottedRedMushroom => false, + crate::BlockKind::PottedRedTulip => false, + crate::BlockKind::PottedSpruceSapling => false, + crate::BlockKind::PottedWhiteTulip => false, + crate::BlockKind::PoweredRail => false, + crate::BlockKind::Prismarine => true, + crate::BlockKind::PrismarineBrickSlab => false, + crate::BlockKind::PrismarineBrickStairs => false, + crate::BlockKind::PrismarineBricks => true, + crate::BlockKind::PrismarineSlab => false, + crate::BlockKind::PrismarineStairs => false, + crate::BlockKind::Pumpkin => false, + crate::BlockKind::PumpkinStem => false, + crate::BlockKind::PurpleBanner => false, + crate::BlockKind::PurpleBed => false, + crate::BlockKind::PurpleCarpet => false, + crate::BlockKind::PurpleConcrete => true, + crate::BlockKind::PurpleConcretePowder => true, + crate::BlockKind::PurpleGlazedTerracotta => true, + crate::BlockKind::PurpleShulkerBox => false, + crate::BlockKind::PurpleStainedGlass => false, + crate::BlockKind::PurpleStainedGlassPane => false, + crate::BlockKind::PurpleTerracotta => true, + crate::BlockKind::PurpleWallBanner => false, + crate::BlockKind::PurpleWool => true, + crate::BlockKind::PurpurBlock => true, + crate::BlockKind::PurpurPillar => true, + crate::BlockKind::PurpurSlab => false, + crate::BlockKind::PurpurStairs => false, + crate::BlockKind::QuartzBlock => true, + crate::BlockKind::QuartzPillar => true, + crate::BlockKind::QuartzSlab => false, + crate::BlockKind::QuartzStairs => false, + crate::BlockKind::Rail => false, + crate::BlockKind::RedBanner => false, + crate::BlockKind::RedBed => false, + crate::BlockKind::RedCarpet => false, + crate::BlockKind::RedConcrete => true, + crate::BlockKind::RedConcretePowder => true, + crate::BlockKind::RedGlazedTerracotta => true, + crate::BlockKind::RedMushroom => true, + crate::BlockKind::RedMushroomBlock => true, + crate::BlockKind::RedNetherBricks => true, + crate::BlockKind::RedSand => true, + crate::BlockKind::RedSandstone => true, + crate::BlockKind::RedSandstoneSlab => false, + crate::BlockKind::RedSandstoneStairs => false, + crate::BlockKind::RedShulkerBox => false, + crate::BlockKind::RedStainedGlass => false, + crate::BlockKind::RedStainedGlassPane => false, + crate::BlockKind::RedTerracotta => true, + crate::BlockKind::RedTulip => false, + crate::BlockKind::RedWallBanner => false, + crate::BlockKind::RedWool => true, + crate::BlockKind::RedstoneBlock => false, + crate::BlockKind::RedstoneLamp => false, + crate::BlockKind::RedstoneOre => false, + crate::BlockKind::RedstoneTorch => false, + crate::BlockKind::RedstoneWallTorch => false, + crate::BlockKind::RedstoneWire => false, + crate::BlockKind::Repeater => false, + crate::BlockKind::RepeatingCommandBlock => true, + crate::BlockKind::RoseBush => false, + crate::BlockKind::Sand => true, + crate::BlockKind::Sandstone => true, + crate::BlockKind::SandstoneSlab => false, + crate::BlockKind::SandstoneStairs => false, + crate::BlockKind::SeaLantern => false, + crate::BlockKind::SeaPickle => true, + crate::BlockKind::Seagrass => false, + crate::BlockKind::ShulkerBox => false, + crate::BlockKind::Sign => false, + crate::BlockKind::SkeletonSkull => false, + crate::BlockKind::SkeletonWallSkull => false, + crate::BlockKind::SlimeBlock => false, + crate::BlockKind::SmoothQuartz => true, + crate::BlockKind::SmoothRedSandstone => true, + crate::BlockKind::SmoothSandstone => true, + crate::BlockKind::SmoothStone => true, + crate::BlockKind::Snow => true, + crate::BlockKind::SnowBlock => true, + crate::BlockKind::SoulSand => true, + crate::BlockKind::Spawner => false, + crate::BlockKind::Sponge => true, + crate::BlockKind::SpruceButton => false, + crate::BlockKind::SpruceDoor => false, + crate::BlockKind::SpruceFence => false, + crate::BlockKind::SpruceFenceGate => false, + crate::BlockKind::SpruceLeaves => false, + crate::BlockKind::SpruceLog => true, + crate::BlockKind::SprucePlanks => true, + crate::BlockKind::SprucePressurePlate => false, + crate::BlockKind::SpruceSapling => false, + crate::BlockKind::SpruceSlab => false, + crate::BlockKind::SpruceStairs => false, + crate::BlockKind::SpruceTrapdoor => false, + crate::BlockKind::SpruceWood => true, + crate::BlockKind::StickyPiston => false, + crate::BlockKind::Stone => true, + crate::BlockKind::StoneBrickSlab => false, + crate::BlockKind::StoneBrickStairs => false, + crate::BlockKind::StoneBricks => true, + crate::BlockKind::StoneButton => false, + crate::BlockKind::StonePressurePlate => false, + crate::BlockKind::StoneSlab => false, + crate::BlockKind::StrippedAcaciaLog => true, + crate::BlockKind::StrippedAcaciaWood => true, + crate::BlockKind::StrippedBirchLog => true, + crate::BlockKind::StrippedBirchWood => true, + crate::BlockKind::StrippedDarkOakLog => true, + crate::BlockKind::StrippedDarkOakWood => true, + crate::BlockKind::StrippedJungleLog => true, + crate::BlockKind::StrippedJungleWood => true, + crate::BlockKind::StrippedOakLog => true, + crate::BlockKind::StrippedOakWood => true, + crate::BlockKind::StrippedSpruceLog => true, + crate::BlockKind::StrippedSpruceWood => true, + crate::BlockKind::StructureBlock => true, + crate::BlockKind::StructureVoid => true, + crate::BlockKind::SugarCane => false, + crate::BlockKind::Sunflower => false, + crate::BlockKind::TallGrass => false, + crate::BlockKind::TallSeagrass => false, + crate::BlockKind::Terracotta => true, + crate::BlockKind::Tnt => false, + crate::BlockKind::Torch => false, + crate::BlockKind::TrappedChest => false, + crate::BlockKind::Tripwire => false, + crate::BlockKind::TripwireHook => false, + crate::BlockKind::TubeCoral => false, + crate::BlockKind::TubeCoralBlock => true, + crate::BlockKind::TubeCoralFan => false, + crate::BlockKind::TubeCoralWallFan => false, + crate::BlockKind::TurtleEgg => true, + crate::BlockKind::Vine => false, + crate::BlockKind::VoidAir => false, + crate::BlockKind::WallSign => false, + crate::BlockKind::WallTorch => false, + crate::BlockKind::Water => false, + crate::BlockKind::WetSponge => true, + crate::BlockKind::Wheat => false, + crate::BlockKind::WhiteBanner => false, + crate::BlockKind::WhiteBed => false, + crate::BlockKind::WhiteCarpet => false, + crate::BlockKind::WhiteConcrete => true, + crate::BlockKind::WhiteConcretePowder => true, + crate::BlockKind::WhiteGlazedTerracotta => true, + crate::BlockKind::WhiteShulkerBox => false, + crate::BlockKind::WhiteStainedGlass => false, + crate::BlockKind::WhiteStainedGlassPane => false, + crate::BlockKind::WhiteTerracotta => true, + crate::BlockKind::WhiteTulip => false, + crate::BlockKind::WhiteWallBanner => false, + crate::BlockKind::WhiteWool => true, + crate::BlockKind::WitherSkeletonSkull => false, + crate::BlockKind::WitherSkeletonWallSkull => false, + crate::BlockKind::YellowBanner => false, + crate::BlockKind::YellowBed => false, + crate::BlockKind::YellowCarpet => false, + crate::BlockKind::YellowConcrete => true, + crate::BlockKind::YellowConcretePowder => true, + crate::BlockKind::YellowGlazedTerracotta => true, + crate::BlockKind::YellowShulkerBox => false, + crate::BlockKind::YellowStainedGlass => false, + crate::BlockKind::YellowStainedGlassPane => false, + crate::BlockKind::YellowTerracotta => true, + crate::BlockKind::YellowWallBanner => false, + crate::BlockKind::YellowWool => true, + crate::BlockKind::ZombieHead => false, + crate::BlockKind::ZombieWallHead => false, + _ => false, + } + } +} +impl crate::BlockKind { + pub fn solid(self) -> bool { + match self { + crate::BlockKind::AcaciaButton => false, + crate::BlockKind::AcaciaDoor => true, + crate::BlockKind::AcaciaFence => true, + crate::BlockKind::AcaciaFenceGate => true, + crate::BlockKind::AcaciaLeaves => true, + crate::BlockKind::AcaciaLog => true, + crate::BlockKind::AcaciaPlanks => true, + crate::BlockKind::AcaciaPressurePlate => false, + crate::BlockKind::AcaciaSapling => false, + crate::BlockKind::AcaciaSlab => true, + crate::BlockKind::AcaciaStairs => true, + crate::BlockKind::AcaciaTrapdoor => true, + crate::BlockKind::AcaciaWood => true, + crate::BlockKind::ActivatorRail => false, + crate::BlockKind::Air => false, + crate::BlockKind::Allium => false, + crate::BlockKind::Andesite => true, + crate::BlockKind::Anvil => true, + crate::BlockKind::AttachedMelonStem => false, + crate::BlockKind::AttachedPumpkinStem => false, + crate::BlockKind::AzureBluet => false, + crate::BlockKind::Barrier => true, + crate::BlockKind::Beacon => true, + crate::BlockKind::Bedrock => true, + crate::BlockKind::Beetroots => false, + crate::BlockKind::BirchButton => false, + crate::BlockKind::BirchDoor => true, + crate::BlockKind::BirchFence => true, + crate::BlockKind::BirchFenceGate => true, + crate::BlockKind::BirchLeaves => true, + crate::BlockKind::BirchLog => true, + crate::BlockKind::BirchPlanks => true, + crate::BlockKind::BirchPressurePlate => false, + crate::BlockKind::BirchSapling => false, + crate::BlockKind::BirchSlab => true, + crate::BlockKind::BirchStairs => true, + crate::BlockKind::BirchTrapdoor => true, + crate::BlockKind::BirchWood => true, + crate::BlockKind::BlackBanner => false, + crate::BlockKind::BlackBed => true, + crate::BlockKind::BlackCarpet => true, + crate::BlockKind::BlackConcrete => true, + crate::BlockKind::BlackConcretePowder => true, + crate::BlockKind::BlackGlazedTerracotta => true, + crate::BlockKind::BlackShulkerBox => true, + crate::BlockKind::BlackStainedGlass => true, + crate::BlockKind::BlackStainedGlassPane => true, + crate::BlockKind::BlackTerracotta => true, + crate::BlockKind::BlackWallBanner => false, + crate::BlockKind::BlackWool => true, + crate::BlockKind::BlueBanner => false, + crate::BlockKind::BlueBed => true, + crate::BlockKind::BlueCarpet => true, + crate::BlockKind::BlueConcrete => true, + crate::BlockKind::BlueConcretePowder => true, + crate::BlockKind::BlueGlazedTerracotta => true, + crate::BlockKind::BlueIce => true, + crate::BlockKind::BlueOrchid => false, + crate::BlockKind::BlueShulkerBox => true, + crate::BlockKind::BlueStainedGlass => true, + crate::BlockKind::BlueStainedGlassPane => true, + crate::BlockKind::BlueTerracotta => true, + crate::BlockKind::BlueWallBanner => false, + crate::BlockKind::BlueWool => true, + crate::BlockKind::BoneBlock => true, + crate::BlockKind::Bookshelf => true, + crate::BlockKind::BrainCoral => false, + crate::BlockKind::BrainCoralBlock => true, + crate::BlockKind::BrainCoralFan => false, + crate::BlockKind::BrainCoralWallFan => false, + crate::BlockKind::BrewingStand => true, + crate::BlockKind::BrickSlab => true, + crate::BlockKind::BrickStairs => true, + crate::BlockKind::Bricks => true, + crate::BlockKind::BrownBanner => false, + crate::BlockKind::BrownBed => true, + crate::BlockKind::BrownCarpet => true, + crate::BlockKind::BrownConcrete => true, + crate::BlockKind::BrownConcretePowder => true, + crate::BlockKind::BrownGlazedTerracotta => true, + crate::BlockKind::BrownMushroom => false, + crate::BlockKind::BrownMushroomBlock => true, + crate::BlockKind::BrownShulkerBox => true, + crate::BlockKind::BrownStainedGlass => true, + crate::BlockKind::BrownStainedGlassPane => true, + crate::BlockKind::BrownTerracotta => true, + crate::BlockKind::BrownWallBanner => false, + crate::BlockKind::BrownWool => true, + crate::BlockKind::BubbleColumn => false, + crate::BlockKind::BubbleCoral => false, + crate::BlockKind::BubbleCoralBlock => true, + crate::BlockKind::BubbleCoralFan => false, + crate::BlockKind::BubbleCoralWallFan => false, + crate::BlockKind::Cactus => true, + crate::BlockKind::Cake => true, + crate::BlockKind::Carrots => false, + crate::BlockKind::CarvedPumpkin => true, + crate::BlockKind::Cauldron => true, + crate::BlockKind::CaveAir => false, + crate::BlockKind::ChainCommandBlock => true, + crate::BlockKind::Chest => true, + crate::BlockKind::ChippedAnvil => true, + crate::BlockKind::ChiseledQuartzBlock => true, + crate::BlockKind::ChiseledRedSandstone => true, + crate::BlockKind::ChiseledSandstone => true, + crate::BlockKind::ChiseledStoneBricks => true, + crate::BlockKind::ChorusFlower => true, + crate::BlockKind::ChorusPlant => true, + crate::BlockKind::Clay => true, + crate::BlockKind::CoalBlock => true, + crate::BlockKind::CoalOre => true, + crate::BlockKind::CoarseDirt => true, + crate::BlockKind::Cobblestone => true, + crate::BlockKind::CobblestoneSlab => true, + crate::BlockKind::CobblestoneStairs => true, + crate::BlockKind::CobblestoneWall => true, + crate::BlockKind::Cobweb => false, + crate::BlockKind::Cocoa => true, + crate::BlockKind::CommandBlock => true, + crate::BlockKind::Comparator => true, + crate::BlockKind::Conduit => true, + crate::BlockKind::CrackedStoneBricks => true, + crate::BlockKind::CraftingTable => true, + crate::BlockKind::CreeperHead => true, + crate::BlockKind::CreeperWallHead => true, + crate::BlockKind::CutRedSandstone => true, + crate::BlockKind::CutSandstone => true, + crate::BlockKind::CyanBanner => false, + crate::BlockKind::CyanBed => true, + crate::BlockKind::CyanCarpet => true, + crate::BlockKind::CyanConcrete => true, + crate::BlockKind::CyanConcretePowder => true, + crate::BlockKind::CyanGlazedTerracotta => true, + crate::BlockKind::CyanShulkerBox => true, + crate::BlockKind::CyanStainedGlass => true, + crate::BlockKind::CyanStainedGlassPane => true, + crate::BlockKind::CyanTerracotta => true, + crate::BlockKind::CyanWallBanner => false, + crate::BlockKind::CyanWool => true, + crate::BlockKind::DamagedAnvil => true, + crate::BlockKind::Dandelion => false, + crate::BlockKind::DarkOakButton => false, + crate::BlockKind::DarkOakDoor => true, + crate::BlockKind::DarkOakFence => true, + crate::BlockKind::DarkOakFenceGate => true, + crate::BlockKind::DarkOakLeaves => true, + crate::BlockKind::DarkOakLog => true, + crate::BlockKind::DarkOakPlanks => true, + crate::BlockKind::DarkOakPressurePlate => false, + crate::BlockKind::DarkOakSapling => false, + crate::BlockKind::DarkOakSlab => true, + crate::BlockKind::DarkOakStairs => true, + crate::BlockKind::DarkOakTrapdoor => true, + crate::BlockKind::DarkOakWood => true, + crate::BlockKind::DarkPrismarine => true, + crate::BlockKind::DarkPrismarineSlab => true, + crate::BlockKind::DarkPrismarineStairs => true, + crate::BlockKind::DaylightDetector => true, + crate::BlockKind::DeadBrainCoral => false, + crate::BlockKind::DeadBrainCoralBlock => true, + crate::BlockKind::DeadBrainCoralFan => false, + crate::BlockKind::DeadBrainCoralWallFan => false, + crate::BlockKind::DeadBubbleCoral => false, + crate::BlockKind::DeadBubbleCoralBlock => true, + crate::BlockKind::DeadBubbleCoralFan => false, + crate::BlockKind::DeadBubbleCoralWallFan => false, + crate::BlockKind::DeadBush => false, + crate::BlockKind::DeadFireCoral => false, + crate::BlockKind::DeadFireCoralBlock => true, + crate::BlockKind::DeadFireCoralFan => false, + crate::BlockKind::DeadFireCoralWallFan => false, + crate::BlockKind::DeadHornCoral => false, + crate::BlockKind::DeadHornCoralBlock => true, + crate::BlockKind::DeadHornCoralFan => false, + crate::BlockKind::DeadHornCoralWallFan => false, + crate::BlockKind::DeadTubeCoral => false, + crate::BlockKind::DeadTubeCoralBlock => true, + crate::BlockKind::DeadTubeCoralFan => false, + crate::BlockKind::DeadTubeCoralWallFan => false, + crate::BlockKind::DetectorRail => false, + crate::BlockKind::DiamondBlock => true, + crate::BlockKind::DiamondOre => true, + crate::BlockKind::Diorite => true, + crate::BlockKind::Dirt => true, + crate::BlockKind::Dispenser => true, + crate::BlockKind::DragonEgg => true, + crate::BlockKind::DragonHead => true, + crate::BlockKind::DragonWallHead => true, + crate::BlockKind::DriedKelpBlock => true, + crate::BlockKind::Dropper => true, + crate::BlockKind::EmeraldBlock => true, + crate::BlockKind::EmeraldOre => true, + crate::BlockKind::EnchantingTable => true, + crate::BlockKind::EndGateway => false, + crate::BlockKind::EndPortal => false, + crate::BlockKind::EndPortalFrame => true, + crate::BlockKind::EndRod => true, + crate::BlockKind::EndStone => true, + crate::BlockKind::EndStoneBricks => true, + crate::BlockKind::EnderChest => true, + crate::BlockKind::Farmland => true, + crate::BlockKind::Fern => false, + crate::BlockKind::Fire => false, + crate::BlockKind::FireCoral => false, + crate::BlockKind::FireCoralBlock => true, + crate::BlockKind::FireCoralFan => false, + crate::BlockKind::FireCoralWallFan => false, + crate::BlockKind::FlowerPot => true, + crate::BlockKind::FrostedIce => true, + crate::BlockKind::Furnace => true, + crate::BlockKind::Glass => true, + crate::BlockKind::GlassPane => true, + crate::BlockKind::Glowstone => true, + crate::BlockKind::GoldBlock => true, + crate::BlockKind::GoldOre => true, + crate::BlockKind::Granite => true, + crate::BlockKind::Grass => false, + crate::BlockKind::GrassBlock => true, + crate::BlockKind::GrassPath => true, + crate::BlockKind::Gravel => true, + crate::BlockKind::GrayBanner => false, + crate::BlockKind::GrayBed => true, + crate::BlockKind::GrayCarpet => true, + crate::BlockKind::GrayConcrete => true, + crate::BlockKind::GrayConcretePowder => true, + crate::BlockKind::GrayGlazedTerracotta => true, + crate::BlockKind::GrayShulkerBox => true, + crate::BlockKind::GrayStainedGlass => true, + crate::BlockKind::GrayStainedGlassPane => true, + crate::BlockKind::GrayTerracotta => true, + crate::BlockKind::GrayWallBanner => false, + crate::BlockKind::GrayWool => true, + crate::BlockKind::GreenBanner => false, + crate::BlockKind::GreenBed => true, + crate::BlockKind::GreenCarpet => true, + crate::BlockKind::GreenConcrete => true, + crate::BlockKind::GreenConcretePowder => true, + crate::BlockKind::GreenGlazedTerracotta => true, + crate::BlockKind::GreenShulkerBox => true, + crate::BlockKind::GreenStainedGlass => true, + crate::BlockKind::GreenStainedGlassPane => true, + crate::BlockKind::GreenTerracotta => true, + crate::BlockKind::GreenWallBanner => false, + crate::BlockKind::GreenWool => true, + crate::BlockKind::HayBlock => true, + crate::BlockKind::HeavyWeightedPressurePlate => false, + crate::BlockKind::Hopper => true, + crate::BlockKind::HornCoral => false, + crate::BlockKind::HornCoralBlock => true, + crate::BlockKind::HornCoralFan => false, + crate::BlockKind::HornCoralWallFan => false, + crate::BlockKind::Ice => true, + crate::BlockKind::InfestedChiseledStoneBricks => true, + crate::BlockKind::InfestedCobblestone => true, + crate::BlockKind::InfestedCrackedStoneBricks => true, + crate::BlockKind::InfestedMossyStoneBricks => true, + crate::BlockKind::InfestedStone => true, + crate::BlockKind::InfestedStoneBricks => true, + crate::BlockKind::IronBars => true, + crate::BlockKind::IronBlock => true, + crate::BlockKind::IronDoor => true, + crate::BlockKind::IronOre => true, + crate::BlockKind::IronTrapdoor => true, + crate::BlockKind::JackOLantern => true, + crate::BlockKind::Jukebox => true, + crate::BlockKind::JungleButton => false, + crate::BlockKind::JungleDoor => true, + crate::BlockKind::JungleFence => true, + crate::BlockKind::JungleFenceGate => true, + crate::BlockKind::JungleLeaves => true, + crate::BlockKind::JungleLog => true, + crate::BlockKind::JunglePlanks => true, + crate::BlockKind::JunglePressurePlate => false, + crate::BlockKind::JungleSapling => false, + crate::BlockKind::JungleSlab => true, + crate::BlockKind::JungleStairs => true, + crate::BlockKind::JungleTrapdoor => true, + crate::BlockKind::JungleWood => true, + crate::BlockKind::Kelp => false, + crate::BlockKind::KelpPlant => false, + crate::BlockKind::Ladder => true, + crate::BlockKind::LapisBlock => true, + crate::BlockKind::LapisOre => true, + crate::BlockKind::LargeFern => false, + crate::BlockKind::Lava => false, + crate::BlockKind::Lever => false, + crate::BlockKind::LightBlueBanner => false, + crate::BlockKind::LightBlueBed => true, + crate::BlockKind::LightBlueCarpet => true, + crate::BlockKind::LightBlueConcrete => true, + crate::BlockKind::LightBlueConcretePowder => true, + crate::BlockKind::LightBlueGlazedTerracotta => true, + crate::BlockKind::LightBlueShulkerBox => true, + crate::BlockKind::LightBlueStainedGlass => true, + crate::BlockKind::LightBlueStainedGlassPane => true, + crate::BlockKind::LightBlueTerracotta => true, + crate::BlockKind::LightBlueWallBanner => false, + crate::BlockKind::LightBlueWool => true, + crate::BlockKind::LightGrayBanner => false, + crate::BlockKind::LightGrayBed => true, + crate::BlockKind::LightGrayCarpet => true, + crate::BlockKind::LightGrayConcrete => true, + crate::BlockKind::LightGrayConcretePowder => true, + crate::BlockKind::LightGrayGlazedTerracotta => true, + crate::BlockKind::LightGrayShulkerBox => true, + crate::BlockKind::LightGrayStainedGlass => true, + crate::BlockKind::LightGrayStainedGlassPane => true, + crate::BlockKind::LightGrayTerracotta => true, + crate::BlockKind::LightGrayWallBanner => false, + crate::BlockKind::LightGrayWool => true, + crate::BlockKind::LightWeightedPressurePlate => false, + crate::BlockKind::Lilac => false, + crate::BlockKind::LilyPad => true, + crate::BlockKind::LimeBanner => false, + crate::BlockKind::LimeBed => true, + crate::BlockKind::LimeCarpet => true, + crate::BlockKind::LimeConcrete => true, + crate::BlockKind::LimeConcretePowder => true, + crate::BlockKind::LimeGlazedTerracotta => true, + crate::BlockKind::LimeShulkerBox => true, + crate::BlockKind::LimeStainedGlass => true, + crate::BlockKind::LimeStainedGlassPane => true, + crate::BlockKind::LimeTerracotta => true, + crate::BlockKind::LimeWallBanner => false, + crate::BlockKind::LimeWool => true, + crate::BlockKind::MagentaBanner => false, + crate::BlockKind::MagentaBed => true, + crate::BlockKind::MagentaCarpet => true, + crate::BlockKind::MagentaConcrete => true, + crate::BlockKind::MagentaConcretePowder => true, + crate::BlockKind::MagentaGlazedTerracotta => true, + crate::BlockKind::MagentaShulkerBox => true, + crate::BlockKind::MagentaStainedGlass => true, + crate::BlockKind::MagentaStainedGlassPane => true, + crate::BlockKind::MagentaTerracotta => true, + crate::BlockKind::MagentaWallBanner => false, + crate::BlockKind::MagentaWool => true, + crate::BlockKind::MagmaBlock => true, + crate::BlockKind::Melon => true, + crate::BlockKind::MelonStem => false, + crate::BlockKind::MossyCobblestone => true, + crate::BlockKind::MossyCobblestoneWall => true, + crate::BlockKind::MossyStoneBricks => true, + crate::BlockKind::MovingPiston => false, + crate::BlockKind::MushroomStem => true, + crate::BlockKind::Mycelium => true, + crate::BlockKind::NetherBrickFence => true, + crate::BlockKind::NetherBrickSlab => true, + crate::BlockKind::NetherBrickStairs => true, + crate::BlockKind::NetherBricks => true, + crate::BlockKind::NetherPortal => false, + crate::BlockKind::NetherQuartzOre => true, + crate::BlockKind::NetherWart => false, + crate::BlockKind::NetherWartBlock => true, + crate::BlockKind::Netherrack => true, + crate::BlockKind::NoteBlock => true, + crate::BlockKind::OakButton => false, + crate::BlockKind::OakDoor => true, + crate::BlockKind::OakFence => true, + crate::BlockKind::OakFenceGate => true, + crate::BlockKind::OakLeaves => true, + crate::BlockKind::OakLog => true, + crate::BlockKind::OakPlanks => true, + crate::BlockKind::OakPressurePlate => false, + crate::BlockKind::OakSapling => false, + crate::BlockKind::OakSlab => true, + crate::BlockKind::OakStairs => true, + crate::BlockKind::OakTrapdoor => true, + crate::BlockKind::OakWood => true, + crate::BlockKind::Observer => true, + crate::BlockKind::Obsidian => true, + crate::BlockKind::OrangeBanner => false, + crate::BlockKind::OrangeBed => true, + crate::BlockKind::OrangeCarpet => true, + crate::BlockKind::OrangeConcrete => true, + crate::BlockKind::OrangeConcretePowder => true, + crate::BlockKind::OrangeGlazedTerracotta => true, + crate::BlockKind::OrangeShulkerBox => true, + crate::BlockKind::OrangeStainedGlass => true, + crate::BlockKind::OrangeStainedGlassPane => true, + crate::BlockKind::OrangeTerracotta => true, + crate::BlockKind::OrangeTulip => false, + crate::BlockKind::OrangeWallBanner => false, + crate::BlockKind::OrangeWool => true, + crate::BlockKind::OxeyeDaisy => false, + crate::BlockKind::PackedIce => true, + crate::BlockKind::Peony => false, + crate::BlockKind::PetrifiedOakSlab => true, + crate::BlockKind::PinkBanner => false, + crate::BlockKind::PinkBed => true, + crate::BlockKind::PinkCarpet => true, + crate::BlockKind::PinkConcrete => true, + crate::BlockKind::PinkConcretePowder => true, + crate::BlockKind::PinkGlazedTerracotta => true, + crate::BlockKind::PinkShulkerBox => true, + crate::BlockKind::PinkStainedGlass => true, + crate::BlockKind::PinkStainedGlassPane => true, + crate::BlockKind::PinkTerracotta => true, + crate::BlockKind::PinkTulip => false, + crate::BlockKind::PinkWallBanner => false, + crate::BlockKind::PinkWool => true, + crate::BlockKind::Piston => true, + crate::BlockKind::PistonHead => true, + crate::BlockKind::PlayerHead => true, + crate::BlockKind::PlayerWallHead => true, + crate::BlockKind::Podzol => true, + crate::BlockKind::PolishedAndesite => true, + crate::BlockKind::PolishedDiorite => true, + crate::BlockKind::PolishedGranite => true, + crate::BlockKind::Poppy => false, + crate::BlockKind::Potatoes => false, + crate::BlockKind::PottedAcaciaSapling => true, + crate::BlockKind::PottedAllium => true, + crate::BlockKind::PottedAzureBluet => true, + crate::BlockKind::PottedBirchSapling => true, + crate::BlockKind::PottedBlueOrchid => true, + crate::BlockKind::PottedBrownMushroom => true, + crate::BlockKind::PottedCactus => true, + crate::BlockKind::PottedDandelion => true, + crate::BlockKind::PottedDarkOakSapling => true, + crate::BlockKind::PottedDeadBush => true, + crate::BlockKind::PottedFern => true, + crate::BlockKind::PottedJungleSapling => true, + crate::BlockKind::PottedOakSapling => true, + crate::BlockKind::PottedOrangeTulip => true, + crate::BlockKind::PottedOxeyeDaisy => true, + crate::BlockKind::PottedPinkTulip => true, + crate::BlockKind::PottedPoppy => true, + crate::BlockKind::PottedRedMushroom => true, + crate::BlockKind::PottedRedTulip => true, + crate::BlockKind::PottedSpruceSapling => true, + crate::BlockKind::PottedWhiteTulip => true, + crate::BlockKind::PoweredRail => false, + crate::BlockKind::Prismarine => true, + crate::BlockKind::PrismarineBrickSlab => true, + crate::BlockKind::PrismarineBrickStairs => true, + crate::BlockKind::PrismarineBricks => true, + crate::BlockKind::PrismarineSlab => true, + crate::BlockKind::PrismarineStairs => true, + crate::BlockKind::Pumpkin => true, + crate::BlockKind::PumpkinStem => false, + crate::BlockKind::PurpleBanner => false, + crate::BlockKind::PurpleBed => true, + crate::BlockKind::PurpleCarpet => true, + crate::BlockKind::PurpleConcrete => true, + crate::BlockKind::PurpleConcretePowder => true, + crate::BlockKind::PurpleGlazedTerracotta => true, + crate::BlockKind::PurpleShulkerBox => true, + crate::BlockKind::PurpleStainedGlass => true, + crate::BlockKind::PurpleStainedGlassPane => true, + crate::BlockKind::PurpleTerracotta => true, + crate::BlockKind::PurpleWallBanner => false, + crate::BlockKind::PurpleWool => true, + crate::BlockKind::PurpurBlock => true, + crate::BlockKind::PurpurPillar => true, + crate::BlockKind::PurpurSlab => true, + crate::BlockKind::PurpurStairs => true, + crate::BlockKind::QuartzBlock => true, + crate::BlockKind::QuartzPillar => true, + crate::BlockKind::QuartzSlab => true, + crate::BlockKind::QuartzStairs => true, + crate::BlockKind::Rail => false, + crate::BlockKind::RedBanner => false, + crate::BlockKind::RedBed => true, + crate::BlockKind::RedCarpet => true, + crate::BlockKind::RedConcrete => true, + crate::BlockKind::RedConcretePowder => true, + crate::BlockKind::RedGlazedTerracotta => true, + crate::BlockKind::RedMushroom => false, + crate::BlockKind::RedMushroomBlock => true, + crate::BlockKind::RedNetherBricks => true, + crate::BlockKind::RedSand => true, + crate::BlockKind::RedSandstone => true, + crate::BlockKind::RedSandstoneSlab => true, + crate::BlockKind::RedSandstoneStairs => true, + crate::BlockKind::RedShulkerBox => true, + crate::BlockKind::RedStainedGlass => true, + crate::BlockKind::RedStainedGlassPane => true, + crate::BlockKind::RedTerracotta => true, + crate::BlockKind::RedTulip => false, + crate::BlockKind::RedWallBanner => false, + crate::BlockKind::RedWool => true, + crate::BlockKind::RedstoneBlock => true, + crate::BlockKind::RedstoneLamp => true, + crate::BlockKind::RedstoneOre => true, + crate::BlockKind::RedstoneTorch => false, + crate::BlockKind::RedstoneWallTorch => false, + crate::BlockKind::RedstoneWire => false, + crate::BlockKind::Repeater => true, + crate::BlockKind::RepeatingCommandBlock => true, + crate::BlockKind::RoseBush => false, + crate::BlockKind::Sand => true, + crate::BlockKind::Sandstone => true, + crate::BlockKind::SandstoneSlab => true, + crate::BlockKind::SandstoneStairs => true, + crate::BlockKind::SeaLantern => true, + crate::BlockKind::SeaPickle => true, + crate::BlockKind::Seagrass => false, + crate::BlockKind::ShulkerBox => true, + crate::BlockKind::Sign => false, + crate::BlockKind::SkeletonSkull => true, + crate::BlockKind::SkeletonWallSkull => true, + crate::BlockKind::SlimeBlock => true, + crate::BlockKind::SmoothQuartz => true, + crate::BlockKind::SmoothRedSandstone => true, + crate::BlockKind::SmoothSandstone => true, + crate::BlockKind::SmoothStone => true, + crate::BlockKind::Snow => true, + crate::BlockKind::SnowBlock => true, + crate::BlockKind::SoulSand => true, + crate::BlockKind::Spawner => true, + crate::BlockKind::Sponge => true, + crate::BlockKind::SpruceButton => false, + crate::BlockKind::SpruceDoor => true, + crate::BlockKind::SpruceFence => true, + crate::BlockKind::SpruceFenceGate => true, + crate::BlockKind::SpruceLeaves => true, + crate::BlockKind::SpruceLog => true, + crate::BlockKind::SprucePlanks => true, + crate::BlockKind::SprucePressurePlate => false, + crate::BlockKind::SpruceSapling => false, + crate::BlockKind::SpruceSlab => true, + crate::BlockKind::SpruceStairs => true, + crate::BlockKind::SpruceTrapdoor => true, + crate::BlockKind::SpruceWood => true, + crate::BlockKind::StickyPiston => true, + crate::BlockKind::Stone => true, + crate::BlockKind::StoneBrickSlab => true, + crate::BlockKind::StoneBrickStairs => true, + crate::BlockKind::StoneBricks => true, + crate::BlockKind::StoneButton => false, + crate::BlockKind::StonePressurePlate => false, + crate::BlockKind::StoneSlab => true, + crate::BlockKind::StrippedAcaciaLog => true, + crate::BlockKind::StrippedAcaciaWood => true, + crate::BlockKind::StrippedBirchLog => true, + crate::BlockKind::StrippedBirchWood => true, + crate::BlockKind::StrippedDarkOakLog => true, + crate::BlockKind::StrippedDarkOakWood => true, + crate::BlockKind::StrippedJungleLog => true, + crate::BlockKind::StrippedJungleWood => true, + crate::BlockKind::StrippedOakLog => true, + crate::BlockKind::StrippedOakWood => true, + crate::BlockKind::StrippedSpruceLog => true, + crate::BlockKind::StrippedSpruceWood => true, + crate::BlockKind::StructureBlock => true, + crate::BlockKind::StructureVoid => false, + crate::BlockKind::SugarCane => false, + crate::BlockKind::Sunflower => false, + crate::BlockKind::TallGrass => false, + crate::BlockKind::TallSeagrass => false, + crate::BlockKind::Terracotta => true, + crate::BlockKind::Tnt => true, + crate::BlockKind::Torch => false, + crate::BlockKind::TrappedChest => true, + crate::BlockKind::Tripwire => false, + crate::BlockKind::TripwireHook => false, + crate::BlockKind::TubeCoral => false, + crate::BlockKind::TubeCoralBlock => true, + crate::BlockKind::TubeCoralFan => false, + crate::BlockKind::TubeCoralWallFan => false, + crate::BlockKind::TurtleEgg => true, + crate::BlockKind::Vine => false, + crate::BlockKind::VoidAir => false, + crate::BlockKind::WallSign => false, + crate::BlockKind::WallTorch => false, + crate::BlockKind::Water => false, + crate::BlockKind::WetSponge => true, + crate::BlockKind::Wheat => false, + crate::BlockKind::WhiteBanner => false, + crate::BlockKind::WhiteBed => true, + crate::BlockKind::WhiteCarpet => true, + crate::BlockKind::WhiteConcrete => true, + crate::BlockKind::WhiteConcretePowder => true, + crate::BlockKind::WhiteGlazedTerracotta => true, + crate::BlockKind::WhiteShulkerBox => true, + crate::BlockKind::WhiteStainedGlass => true, + crate::BlockKind::WhiteStainedGlassPane => true, + crate::BlockKind::WhiteTerracotta => true, + crate::BlockKind::WhiteTulip => false, + crate::BlockKind::WhiteWallBanner => false, + crate::BlockKind::WhiteWool => true, + crate::BlockKind::WitherSkeletonSkull => true, + crate::BlockKind::WitherSkeletonWallSkull => true, + crate::BlockKind::YellowBanner => false, + crate::BlockKind::YellowBed => true, + crate::BlockKind::YellowCarpet => true, + crate::BlockKind::YellowConcrete => true, + crate::BlockKind::YellowConcretePowder => true, + crate::BlockKind::YellowGlazedTerracotta => true, + crate::BlockKind::YellowShulkerBox => true, + crate::BlockKind::YellowStainedGlass => true, + crate::BlockKind::YellowStainedGlassPane => true, + crate::BlockKind::YellowTerracotta => true, + crate::BlockKind::YellowWallBanner => false, + crate::BlockKind::YellowWool => true, + crate::BlockKind::ZombieHead => true, + crate::BlockKind::ZombieWallHead => true, + _ => false, + } + } +} +impl crate::BlockKind { + pub fn full_block(self) -> bool { + match self { + crate::BlockKind::AcaciaButton => false, + crate::BlockKind::AcaciaDoor => false, + crate::BlockKind::AcaciaFence => false, + crate::BlockKind::AcaciaFenceGate => false, + crate::BlockKind::AcaciaLeaves => true, + crate::BlockKind::AcaciaLog => true, + crate::BlockKind::AcaciaPlanks => true, + crate::BlockKind::AcaciaPressurePlate => false, + crate::BlockKind::AcaciaSapling => false, + crate::BlockKind::AcaciaSlab => false, + crate::BlockKind::AcaciaStairs => false, + crate::BlockKind::AcaciaTrapdoor => false, + crate::BlockKind::AcaciaWood => true, + crate::BlockKind::ActivatorRail => false, + crate::BlockKind::Air => false, + crate::BlockKind::Allium => false, + crate::BlockKind::Andesite => true, + crate::BlockKind::Anvil => false, + crate::BlockKind::AttachedMelonStem => false, + crate::BlockKind::AttachedPumpkinStem => false, + crate::BlockKind::AzureBluet => false, + crate::BlockKind::Barrier => true, + crate::BlockKind::Beacon => true, + crate::BlockKind::Bedrock => true, + crate::BlockKind::Beetroots => false, + crate::BlockKind::BirchButton => false, + crate::BlockKind::BirchDoor => false, + crate::BlockKind::BirchFence => false, + crate::BlockKind::BirchFenceGate => false, + crate::BlockKind::BirchLeaves => true, + crate::BlockKind::BirchLog => true, + crate::BlockKind::BirchPlanks => true, + crate::BlockKind::BirchPressurePlate => false, + crate::BlockKind::BirchSapling => false, + crate::BlockKind::BirchSlab => false, + crate::BlockKind::BirchStairs => false, + crate::BlockKind::BirchTrapdoor => false, + crate::BlockKind::BirchWood => true, + crate::BlockKind::BlackBanner => false, + crate::BlockKind::BlackBed => false, + crate::BlockKind::BlackCarpet => false, + crate::BlockKind::BlackConcrete => true, + crate::BlockKind::BlackConcretePowder => true, + crate::BlockKind::BlackGlazedTerracotta => true, + crate::BlockKind::BlackShulkerBox => true, + crate::BlockKind::BlackStainedGlass => true, + crate::BlockKind::BlackStainedGlassPane => false, + crate::BlockKind::BlackTerracotta => true, + crate::BlockKind::BlackWallBanner => false, + crate::BlockKind::BlackWool => true, + crate::BlockKind::BlueBanner => false, + crate::BlockKind::BlueBed => false, + crate::BlockKind::BlueCarpet => false, + crate::BlockKind::BlueConcrete => true, + crate::BlockKind::BlueConcretePowder => true, + crate::BlockKind::BlueGlazedTerracotta => true, + crate::BlockKind::BlueIce => true, + crate::BlockKind::BlueOrchid => false, + crate::BlockKind::BlueShulkerBox => true, + crate::BlockKind::BlueStainedGlass => true, + crate::BlockKind::BlueStainedGlassPane => false, + crate::BlockKind::BlueTerracotta => true, + crate::BlockKind::BlueWallBanner => false, + crate::BlockKind::BlueWool => true, + crate::BlockKind::BoneBlock => true, + crate::BlockKind::Bookshelf => true, + crate::BlockKind::BrainCoral => false, + crate::BlockKind::BrainCoralBlock => true, + crate::BlockKind::BrainCoralFan => false, + crate::BlockKind::BrainCoralWallFan => false, + crate::BlockKind::BrewingStand => false, + crate::BlockKind::BrickSlab => false, + crate::BlockKind::BrickStairs => false, + crate::BlockKind::Bricks => true, + crate::BlockKind::BrownBanner => false, + crate::BlockKind::BrownBed => false, + crate::BlockKind::BrownCarpet => false, + crate::BlockKind::BrownConcrete => true, + crate::BlockKind::BrownConcretePowder => true, + crate::BlockKind::BrownGlazedTerracotta => true, + crate::BlockKind::BrownMushroom => false, + crate::BlockKind::BrownMushroomBlock => true, + crate::BlockKind::BrownShulkerBox => true, + crate::BlockKind::BrownStainedGlass => true, + crate::BlockKind::BrownStainedGlassPane => false, + crate::BlockKind::BrownTerracotta => true, + crate::BlockKind::BrownWallBanner => false, + crate::BlockKind::BrownWool => true, + crate::BlockKind::BubbleColumn => false, + crate::BlockKind::BubbleCoral => false, + crate::BlockKind::BubbleCoralBlock => true, + crate::BlockKind::BubbleCoralFan => false, + crate::BlockKind::BubbleCoralWallFan => false, + crate::BlockKind::Cactus => false, + crate::BlockKind::Cake => false, + crate::BlockKind::Carrots => false, + crate::BlockKind::CarvedPumpkin => true, + crate::BlockKind::Cauldron => false, + crate::BlockKind::CaveAir => false, + crate::BlockKind::ChainCommandBlock => true, + crate::BlockKind::Chest => false, + crate::BlockKind::ChippedAnvil => false, + crate::BlockKind::ChiseledQuartzBlock => true, + crate::BlockKind::ChiseledRedSandstone => true, + crate::BlockKind::ChiseledSandstone => true, + crate::BlockKind::ChiseledStoneBricks => true, + crate::BlockKind::ChorusFlower => true, + crate::BlockKind::ChorusPlant => false, + crate::BlockKind::Clay => true, + crate::BlockKind::CoalBlock => true, + crate::BlockKind::CoalOre => true, + crate::BlockKind::CoarseDirt => true, + crate::BlockKind::Cobblestone => true, + crate::BlockKind::CobblestoneSlab => false, + crate::BlockKind::CobblestoneStairs => false, + crate::BlockKind::CobblestoneWall => false, + crate::BlockKind::Cobweb => false, + crate::BlockKind::Cocoa => false, + crate::BlockKind::CommandBlock => true, + crate::BlockKind::Comparator => false, + crate::BlockKind::Conduit => false, + crate::BlockKind::CrackedStoneBricks => true, + crate::BlockKind::CraftingTable => true, + crate::BlockKind::CreeperHead => false, + crate::BlockKind::CreeperWallHead => false, + crate::BlockKind::CutRedSandstone => true, + crate::BlockKind::CutSandstone => true, + crate::BlockKind::CyanBanner => false, + crate::BlockKind::CyanBed => false, + crate::BlockKind::CyanCarpet => false, + crate::BlockKind::CyanConcrete => true, + crate::BlockKind::CyanConcretePowder => true, + crate::BlockKind::CyanGlazedTerracotta => true, + crate::BlockKind::CyanShulkerBox => true, + crate::BlockKind::CyanStainedGlass => true, + crate::BlockKind::CyanStainedGlassPane => false, + crate::BlockKind::CyanTerracotta => true, + crate::BlockKind::CyanWallBanner => false, + crate::BlockKind::CyanWool => true, + crate::BlockKind::DamagedAnvil => false, + crate::BlockKind::Dandelion => false, + crate::BlockKind::DarkOakButton => false, + crate::BlockKind::DarkOakDoor => false, + crate::BlockKind::DarkOakFence => false, + crate::BlockKind::DarkOakFenceGate => false, + crate::BlockKind::DarkOakLeaves => true, + crate::BlockKind::DarkOakLog => true, + crate::BlockKind::DarkOakPlanks => true, + crate::BlockKind::DarkOakPressurePlate => false, + crate::BlockKind::DarkOakSapling => false, + crate::BlockKind::DarkOakSlab => false, + crate::BlockKind::DarkOakStairs => false, + crate::BlockKind::DarkOakTrapdoor => false, + crate::BlockKind::DarkOakWood => true, + crate::BlockKind::DarkPrismarine => true, + crate::BlockKind::DarkPrismarineSlab => false, + crate::BlockKind::DarkPrismarineStairs => false, + crate::BlockKind::DaylightDetector => false, + crate::BlockKind::DeadBrainCoral => false, + crate::BlockKind::DeadBrainCoralBlock => true, + crate::BlockKind::DeadBrainCoralFan => false, + crate::BlockKind::DeadBrainCoralWallFan => false, + crate::BlockKind::DeadBubbleCoral => false, + crate::BlockKind::DeadBubbleCoralBlock => true, + crate::BlockKind::DeadBubbleCoralFan => false, + crate::BlockKind::DeadBubbleCoralWallFan => false, + crate::BlockKind::DeadBush => false, + crate::BlockKind::DeadFireCoral => false, + crate::BlockKind::DeadFireCoralBlock => true, + crate::BlockKind::DeadFireCoralFan => false, + crate::BlockKind::DeadFireCoralWallFan => false, + crate::BlockKind::DeadHornCoral => false, + crate::BlockKind::DeadHornCoralBlock => true, + crate::BlockKind::DeadHornCoralFan => false, + crate::BlockKind::DeadHornCoralWallFan => false, + crate::BlockKind::DeadTubeCoral => false, + crate::BlockKind::DeadTubeCoralBlock => true, + crate::BlockKind::DeadTubeCoralFan => false, + crate::BlockKind::DeadTubeCoralWallFan => false, + crate::BlockKind::DetectorRail => false, + crate::BlockKind::DiamondBlock => true, + crate::BlockKind::DiamondOre => true, + crate::BlockKind::Diorite => true, + crate::BlockKind::Dirt => true, + crate::BlockKind::Dispenser => true, + crate::BlockKind::DragonEgg => false, + crate::BlockKind::DragonHead => false, + crate::BlockKind::DragonWallHead => false, + crate::BlockKind::DriedKelpBlock => true, + crate::BlockKind::Dropper => true, + crate::BlockKind::EmeraldBlock => true, + crate::BlockKind::EmeraldOre => true, + crate::BlockKind::EnchantingTable => false, + crate::BlockKind::EndGateway => false, + crate::BlockKind::EndPortal => false, + crate::BlockKind::EndPortalFrame => false, + crate::BlockKind::EndRod => false, + crate::BlockKind::EndStone => true, + crate::BlockKind::EndStoneBricks => true, + crate::BlockKind::EnderChest => false, + crate::BlockKind::Farmland => false, + crate::BlockKind::Fern => false, + crate::BlockKind::Fire => false, + crate::BlockKind::FireCoral => false, + crate::BlockKind::FireCoralBlock => true, + crate::BlockKind::FireCoralFan => false, + crate::BlockKind::FireCoralWallFan => false, + crate::BlockKind::FlowerPot => false, + crate::BlockKind::FrostedIce => true, + crate::BlockKind::Furnace => true, + crate::BlockKind::Glass => true, + crate::BlockKind::GlassPane => false, + crate::BlockKind::Glowstone => true, + crate::BlockKind::GoldBlock => true, + crate::BlockKind::GoldOre => true, + crate::BlockKind::Granite => true, + crate::BlockKind::Grass => false, + crate::BlockKind::GrassBlock => true, + crate::BlockKind::GrassPath => false, + crate::BlockKind::Gravel => true, + crate::BlockKind::GrayBanner => false, + crate::BlockKind::GrayBed => false, + crate::BlockKind::GrayCarpet => false, + crate::BlockKind::GrayConcrete => true, + crate::BlockKind::GrayConcretePowder => true, + crate::BlockKind::GrayGlazedTerracotta => true, + crate::BlockKind::GrayShulkerBox => true, + crate::BlockKind::GrayStainedGlass => true, + crate::BlockKind::GrayStainedGlassPane => false, + crate::BlockKind::GrayTerracotta => true, + crate::BlockKind::GrayWallBanner => false, + crate::BlockKind::GrayWool => true, + crate::BlockKind::GreenBanner => false, + crate::BlockKind::GreenBed => false, + crate::BlockKind::GreenCarpet => false, + crate::BlockKind::GreenConcrete => true, + crate::BlockKind::GreenConcretePowder => true, + crate::BlockKind::GreenGlazedTerracotta => true, + crate::BlockKind::GreenShulkerBox => true, + crate::BlockKind::GreenStainedGlass => true, + crate::BlockKind::GreenStainedGlassPane => false, + crate::BlockKind::GreenTerracotta => true, + crate::BlockKind::GreenWallBanner => false, + crate::BlockKind::GreenWool => true, + crate::BlockKind::HayBlock => true, + crate::BlockKind::HeavyWeightedPressurePlate => false, + crate::BlockKind::Hopper => false, + crate::BlockKind::HornCoral => false, + crate::BlockKind::HornCoralBlock => true, + crate::BlockKind::HornCoralFan => false, + crate::BlockKind::HornCoralWallFan => false, + crate::BlockKind::Ice => true, + crate::BlockKind::InfestedChiseledStoneBricks => true, + crate::BlockKind::InfestedCobblestone => true, + crate::BlockKind::InfestedCrackedStoneBricks => true, + crate::BlockKind::InfestedMossyStoneBricks => true, + crate::BlockKind::InfestedStone => true, + crate::BlockKind::InfestedStoneBricks => true, + crate::BlockKind::IronBars => false, + crate::BlockKind::IronBlock => true, + crate::BlockKind::IronDoor => false, + crate::BlockKind::IronOre => true, + crate::BlockKind::IronTrapdoor => false, + crate::BlockKind::JackOLantern => true, + crate::BlockKind::Jukebox => true, + crate::BlockKind::JungleButton => false, + crate::BlockKind::JungleDoor => false, + crate::BlockKind::JungleFence => false, + crate::BlockKind::JungleFenceGate => false, + crate::BlockKind::JungleLeaves => true, + crate::BlockKind::JungleLog => true, + crate::BlockKind::JunglePlanks => true, + crate::BlockKind::JunglePressurePlate => false, + crate::BlockKind::JungleSapling => false, + crate::BlockKind::JungleSlab => false, + crate::BlockKind::JungleStairs => false, + crate::BlockKind::JungleTrapdoor => false, + crate::BlockKind::JungleWood => true, + crate::BlockKind::Kelp => false, + crate::BlockKind::KelpPlant => false, + crate::BlockKind::Ladder => false, + crate::BlockKind::LapisBlock => true, + crate::BlockKind::LapisOre => true, + crate::BlockKind::LargeFern => false, + crate::BlockKind::Lava => false, + crate::BlockKind::Lever => false, + crate::BlockKind::LightBlueBanner => false, + crate::BlockKind::LightBlueBed => false, + crate::BlockKind::LightBlueCarpet => false, + crate::BlockKind::LightBlueConcrete => true, + crate::BlockKind::LightBlueConcretePowder => true, + crate::BlockKind::LightBlueGlazedTerracotta => true, + crate::BlockKind::LightBlueShulkerBox => true, + crate::BlockKind::LightBlueStainedGlass => true, + crate::BlockKind::LightBlueStainedGlassPane => false, + crate::BlockKind::LightBlueTerracotta => true, + crate::BlockKind::LightBlueWallBanner => false, + crate::BlockKind::LightBlueWool => true, + crate::BlockKind::LightGrayBanner => false, + crate::BlockKind::LightGrayBed => false, + crate::BlockKind::LightGrayCarpet => false, + crate::BlockKind::LightGrayConcrete => true, + crate::BlockKind::LightGrayConcretePowder => true, + crate::BlockKind::LightGrayGlazedTerracotta => true, + crate::BlockKind::LightGrayShulkerBox => true, + crate::BlockKind::LightGrayStainedGlass => true, + crate::BlockKind::LightGrayStainedGlassPane => false, + crate::BlockKind::LightGrayTerracotta => true, + crate::BlockKind::LightGrayWallBanner => false, + crate::BlockKind::LightGrayWool => true, + crate::BlockKind::LightWeightedPressurePlate => false, + crate::BlockKind::Lilac => false, + crate::BlockKind::LilyPad => false, + crate::BlockKind::LimeBanner => false, + crate::BlockKind::LimeBed => false, + crate::BlockKind::LimeCarpet => false, + crate::BlockKind::LimeConcrete => true, + crate::BlockKind::LimeConcretePowder => true, + crate::BlockKind::LimeGlazedTerracotta => true, + crate::BlockKind::LimeShulkerBox => true, + crate::BlockKind::LimeStainedGlass => true, + crate::BlockKind::LimeStainedGlassPane => false, + crate::BlockKind::LimeTerracotta => true, + crate::BlockKind::LimeWallBanner => false, + crate::BlockKind::LimeWool => true, + crate::BlockKind::MagentaBanner => false, + crate::BlockKind::MagentaBed => false, + crate::BlockKind::MagentaCarpet => false, + crate::BlockKind::MagentaConcrete => true, + crate::BlockKind::MagentaConcretePowder => true, + crate::BlockKind::MagentaGlazedTerracotta => true, + crate::BlockKind::MagentaShulkerBox => true, + crate::BlockKind::MagentaStainedGlass => true, + crate::BlockKind::MagentaStainedGlassPane => false, + crate::BlockKind::MagentaTerracotta => true, + crate::BlockKind::MagentaWallBanner => false, + crate::BlockKind::MagentaWool => true, + crate::BlockKind::MagmaBlock => true, + crate::BlockKind::Melon => true, + crate::BlockKind::MelonStem => false, + crate::BlockKind::MossyCobblestone => true, + crate::BlockKind::MossyCobblestoneWall => false, + crate::BlockKind::MossyStoneBricks => true, + crate::BlockKind::MovingPiston => false, + crate::BlockKind::MushroomStem => true, + crate::BlockKind::Mycelium => true, + crate::BlockKind::NetherBrickFence => false, + crate::BlockKind::NetherBrickSlab => false, + crate::BlockKind::NetherBrickStairs => false, + crate::BlockKind::NetherBricks => true, + crate::BlockKind::NetherPortal => false, + crate::BlockKind::NetherQuartzOre => true, + crate::BlockKind::NetherWart => false, + crate::BlockKind::NetherWartBlock => true, + crate::BlockKind::Netherrack => true, + crate::BlockKind::NoteBlock => true, + crate::BlockKind::OakButton => false, + crate::BlockKind::OakDoor => false, + crate::BlockKind::OakFence => false, + crate::BlockKind::OakFenceGate => false, + crate::BlockKind::OakLeaves => true, + crate::BlockKind::OakLog => true, + crate::BlockKind::OakPlanks => true, + crate::BlockKind::OakPressurePlate => false, + crate::BlockKind::OakSapling => false, + crate::BlockKind::OakSlab => false, + crate::BlockKind::OakStairs => false, + crate::BlockKind::OakTrapdoor => false, + crate::BlockKind::OakWood => true, + crate::BlockKind::Observer => true, + crate::BlockKind::Obsidian => true, + crate::BlockKind::OrangeBanner => false, + crate::BlockKind::OrangeBed => false, + crate::BlockKind::OrangeCarpet => false, + crate::BlockKind::OrangeConcrete => true, + crate::BlockKind::OrangeConcretePowder => true, + crate::BlockKind::OrangeGlazedTerracotta => true, + crate::BlockKind::OrangeShulkerBox => true, + crate::BlockKind::OrangeStainedGlass => true, + crate::BlockKind::OrangeStainedGlassPane => false, + crate::BlockKind::OrangeTerracotta => true, + crate::BlockKind::OrangeTulip => false, + crate::BlockKind::OrangeWallBanner => false, + crate::BlockKind::OrangeWool => true, + crate::BlockKind::OxeyeDaisy => false, + crate::BlockKind::PackedIce => true, + crate::BlockKind::Peony => false, + crate::BlockKind::PetrifiedOakSlab => false, + crate::BlockKind::PinkBanner => false, + crate::BlockKind::PinkBed => false, + crate::BlockKind::PinkCarpet => false, + crate::BlockKind::PinkConcrete => true, + crate::BlockKind::PinkConcretePowder => true, + crate::BlockKind::PinkGlazedTerracotta => true, + crate::BlockKind::PinkShulkerBox => true, + crate::BlockKind::PinkStainedGlass => true, + crate::BlockKind::PinkStainedGlassPane => false, + crate::BlockKind::PinkTerracotta => true, + crate::BlockKind::PinkTulip => false, + crate::BlockKind::PinkWallBanner => false, + crate::BlockKind::PinkWool => true, + crate::BlockKind::Piston => false, + crate::BlockKind::PistonHead => false, + crate::BlockKind::PlayerHead => false, + crate::BlockKind::PlayerWallHead => false, + crate::BlockKind::Podzol => true, + crate::BlockKind::PolishedAndesite => true, + crate::BlockKind::PolishedDiorite => true, + crate::BlockKind::PolishedGranite => true, + crate::BlockKind::Poppy => false, + crate::BlockKind::Potatoes => false, + crate::BlockKind::PottedAcaciaSapling => false, + crate::BlockKind::PottedAllium => false, + crate::BlockKind::PottedAzureBluet => false, + crate::BlockKind::PottedBirchSapling => false, + crate::BlockKind::PottedBlueOrchid => false, + crate::BlockKind::PottedBrownMushroom => false, + crate::BlockKind::PottedCactus => false, + crate::BlockKind::PottedDandelion => false, + crate::BlockKind::PottedDarkOakSapling => false, + crate::BlockKind::PottedDeadBush => false, + crate::BlockKind::PottedFern => false, + crate::BlockKind::PottedJungleSapling => false, + crate::BlockKind::PottedOakSapling => false, + crate::BlockKind::PottedOrangeTulip => false, + crate::BlockKind::PottedOxeyeDaisy => false, + crate::BlockKind::PottedPinkTulip => false, + crate::BlockKind::PottedPoppy => false, + crate::BlockKind::PottedRedMushroom => false, + crate::BlockKind::PottedRedTulip => false, + crate::BlockKind::PottedSpruceSapling => false, + crate::BlockKind::PottedWhiteTulip => false, + crate::BlockKind::PoweredRail => false, + crate::BlockKind::Prismarine => true, + crate::BlockKind::PrismarineBrickSlab => false, + crate::BlockKind::PrismarineBrickStairs => false, + crate::BlockKind::PrismarineBricks => true, + crate::BlockKind::PrismarineSlab => false, + crate::BlockKind::PrismarineStairs => false, + crate::BlockKind::Pumpkin => true, + crate::BlockKind::PumpkinStem => false, + crate::BlockKind::PurpleBanner => false, + crate::BlockKind::PurpleBed => false, + crate::BlockKind::PurpleCarpet => false, + crate::BlockKind::PurpleConcrete => true, + crate::BlockKind::PurpleConcretePowder => true, + crate::BlockKind::PurpleGlazedTerracotta => true, + crate::BlockKind::PurpleShulkerBox => true, + crate::BlockKind::PurpleStainedGlass => true, + crate::BlockKind::PurpleStainedGlassPane => false, + crate::BlockKind::PurpleTerracotta => true, + crate::BlockKind::PurpleWallBanner => false, + crate::BlockKind::PurpleWool => true, + crate::BlockKind::PurpurBlock => true, + crate::BlockKind::PurpurPillar => true, + crate::BlockKind::PurpurSlab => false, + crate::BlockKind::PurpurStairs => false, + crate::BlockKind::QuartzBlock => true, + crate::BlockKind::QuartzPillar => true, + crate::BlockKind::QuartzSlab => false, + crate::BlockKind::QuartzStairs => false, + crate::BlockKind::Rail => false, + crate::BlockKind::RedBanner => false, + crate::BlockKind::RedBed => false, + crate::BlockKind::RedCarpet => false, + crate::BlockKind::RedConcrete => true, + crate::BlockKind::RedConcretePowder => true, + crate::BlockKind::RedGlazedTerracotta => true, + crate::BlockKind::RedMushroom => false, + crate::BlockKind::RedMushroomBlock => true, + crate::BlockKind::RedNetherBricks => true, + crate::BlockKind::RedSand => true, + crate::BlockKind::RedSandstone => true, + crate::BlockKind::RedSandstoneSlab => false, + crate::BlockKind::RedSandstoneStairs => false, + crate::BlockKind::RedShulkerBox => true, + crate::BlockKind::RedStainedGlass => true, + crate::BlockKind::RedStainedGlassPane => false, + crate::BlockKind::RedTerracotta => true, + crate::BlockKind::RedTulip => false, + crate::BlockKind::RedWallBanner => false, + crate::BlockKind::RedWool => true, + crate::BlockKind::RedstoneBlock => true, + crate::BlockKind::RedstoneLamp => true, + crate::BlockKind::RedstoneOre => true, + crate::BlockKind::RedstoneTorch => false, + crate::BlockKind::RedstoneWallTorch => false, + crate::BlockKind::RedstoneWire => false, + crate::BlockKind::Repeater => false, + crate::BlockKind::RepeatingCommandBlock => true, + crate::BlockKind::RoseBush => false, + crate::BlockKind::Sand => true, + crate::BlockKind::Sandstone => true, + crate::BlockKind::SandstoneSlab => false, + crate::BlockKind::SandstoneStairs => false, + crate::BlockKind::SeaLantern => true, + crate::BlockKind::SeaPickle => false, + crate::BlockKind::Seagrass => false, + crate::BlockKind::ShulkerBox => true, + crate::BlockKind::Sign => false, + crate::BlockKind::SkeletonSkull => false, + crate::BlockKind::SkeletonWallSkull => false, + crate::BlockKind::SlimeBlock => true, + crate::BlockKind::SmoothQuartz => true, + crate::BlockKind::SmoothRedSandstone => true, + crate::BlockKind::SmoothSandstone => true, + crate::BlockKind::SmoothStone => true, + crate::BlockKind::Snow => false, + crate::BlockKind::SnowBlock => true, + crate::BlockKind::SoulSand => false, + crate::BlockKind::Spawner => true, + crate::BlockKind::Sponge => true, + crate::BlockKind::SpruceButton => false, + crate::BlockKind::SpruceDoor => false, + crate::BlockKind::SpruceFence => false, + crate::BlockKind::SpruceFenceGate => false, + crate::BlockKind::SpruceLeaves => true, + crate::BlockKind::SpruceLog => true, + crate::BlockKind::SprucePlanks => true, + crate::BlockKind::SprucePressurePlate => false, + crate::BlockKind::SpruceSapling => false, + crate::BlockKind::SpruceSlab => false, + crate::BlockKind::SpruceStairs => false, + crate::BlockKind::SpruceTrapdoor => false, + crate::BlockKind::SpruceWood => true, + crate::BlockKind::StickyPiston => false, + crate::BlockKind::Stone => true, + crate::BlockKind::StoneBrickSlab => false, + crate::BlockKind::StoneBrickStairs => false, + crate::BlockKind::StoneBricks => true, + crate::BlockKind::StoneButton => false, + crate::BlockKind::StonePressurePlate => false, + crate::BlockKind::StoneSlab => false, + crate::BlockKind::StrippedAcaciaLog => true, + crate::BlockKind::StrippedAcaciaWood => true, + crate::BlockKind::StrippedBirchLog => true, + crate::BlockKind::StrippedBirchWood => true, + crate::BlockKind::StrippedDarkOakLog => true, + crate::BlockKind::StrippedDarkOakWood => true, + crate::BlockKind::StrippedJungleLog => true, + crate::BlockKind::StrippedJungleWood => true, + crate::BlockKind::StrippedOakLog => true, + crate::BlockKind::StrippedOakWood => true, + crate::BlockKind::StrippedSpruceLog => true, + crate::BlockKind::StrippedSpruceWood => true, + crate::BlockKind::StructureBlock => true, + crate::BlockKind::StructureVoid => false, + crate::BlockKind::SugarCane => false, + crate::BlockKind::Sunflower => false, + crate::BlockKind::TallGrass => false, + crate::BlockKind::TallSeagrass => false, + crate::BlockKind::Terracotta => true, + crate::BlockKind::Tnt => true, + crate::BlockKind::Torch => false, + crate::BlockKind::TrappedChest => false, + crate::BlockKind::Tripwire => false, + crate::BlockKind::TripwireHook => false, + crate::BlockKind::TubeCoral => false, + crate::BlockKind::TubeCoralBlock => true, + crate::BlockKind::TubeCoralFan => false, + crate::BlockKind::TubeCoralWallFan => false, + crate::BlockKind::TurtleEgg => false, + crate::BlockKind::Vine => false, + crate::BlockKind::VoidAir => false, + crate::BlockKind::WallSign => false, + crate::BlockKind::WallTorch => false, + crate::BlockKind::Water => false, + crate::BlockKind::WetSponge => true, + crate::BlockKind::Wheat => false, + crate::BlockKind::WhiteBanner => false, + crate::BlockKind::WhiteBed => false, + crate::BlockKind::WhiteCarpet => false, + crate::BlockKind::WhiteConcrete => true, + crate::BlockKind::WhiteConcretePowder => true, + crate::BlockKind::WhiteGlazedTerracotta => true, + crate::BlockKind::WhiteShulkerBox => true, + crate::BlockKind::WhiteStainedGlass => true, + crate::BlockKind::WhiteStainedGlassPane => false, + crate::BlockKind::WhiteTerracotta => true, + crate::BlockKind::WhiteTulip => false, + crate::BlockKind::WhiteWallBanner => false, + crate::BlockKind::WhiteWool => true, + crate::BlockKind::WitherSkeletonSkull => false, + crate::BlockKind::WitherSkeletonWallSkull => false, + crate::BlockKind::YellowBanner => false, + crate::BlockKind::YellowBed => false, + crate::BlockKind::YellowCarpet => false, + crate::BlockKind::YellowConcrete => true, + crate::BlockKind::YellowConcretePowder => true, + crate::BlockKind::YellowGlazedTerracotta => true, + crate::BlockKind::YellowShulkerBox => true, + crate::BlockKind::YellowStainedGlass => true, + crate::BlockKind::YellowStainedGlassPane => false, + crate::BlockKind::YellowTerracotta => true, + crate::BlockKind::YellowWallBanner => false, + crate::BlockKind::YellowWool => true, + crate::BlockKind::ZombieHead => false, + crate::BlockKind::ZombieWallHead => false, + _ => false, + } + } +} +impl crate::BlockKind { + pub fn to_simplified_kind(self) -> crate::SimplifiedBlockKind { + match self { + crate::BlockKind::AcaciaButton => crate::SimplifiedBlockKind::WoodenButton, + crate::BlockKind::AcaciaDoor => crate::SimplifiedBlockKind::WoodenDoor, + crate::BlockKind::AcaciaFence => crate::SimplifiedBlockKind::Fence, + crate::BlockKind::AcaciaFenceGate => crate::SimplifiedBlockKind::FenceGate, + crate::BlockKind::AcaciaLeaves => crate::SimplifiedBlockKind::Leaves, + crate::BlockKind::AcaciaLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::AcaciaPlanks => crate::SimplifiedBlockKind::Planks, + crate::BlockKind::AcaciaPressurePlate => { + crate::SimplifiedBlockKind::WoodenPressurePlate + } + crate::BlockKind::AcaciaSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::AcaciaSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::AcaciaStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::AcaciaTrapdoor => crate::SimplifiedBlockKind::WoodenTrapdoor, + crate::BlockKind::AcaciaWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::ActivatorRail => crate::SimplifiedBlockKind::ActivatorRail, + crate::BlockKind::Air => crate::SimplifiedBlockKind::Air, + crate::BlockKind::Allium => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::Andesite => crate::SimplifiedBlockKind::Andesite, + crate::BlockKind::Anvil => crate::SimplifiedBlockKind::Anvil, + crate::BlockKind::AttachedMelonStem => crate::SimplifiedBlockKind::AttachedMelonStem, + crate::BlockKind::AttachedPumpkinStem => { + crate::SimplifiedBlockKind::AttachedPumpkinStem + } + crate::BlockKind::AzureBluet => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::Barrier => crate::SimplifiedBlockKind::Barrier, + crate::BlockKind::Beacon => crate::SimplifiedBlockKind::Beacon, + crate::BlockKind::Bedrock => crate::SimplifiedBlockKind::Bedrock, + crate::BlockKind::Beetroots => crate::SimplifiedBlockKind::Beetroots, + crate::BlockKind::BirchButton => crate::SimplifiedBlockKind::WoodenButton, + crate::BlockKind::BirchDoor => crate::SimplifiedBlockKind::WoodenDoor, + crate::BlockKind::BirchFence => crate::SimplifiedBlockKind::Fence, + crate::BlockKind::BirchFenceGate => crate::SimplifiedBlockKind::FenceGate, + crate::BlockKind::BirchLeaves => crate::SimplifiedBlockKind::Leaves, + crate::BlockKind::BirchLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::BirchPlanks => crate::SimplifiedBlockKind::Planks, + crate::BlockKind::BirchPressurePlate => crate::SimplifiedBlockKind::WoodenPressurePlate, + crate::BlockKind::BirchSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::BirchSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::BirchStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::BirchTrapdoor => crate::SimplifiedBlockKind::WoodenTrapdoor, + crate::BlockKind::BirchWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::BlackBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::BlackBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::BlackCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::BlackConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::BlackConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::BlackGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::BlackShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::BlackStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::BlackStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::BlackTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::BlackWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::BlackWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::BlueBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::BlueBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::BlueCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::BlueConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::BlueConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::BlueGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::BlueIce => crate::SimplifiedBlockKind::BlueIce, + crate::BlockKind::BlueOrchid => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::BlueShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::BlueStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::BlueStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::BlueTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::BlueWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::BlueWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::BoneBlock => crate::SimplifiedBlockKind::BoneBlock, + crate::BlockKind::Bookshelf => crate::SimplifiedBlockKind::Bookshelf, + crate::BlockKind::BrainCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::BrainCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::BrainCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::BrainCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::BrewingStand => crate::SimplifiedBlockKind::BrewingStand, + crate::BlockKind::BrickSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::BrickStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::Bricks => crate::SimplifiedBlockKind::Bricks, + crate::BlockKind::BrownBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::BrownBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::BrownCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::BrownConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::BrownConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::BrownGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::BrownMushroom => crate::SimplifiedBlockKind::Mushroom, + crate::BlockKind::BrownMushroomBlock => crate::SimplifiedBlockKind::BrownMushroomBlock, + crate::BlockKind::BrownShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::BrownStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::BrownStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::BrownTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::BrownWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::BrownWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::BubbleColumn => crate::SimplifiedBlockKind::BubbleColumn, + crate::BlockKind::BubbleCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::BubbleCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::BubbleCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::BubbleCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::Cactus => crate::SimplifiedBlockKind::Cactus, + crate::BlockKind::Cake => crate::SimplifiedBlockKind::Cake, + crate::BlockKind::Carrots => crate::SimplifiedBlockKind::Carrots, + crate::BlockKind::CarvedPumpkin => crate::SimplifiedBlockKind::CarvedPumpkin, + crate::BlockKind::Cauldron => crate::SimplifiedBlockKind::Cauldron, + crate::BlockKind::CaveAir => crate::SimplifiedBlockKind::Air, + crate::BlockKind::ChainCommandBlock => crate::SimplifiedBlockKind::ChainCommandBlock, + crate::BlockKind::Chest => crate::SimplifiedBlockKind::Chest, + crate::BlockKind::ChippedAnvil => crate::SimplifiedBlockKind::Anvil, + crate::BlockKind::ChiseledQuartzBlock => { + crate::SimplifiedBlockKind::ChiseledQuartzBlock + } + crate::BlockKind::ChiseledRedSandstone => { + crate::SimplifiedBlockKind::ChiseledRedSandstone + } + crate::BlockKind::ChiseledSandstone => crate::SimplifiedBlockKind::ChiseledSandstone, + crate::BlockKind::ChiseledStoneBricks => { + crate::SimplifiedBlockKind::ChiseledStoneBricks + } + crate::BlockKind::ChorusFlower => crate::SimplifiedBlockKind::ChorusFlower, + crate::BlockKind::ChorusPlant => crate::SimplifiedBlockKind::ChorusPlant, + crate::BlockKind::Clay => crate::SimplifiedBlockKind::Clay, + crate::BlockKind::CoalBlock => crate::SimplifiedBlockKind::CoalBlock, + crate::BlockKind::CoalOre => crate::SimplifiedBlockKind::CoalOre, + crate::BlockKind::CoarseDirt => crate::SimplifiedBlockKind::CoarseDirt, + crate::BlockKind::Cobblestone => crate::SimplifiedBlockKind::Cobblestone, + crate::BlockKind::CobblestoneSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::CobblestoneStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::CobblestoneWall => crate::SimplifiedBlockKind::CobblestoneWall, + crate::BlockKind::Cobweb => crate::SimplifiedBlockKind::Cobweb, + crate::BlockKind::Cocoa => crate::SimplifiedBlockKind::Cocoa, + crate::BlockKind::CommandBlock => crate::SimplifiedBlockKind::CommandBlock, + crate::BlockKind::Comparator => crate::SimplifiedBlockKind::Comparator, + crate::BlockKind::Conduit => crate::SimplifiedBlockKind::Conduit, + crate::BlockKind::CrackedStoneBricks => crate::SimplifiedBlockKind::CrackedStoneBricks, + crate::BlockKind::CraftingTable => crate::SimplifiedBlockKind::CraftingTable, + crate::BlockKind::CreeperHead => crate::SimplifiedBlockKind::CreeperHead, + crate::BlockKind::CreeperWallHead => crate::SimplifiedBlockKind::CreeperWallHead, + crate::BlockKind::CutRedSandstone => crate::SimplifiedBlockKind::CutRedSandstone, + crate::BlockKind::CutSandstone => crate::SimplifiedBlockKind::CutSandstone, + crate::BlockKind::CyanBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::CyanBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::CyanCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::CyanConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::CyanConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::CyanGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::CyanShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::CyanStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::CyanStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::CyanTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::CyanWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::CyanWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::DamagedAnvil => crate::SimplifiedBlockKind::Anvil, + crate::BlockKind::Dandelion => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::DarkOakButton => crate::SimplifiedBlockKind::WoodenButton, + crate::BlockKind::DarkOakDoor => crate::SimplifiedBlockKind::WoodenDoor, + crate::BlockKind::DarkOakFence => crate::SimplifiedBlockKind::Fence, + crate::BlockKind::DarkOakFenceGate => crate::SimplifiedBlockKind::FenceGate, + crate::BlockKind::DarkOakLeaves => crate::SimplifiedBlockKind::Leaves, + crate::BlockKind::DarkOakLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::DarkOakPlanks => crate::SimplifiedBlockKind::Planks, + crate::BlockKind::DarkOakPressurePlate => { + crate::SimplifiedBlockKind::WoodenPressurePlate + } + crate::BlockKind::DarkOakSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::DarkOakSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::DarkOakStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::DarkOakTrapdoor => crate::SimplifiedBlockKind::WoodenTrapdoor, + crate::BlockKind::DarkOakWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::DarkPrismarine => crate::SimplifiedBlockKind::DarkPrismarine, + crate::BlockKind::DarkPrismarineSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::DarkPrismarineStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::DaylightDetector => crate::SimplifiedBlockKind::DaylightDetector, + crate::BlockKind::DeadBrainCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::DeadBrainCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::DeadBrainCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::DeadBrainCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::DeadBubbleCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::DeadBubbleCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::DeadBubbleCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::DeadBubbleCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::DeadBush => crate::SimplifiedBlockKind::DeadBush, + crate::BlockKind::DeadFireCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::DeadFireCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::DeadFireCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::DeadFireCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::DeadHornCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::DeadHornCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::DeadHornCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::DeadHornCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::DeadTubeCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::DeadTubeCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::DeadTubeCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::DeadTubeCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::DetectorRail => crate::SimplifiedBlockKind::DetectorRail, + crate::BlockKind::DiamondBlock => crate::SimplifiedBlockKind::DiamondBlock, + crate::BlockKind::DiamondOre => crate::SimplifiedBlockKind::DiamondOre, + crate::BlockKind::Diorite => crate::SimplifiedBlockKind::Diorite, + crate::BlockKind::Dirt => crate::SimplifiedBlockKind::Dirt, + crate::BlockKind::Dispenser => crate::SimplifiedBlockKind::Dispenser, + crate::BlockKind::DragonEgg => crate::SimplifiedBlockKind::DragonEgg, + crate::BlockKind::DragonHead => crate::SimplifiedBlockKind::DragonHead, + crate::BlockKind::DragonWallHead => crate::SimplifiedBlockKind::DragonWallHead, + crate::BlockKind::DriedKelpBlock => crate::SimplifiedBlockKind::DriedKelpBlock, + crate::BlockKind::Dropper => crate::SimplifiedBlockKind::Dropper, + crate::BlockKind::EmeraldBlock => crate::SimplifiedBlockKind::EmeraldBlock, + crate::BlockKind::EmeraldOre => crate::SimplifiedBlockKind::EmeraldOre, + crate::BlockKind::EnchantingTable => crate::SimplifiedBlockKind::EnchantingTable, + crate::BlockKind::EndGateway => crate::SimplifiedBlockKind::EndGateway, + crate::BlockKind::EndPortal => crate::SimplifiedBlockKind::EndPortal, + crate::BlockKind::EndPortalFrame => crate::SimplifiedBlockKind::EndPortalFrame, + crate::BlockKind::EndRod => crate::SimplifiedBlockKind::EndRod, + crate::BlockKind::EndStone => crate::SimplifiedBlockKind::EndStone, + crate::BlockKind::EndStoneBricks => crate::SimplifiedBlockKind::EndStoneBricks, + crate::BlockKind::EnderChest => crate::SimplifiedBlockKind::EnderChest, + crate::BlockKind::Farmland => crate::SimplifiedBlockKind::Farmland, + crate::BlockKind::Fern => crate::SimplifiedBlockKind::Fern, + crate::BlockKind::Fire => crate::SimplifiedBlockKind::Fire, + crate::BlockKind::FireCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::FireCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::FireCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::FireCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::FlowerPot => crate::SimplifiedBlockKind::FlowerPot, + crate::BlockKind::FrostedIce => crate::SimplifiedBlockKind::FrostedIce, + crate::BlockKind::Furnace => crate::SimplifiedBlockKind::Furnace, + crate::BlockKind::Glass => crate::SimplifiedBlockKind::Glass, + crate::BlockKind::GlassPane => crate::SimplifiedBlockKind::GlassPane, + crate::BlockKind::Glowstone => crate::SimplifiedBlockKind::Glowstone, + crate::BlockKind::GoldBlock => crate::SimplifiedBlockKind::GoldBlock, + crate::BlockKind::GoldOre => crate::SimplifiedBlockKind::GoldOre, + crate::BlockKind::Granite => crate::SimplifiedBlockKind::Granite, + crate::BlockKind::Grass => crate::SimplifiedBlockKind::Grass, + crate::BlockKind::GrassBlock => crate::SimplifiedBlockKind::GrassBlock, + crate::BlockKind::GrassPath => crate::SimplifiedBlockKind::GrassPath, + crate::BlockKind::Gravel => crate::SimplifiedBlockKind::Gravel, + crate::BlockKind::GrayBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::GrayBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::GrayCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::GrayConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::GrayConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::GrayGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::GrayShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::GrayStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::GrayStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::GrayTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::GrayWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::GrayWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::GreenBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::GreenBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::GreenCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::GreenConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::GreenConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::GreenGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::GreenShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::GreenStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::GreenStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::GreenTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::GreenWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::GreenWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::HayBlock => crate::SimplifiedBlockKind::HayBlock, + crate::BlockKind::HeavyWeightedPressurePlate => { + crate::SimplifiedBlockKind::HeavyWeightedPressurePlate + } + crate::BlockKind::Hopper => crate::SimplifiedBlockKind::Hopper, + crate::BlockKind::HornCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::HornCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::HornCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::HornCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::Ice => crate::SimplifiedBlockKind::Ice, + crate::BlockKind::InfestedChiseledStoneBricks => { + crate::SimplifiedBlockKind::InfestedChiseledStoneBricks + } + crate::BlockKind::InfestedCobblestone => { + crate::SimplifiedBlockKind::InfestedCobblestone + } + crate::BlockKind::InfestedCrackedStoneBricks => { + crate::SimplifiedBlockKind::InfestedCrackedStoneBricks + } + crate::BlockKind::InfestedMossyStoneBricks => { + crate::SimplifiedBlockKind::InfestedMossyStoneBricks + } + crate::BlockKind::InfestedStone => crate::SimplifiedBlockKind::InfestedStone, + crate::BlockKind::InfestedStoneBricks => { + crate::SimplifiedBlockKind::InfestedStoneBricks + } + crate::BlockKind::IronBars => crate::SimplifiedBlockKind::IronBars, + crate::BlockKind::IronBlock => crate::SimplifiedBlockKind::IronBlock, + crate::BlockKind::IronDoor => crate::SimplifiedBlockKind::IronDoor, + crate::BlockKind::IronOre => crate::SimplifiedBlockKind::IronOre, + crate::BlockKind::IronTrapdoor => crate::SimplifiedBlockKind::IronTrapdoor, + crate::BlockKind::JackOLantern => crate::SimplifiedBlockKind::JackOLantern, + crate::BlockKind::Jukebox => crate::SimplifiedBlockKind::Jukebox, + crate::BlockKind::JungleButton => crate::SimplifiedBlockKind::WoodenButton, + crate::BlockKind::JungleDoor => crate::SimplifiedBlockKind::WoodenDoor, + crate::BlockKind::JungleFence => crate::SimplifiedBlockKind::Fence, + crate::BlockKind::JungleFenceGate => crate::SimplifiedBlockKind::FenceGate, + crate::BlockKind::JungleLeaves => crate::SimplifiedBlockKind::Leaves, + crate::BlockKind::JungleLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::JunglePlanks => crate::SimplifiedBlockKind::Planks, + crate::BlockKind::JunglePressurePlate => { + crate::SimplifiedBlockKind::WoodenPressurePlate + } + crate::BlockKind::JungleSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::JungleSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::JungleStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::JungleTrapdoor => crate::SimplifiedBlockKind::WoodenTrapdoor, + crate::BlockKind::JungleWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::Kelp => crate::SimplifiedBlockKind::Kelp, + crate::BlockKind::KelpPlant => crate::SimplifiedBlockKind::KelpPlant, + crate::BlockKind::Ladder => crate::SimplifiedBlockKind::Ladder, + crate::BlockKind::LapisBlock => crate::SimplifiedBlockKind::LapisBlock, + crate::BlockKind::LapisOre => crate::SimplifiedBlockKind::LapisOre, + crate::BlockKind::LargeFern => crate::SimplifiedBlockKind::LargeFern, + crate::BlockKind::Lava => crate::SimplifiedBlockKind::Lava, + crate::BlockKind::Lever => crate::SimplifiedBlockKind::Lever, + crate::BlockKind::LightBlueBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::LightBlueBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::LightBlueCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::LightBlueConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::LightBlueConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::LightBlueGlazedTerracotta => { + crate::SimplifiedBlockKind::GlazedTerracotta + } + crate::BlockKind::LightBlueShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::LightBlueStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::LightBlueStainedGlassPane => { + crate::SimplifiedBlockKind::StainedGlassPane + } + crate::BlockKind::LightBlueTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::LightBlueWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::LightBlueWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::LightGrayBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::LightGrayBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::LightGrayCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::LightGrayConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::LightGrayConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::LightGrayGlazedTerracotta => { + crate::SimplifiedBlockKind::GlazedTerracotta + } + crate::BlockKind::LightGrayShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::LightGrayStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::LightGrayStainedGlassPane => { + crate::SimplifiedBlockKind::StainedGlassPane + } + crate::BlockKind::LightGrayTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::LightGrayWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::LightGrayWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::LightWeightedPressurePlate => { + crate::SimplifiedBlockKind::LightWeightedPressurePlate + } + crate::BlockKind::Lilac => crate::SimplifiedBlockKind::Lilac, + crate::BlockKind::LilyPad => crate::SimplifiedBlockKind::LilyPad, + crate::BlockKind::LimeBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::LimeBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::LimeCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::LimeConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::LimeConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::LimeGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::LimeShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::LimeStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::LimeStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::LimeTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::LimeWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::LimeWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::MagentaBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::MagentaBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::MagentaCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::MagentaConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::MagentaConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::MagentaGlazedTerracotta => { + crate::SimplifiedBlockKind::GlazedTerracotta + } + crate::BlockKind::MagentaShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::MagentaStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::MagentaStainedGlassPane => { + crate::SimplifiedBlockKind::StainedGlassPane + } + crate::BlockKind::MagentaTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::MagentaWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::MagentaWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::MagmaBlock => crate::SimplifiedBlockKind::MagmaBlock, + crate::BlockKind::Melon => crate::SimplifiedBlockKind::Melon, + crate::BlockKind::MelonStem => crate::SimplifiedBlockKind::MelonStem, + crate::BlockKind::MossyCobblestone => crate::SimplifiedBlockKind::MossyCobblestone, + crate::BlockKind::MossyCobblestoneWall => { + crate::SimplifiedBlockKind::MossyCobblestoneWall + } + crate::BlockKind::MossyStoneBricks => crate::SimplifiedBlockKind::MossyStoneBricks, + crate::BlockKind::MovingPiston => crate::SimplifiedBlockKind::MovingPiston, + crate::BlockKind::MushroomStem => crate::SimplifiedBlockKind::MushroomStem, + crate::BlockKind::Mycelium => crate::SimplifiedBlockKind::Mycelium, + crate::BlockKind::NetherBrickFence => crate::SimplifiedBlockKind::Fence, + crate::BlockKind::NetherBrickSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::NetherBrickStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::NetherBricks => crate::SimplifiedBlockKind::NetherBricks, + crate::BlockKind::NetherPortal => crate::SimplifiedBlockKind::NetherPortal, + crate::BlockKind::NetherQuartzOre => crate::SimplifiedBlockKind::NetherQuartzOre, + crate::BlockKind::NetherWart => crate::SimplifiedBlockKind::NetherWart, + crate::BlockKind::NetherWartBlock => crate::SimplifiedBlockKind::NetherWartBlock, + crate::BlockKind::Netherrack => crate::SimplifiedBlockKind::Netherrack, + crate::BlockKind::NoteBlock => crate::SimplifiedBlockKind::NoteBlock, + crate::BlockKind::OakButton => crate::SimplifiedBlockKind::WoodenButton, + crate::BlockKind::OakDoor => crate::SimplifiedBlockKind::WoodenDoor, + crate::BlockKind::OakFence => crate::SimplifiedBlockKind::Fence, + crate::BlockKind::OakFenceGate => crate::SimplifiedBlockKind::FenceGate, + crate::BlockKind::OakLeaves => crate::SimplifiedBlockKind::Leaves, + crate::BlockKind::OakLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::OakPlanks => crate::SimplifiedBlockKind::Planks, + crate::BlockKind::OakPressurePlate => crate::SimplifiedBlockKind::WoodenPressurePlate, + crate::BlockKind::OakSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::OakSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::OakStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::OakTrapdoor => crate::SimplifiedBlockKind::WoodenTrapdoor, + crate::BlockKind::OakWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::Observer => crate::SimplifiedBlockKind::Observer, + crate::BlockKind::Obsidian => crate::SimplifiedBlockKind::Obsidian, + crate::BlockKind::OrangeBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::OrangeBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::OrangeCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::OrangeConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::OrangeConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::OrangeGlazedTerracotta => { + crate::SimplifiedBlockKind::GlazedTerracotta + } + crate::BlockKind::OrangeShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::OrangeStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::OrangeStainedGlassPane => { + crate::SimplifiedBlockKind::StainedGlassPane + } + crate::BlockKind::OrangeTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::OrangeTulip => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::OrangeWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::OrangeWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::OxeyeDaisy => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PackedIce => crate::SimplifiedBlockKind::PackedIce, + crate::BlockKind::Peony => crate::SimplifiedBlockKind::Peony, + crate::BlockKind::PetrifiedOakSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::PinkBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::PinkBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::PinkCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::PinkConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::PinkConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::PinkGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::PinkShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::PinkStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::PinkStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::PinkTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::PinkTulip => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PinkWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::PinkWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::Piston => crate::SimplifiedBlockKind::Piston, + crate::BlockKind::PistonHead => crate::SimplifiedBlockKind::PistonHead, + crate::BlockKind::PlayerHead => crate::SimplifiedBlockKind::PlayerHead, + crate::BlockKind::PlayerWallHead => crate::SimplifiedBlockKind::PlayerWallHead, + crate::BlockKind::Podzol => crate::SimplifiedBlockKind::Podzol, + crate::BlockKind::PolishedAndesite => crate::SimplifiedBlockKind::PolishedAndesite, + crate::BlockKind::PolishedDiorite => crate::SimplifiedBlockKind::PolishedDiorite, + crate::BlockKind::PolishedGranite => crate::SimplifiedBlockKind::PolishedGranite, + crate::BlockKind::Poppy => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::Potatoes => crate::SimplifiedBlockKind::Potatoes, + crate::BlockKind::PottedAcaciaSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::PottedAllium => crate::SimplifiedBlockKind::PottedPlant, + crate::BlockKind::PottedAzureBluet => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PottedBirchSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::PottedBlueOrchid => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PottedBrownMushroom => crate::SimplifiedBlockKind::PottedPlant, + crate::BlockKind::PottedCactus => crate::SimplifiedBlockKind::PottedPlant, + crate::BlockKind::PottedDandelion => crate::SimplifiedBlockKind::PottedPlant, + crate::BlockKind::PottedDarkOakSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::PottedDeadBush => crate::SimplifiedBlockKind::PottedPlant, + crate::BlockKind::PottedFern => crate::SimplifiedBlockKind::PottedPlant, + crate::BlockKind::PottedJungleSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::PottedOakSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::PottedOrangeTulip => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PottedOxeyeDaisy => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PottedPinkTulip => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PottedPoppy => crate::SimplifiedBlockKind::PottedPlant, + crate::BlockKind::PottedRedMushroom => crate::SimplifiedBlockKind::PottedPlant, + crate::BlockKind::PottedRedTulip => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PottedSpruceSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::PottedWhiteTulip => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::PoweredRail => crate::SimplifiedBlockKind::PoweredRail, + crate::BlockKind::Prismarine => crate::SimplifiedBlockKind::Prismarine, + crate::BlockKind::PrismarineBrickSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::PrismarineBrickStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::PrismarineBricks => crate::SimplifiedBlockKind::PrismarineBricks, + crate::BlockKind::PrismarineSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::PrismarineStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::Pumpkin => crate::SimplifiedBlockKind::Pumpkin, + crate::BlockKind::PumpkinStem => crate::SimplifiedBlockKind::PumpkinStem, + crate::BlockKind::PurpleBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::PurpleBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::PurpleCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::PurpleConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::PurpleConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::PurpleGlazedTerracotta => { + crate::SimplifiedBlockKind::GlazedTerracotta + } + crate::BlockKind::PurpleShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::PurpleStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::PurpleStainedGlassPane => { + crate::SimplifiedBlockKind::StainedGlassPane + } + crate::BlockKind::PurpleTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::PurpleWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::PurpleWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::PurpurBlock => crate::SimplifiedBlockKind::PurpurBlock, + crate::BlockKind::PurpurPillar => crate::SimplifiedBlockKind::PurpurPillar, + crate::BlockKind::PurpurSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::PurpurStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::QuartzBlock => crate::SimplifiedBlockKind::QuartzBlock, + crate::BlockKind::QuartzPillar => crate::SimplifiedBlockKind::QuartzPillar, + crate::BlockKind::QuartzSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::QuartzStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::Rail => crate::SimplifiedBlockKind::Rail, + crate::BlockKind::RedBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::RedBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::RedCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::RedConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::RedConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::RedGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::RedMushroom => crate::SimplifiedBlockKind::Mushroom, + crate::BlockKind::RedMushroomBlock => crate::SimplifiedBlockKind::RedMushroomBlock, + crate::BlockKind::RedNetherBricks => crate::SimplifiedBlockKind::RedNetherBricks, + crate::BlockKind::RedSand => crate::SimplifiedBlockKind::RedSand, + crate::BlockKind::RedSandstone => crate::SimplifiedBlockKind::RedSandstone, + crate::BlockKind::RedSandstoneSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::RedSandstoneStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::RedShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::RedStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::RedStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::RedTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::RedTulip => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::RedWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::RedWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::RedstoneBlock => crate::SimplifiedBlockKind::RedstoneBlock, + crate::BlockKind::RedstoneLamp => crate::SimplifiedBlockKind::RedstoneLamp, + crate::BlockKind::RedstoneOre => crate::SimplifiedBlockKind::RedstoneOre, + crate::BlockKind::RedstoneTorch => crate::SimplifiedBlockKind::RedstoneTorch, + crate::BlockKind::RedstoneWallTorch => crate::SimplifiedBlockKind::RedstoneWallTorch, + crate::BlockKind::RedstoneWire => crate::SimplifiedBlockKind::RedstoneWire, + crate::BlockKind::Repeater => crate::SimplifiedBlockKind::Repeater, + crate::BlockKind::RepeatingCommandBlock => { + crate::SimplifiedBlockKind::RepeatingCommandBlock + } + crate::BlockKind::RoseBush => crate::SimplifiedBlockKind::RoseBush, + crate::BlockKind::Sand => crate::SimplifiedBlockKind::Sand, + crate::BlockKind::Sandstone => crate::SimplifiedBlockKind::Sandstone, + crate::BlockKind::SandstoneSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::SandstoneStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::SeaLantern => crate::SimplifiedBlockKind::SeaLantern, + crate::BlockKind::SeaPickle => crate::SimplifiedBlockKind::SeaPickle, + crate::BlockKind::Seagrass => crate::SimplifiedBlockKind::Seagrass, + crate::BlockKind::ShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::Sign => crate::SimplifiedBlockKind::Sign, + crate::BlockKind::SkeletonSkull => crate::SimplifiedBlockKind::SkeletonSkull, + crate::BlockKind::SkeletonWallSkull => crate::SimplifiedBlockKind::SkeletonWallSkull, + crate::BlockKind::SlimeBlock => crate::SimplifiedBlockKind::SlimeBlock, + crate::BlockKind::SmoothQuartz => crate::SimplifiedBlockKind::SmoothQuartz, + crate::BlockKind::SmoothRedSandstone => crate::SimplifiedBlockKind::SmoothRedSandstone, + crate::BlockKind::SmoothSandstone => crate::SimplifiedBlockKind::SmoothSandstone, + crate::BlockKind::SmoothStone => crate::SimplifiedBlockKind::SmoothStone, + crate::BlockKind::Snow => crate::SimplifiedBlockKind::Snow, + crate::BlockKind::SnowBlock => crate::SimplifiedBlockKind::SnowBlock, + crate::BlockKind::SoulSand => crate::SimplifiedBlockKind::SoulSand, + crate::BlockKind::Spawner => crate::SimplifiedBlockKind::Spawner, + crate::BlockKind::Sponge => crate::SimplifiedBlockKind::Sponge, + crate::BlockKind::SpruceButton => crate::SimplifiedBlockKind::WoodenButton, + crate::BlockKind::SpruceDoor => crate::SimplifiedBlockKind::WoodenDoor, + crate::BlockKind::SpruceFence => crate::SimplifiedBlockKind::Fence, + crate::BlockKind::SpruceFenceGate => crate::SimplifiedBlockKind::FenceGate, + crate::BlockKind::SpruceLeaves => crate::SimplifiedBlockKind::Leaves, + crate::BlockKind::SpruceLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::SprucePlanks => crate::SimplifiedBlockKind::Planks, + crate::BlockKind::SprucePressurePlate => { + crate::SimplifiedBlockKind::WoodenPressurePlate + } + crate::BlockKind::SpruceSapling => crate::SimplifiedBlockKind::Sapling, + crate::BlockKind::SpruceSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::SpruceStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::SpruceTrapdoor => crate::SimplifiedBlockKind::WoodenTrapdoor, + crate::BlockKind::SpruceWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StickyPiston => crate::SimplifiedBlockKind::StickyPiston, + crate::BlockKind::Stone => crate::SimplifiedBlockKind::Stone, + crate::BlockKind::StoneBrickSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::StoneBrickStairs => crate::SimplifiedBlockKind::Stairs, + crate::BlockKind::StoneBricks => crate::SimplifiedBlockKind::StoneBricks, + crate::BlockKind::StoneButton => crate::SimplifiedBlockKind::StoneButton, + crate::BlockKind::StonePressurePlate => crate::SimplifiedBlockKind::StonePressurePlate, + crate::BlockKind::StoneSlab => crate::SimplifiedBlockKind::Slab, + crate::BlockKind::StrippedAcaciaLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedAcaciaWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedBirchLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedBirchWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedDarkOakLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedDarkOakWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedJungleLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedJungleWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedOakLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedOakWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedSpruceLog => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StrippedSpruceWood => crate::SimplifiedBlockKind::Log, + crate::BlockKind::StructureBlock => crate::SimplifiedBlockKind::StructureBlock, + crate::BlockKind::StructureVoid => crate::SimplifiedBlockKind::StructureVoid, + crate::BlockKind::SugarCane => crate::SimplifiedBlockKind::SugarCane, + crate::BlockKind::Sunflower => crate::SimplifiedBlockKind::Sunflower, + crate::BlockKind::TallGrass => crate::SimplifiedBlockKind::TallGrass, + crate::BlockKind::TallSeagrass => crate::SimplifiedBlockKind::TallSeagrass, + crate::BlockKind::Terracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::Tnt => crate::SimplifiedBlockKind::Tnt, + crate::BlockKind::Torch => crate::SimplifiedBlockKind::Torch, + crate::BlockKind::TrappedChest => crate::SimplifiedBlockKind::TrappedChest, + crate::BlockKind::Tripwire => crate::SimplifiedBlockKind::Tripwire, + crate::BlockKind::TripwireHook => crate::SimplifiedBlockKind::TripwireHook, + crate::BlockKind::TubeCoral => crate::SimplifiedBlockKind::Coral, + crate::BlockKind::TubeCoralBlock => crate::SimplifiedBlockKind::CoralBlock, + crate::BlockKind::TubeCoralFan => crate::SimplifiedBlockKind::CoralFan, + crate::BlockKind::TubeCoralWallFan => crate::SimplifiedBlockKind::CoralWallFan, + crate::BlockKind::TurtleEgg => crate::SimplifiedBlockKind::TurtleEgg, + crate::BlockKind::Vine => crate::SimplifiedBlockKind::Vine, + crate::BlockKind::VoidAir => crate::SimplifiedBlockKind::Air, + crate::BlockKind::WallSign => crate::SimplifiedBlockKind::WallSign, + crate::BlockKind::WallTorch => crate::SimplifiedBlockKind::WallTorch, + crate::BlockKind::Water => crate::SimplifiedBlockKind::Water, + crate::BlockKind::WetSponge => crate::SimplifiedBlockKind::WetSponge, + crate::BlockKind::Wheat => crate::SimplifiedBlockKind::Wheat, + crate::BlockKind::WhiteBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::WhiteBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::WhiteCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::WhiteConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::WhiteConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::WhiteGlazedTerracotta => crate::SimplifiedBlockKind::GlazedTerracotta, + crate::BlockKind::WhiteShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::WhiteStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::WhiteStainedGlassPane => crate::SimplifiedBlockKind::StainedGlassPane, + crate::BlockKind::WhiteTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::WhiteTulip => crate::SimplifiedBlockKind::Flower, + crate::BlockKind::WhiteWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::WhiteWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::WitherSkeletonSkull => { + crate::SimplifiedBlockKind::WitherSkeletonSkull + } + crate::BlockKind::WitherSkeletonWallSkull => { + crate::SimplifiedBlockKind::WitherSkeletonWallSkull + } + crate::BlockKind::YellowBanner => crate::SimplifiedBlockKind::Banner, + crate::BlockKind::YellowBed => crate::SimplifiedBlockKind::Bed, + crate::BlockKind::YellowCarpet => crate::SimplifiedBlockKind::Carpet, + crate::BlockKind::YellowConcrete => crate::SimplifiedBlockKind::Concrete, + crate::BlockKind::YellowConcretePowder => crate::SimplifiedBlockKind::ConcretePowder, + crate::BlockKind::YellowGlazedTerracotta => { + crate::SimplifiedBlockKind::GlazedTerracotta + } + crate::BlockKind::YellowShulkerBox => crate::SimplifiedBlockKind::ShulkerBox, + crate::BlockKind::YellowStainedGlass => crate::SimplifiedBlockKind::StainedGlass, + crate::BlockKind::YellowStainedGlassPane => { + crate::SimplifiedBlockKind::StainedGlassPane + } + crate::BlockKind::YellowTerracotta => crate::SimplifiedBlockKind::Terracotta, + crate::BlockKind::YellowWallBanner => crate::SimplifiedBlockKind::WallBanner, + crate::BlockKind::YellowWool => crate::SimplifiedBlockKind::Wool, + crate::BlockKind::ZombieHead => crate::SimplifiedBlockKind::ZombieHead, + crate::BlockKind::ZombieWallHead => crate::SimplifiedBlockKind::ZombieWallHead, + } + } +} diff --git a/feather/old/definitions/src/generated/item.rs b/feather/old/definitions/src/generated/item.rs new file mode 100644 index 000000000..92ac41900 --- /dev/null +++ b/feather/old/definitions/src/generated/item.rs @@ -0,0 +1,5584 @@ +// This file is @generated +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ToPrimitive, FromPrimitive)] +pub enum Item { + Air, + Stone, + Granite, + PolishedGranite, + Diorite, + PolishedDiorite, + Andesite, + PolishedAndesite, + GrassBlock, + Dirt, + CoarseDirt, + Podzol, + Cobblestone, + OakPlanks, + SprucePlanks, + BirchPlanks, + JunglePlanks, + AcaciaPlanks, + DarkOakPlanks, + OakSapling, + SpruceSapling, + BirchSapling, + JungleSapling, + AcaciaSapling, + DarkOakSapling, + Bedrock, + Sand, + RedSand, + Gravel, + GoldOre, + IronOre, + CoalOre, + OakLog, + SpruceLog, + BirchLog, + JungleLog, + AcaciaLog, + DarkOakLog, + StrippedOakLog, + StrippedSpruceLog, + StrippedBirchLog, + StrippedJungleLog, + StrippedAcaciaLog, + StrippedDarkOakLog, + StrippedOakWood, + StrippedSpruceWood, + StrippedBirchWood, + StrippedJungleWood, + StrippedAcaciaWood, + StrippedDarkOakWood, + OakWood, + SpruceWood, + BirchWood, + JungleWood, + AcaciaWood, + DarkOakWood, + OakLeaves, + SpruceLeaves, + BirchLeaves, + JungleLeaves, + AcaciaLeaves, + DarkOakLeaves, + Sponge, + WetSponge, + Glass, + LapisOre, + LapisBlock, + Dispenser, + Sandstone, + ChiseledSandstone, + CutSandstone, + NoteBlock, + PoweredRail, + DetectorRail, + StickyPiston, + Cobweb, + Grass, + Fern, + DeadBush, + Seagrass, + SeaPickle, + Piston, + WhiteWool, + OrangeWool, + MagentaWool, + LightBlueWool, + YellowWool, + LimeWool, + PinkWool, + GrayWool, + LightGrayWool, + CyanWool, + PurpleWool, + BlueWool, + BrownWool, + GreenWool, + RedWool, + BlackWool, + Dandelion, + Poppy, + BlueOrchid, + Allium, + AzureBluet, + RedTulip, + OrangeTulip, + WhiteTulip, + PinkTulip, + OxeyeDaisy, + BrownMushroom, + RedMushroom, + GoldBlock, + IronBlock, + OakSlab, + SpruceSlab, + BirchSlab, + JungleSlab, + AcaciaSlab, + DarkOakSlab, + StoneSlab, + SandstoneSlab, + PetrifiedOakSlab, + CobblestoneSlab, + BrickSlab, + StoneBrickSlab, + NetherBrickSlab, + QuartzSlab, + RedSandstoneSlab, + PurpurSlab, + PrismarineSlab, + PrismarineBrickSlab, + DarkPrismarineSlab, + SmoothQuartz, + SmoothRedSandstone, + SmoothSandstone, + SmoothStone, + Bricks, + Tnt, + Bookshelf, + MossyCobblestone, + Obsidian, + Torch, + EndRod, + ChorusPlant, + ChorusFlower, + PurpurBlock, + PurpurPillar, + PurpurStairs, + Spawner, + OakStairs, + Chest, + DiamondOre, + DiamondBlock, + CraftingTable, + Farmland, + Furnace, + Ladder, + Rail, + CobblestoneStairs, + Lever, + StonePressurePlate, + OakPressurePlate, + SprucePressurePlate, + BirchPressurePlate, + JunglePressurePlate, + AcaciaPressurePlate, + DarkOakPressurePlate, + RedstoneOre, + RedstoneTorch, + StoneButton, + Snow, + Ice, + SnowBlock, + Cactus, + Clay, + Jukebox, + OakFence, + SpruceFence, + BirchFence, + JungleFence, + AcaciaFence, + DarkOakFence, + Pumpkin, + CarvedPumpkin, + Netherrack, + SoulSand, + Glowstone, + JackOLantern, + OakTrapdoor, + SpruceTrapdoor, + BirchTrapdoor, + JungleTrapdoor, + AcaciaTrapdoor, + DarkOakTrapdoor, + InfestedStone, + InfestedCobblestone, + InfestedStoneBricks, + InfestedMossyStoneBricks, + InfestedCrackedStoneBricks, + InfestedChiseledStoneBricks, + StoneBricks, + MossyStoneBricks, + CrackedStoneBricks, + ChiseledStoneBricks, + BrownMushroomBlock, + RedMushroomBlock, + MushroomStem, + IronBars, + GlassPane, + Melon, + Vine, + OakFenceGate, + SpruceFenceGate, + BirchFenceGate, + JungleFenceGate, + AcaciaFenceGate, + DarkOakFenceGate, + BrickStairs, + StoneBrickStairs, + Mycelium, + LilyPad, + NetherBricks, + NetherBrickFence, + NetherBrickStairs, + EnchantingTable, + EndPortalFrame, + EndStone, + EndStoneBricks, + DragonEgg, + RedstoneLamp, + SandstoneStairs, + EmeraldOre, + EnderChest, + TripwireHook, + EmeraldBlock, + SpruceStairs, + BirchStairs, + JungleStairs, + CommandBlock, + Beacon, + CobblestoneWall, + MossyCobblestoneWall, + OakButton, + SpruceButton, + BirchButton, + JungleButton, + AcaciaButton, + DarkOakButton, + Anvil, + ChippedAnvil, + DamagedAnvil, + TrappedChest, + LightWeightedPressurePlate, + HeavyWeightedPressurePlate, + DaylightDetector, + RedstoneBlock, + NetherQuartzOre, + Hopper, + ChiseledQuartzBlock, + QuartzBlock, + QuartzPillar, + QuartzStairs, + ActivatorRail, + Dropper, + WhiteTerracotta, + OrangeTerracotta, + MagentaTerracotta, + LightBlueTerracotta, + YellowTerracotta, + LimeTerracotta, + PinkTerracotta, + GrayTerracotta, + LightGrayTerracotta, + CyanTerracotta, + PurpleTerracotta, + BlueTerracotta, + BrownTerracotta, + GreenTerracotta, + RedTerracotta, + BlackTerracotta, + Barrier, + IronTrapdoor, + HayBlock, + WhiteCarpet, + OrangeCarpet, + MagentaCarpet, + LightBlueCarpet, + YellowCarpet, + LimeCarpet, + PinkCarpet, + GrayCarpet, + LightGrayCarpet, + CyanCarpet, + PurpleCarpet, + BlueCarpet, + BrownCarpet, + GreenCarpet, + RedCarpet, + BlackCarpet, + Terracotta, + CoalBlock, + PackedIce, + AcaciaStairs, + DarkOakStairs, + SlimeBlock, + GrassPath, + Sunflower, + Lilac, + RoseBush, + Peony, + TallGrass, + LargeFern, + WhiteStainedGlass, + OrangeStainedGlass, + MagentaStainedGlass, + LightBlueStainedGlass, + YellowStainedGlass, + LimeStainedGlass, + PinkStainedGlass, + GrayStainedGlass, + LightGrayStainedGlass, + CyanStainedGlass, + PurpleStainedGlass, + BlueStainedGlass, + BrownStainedGlass, + GreenStainedGlass, + RedStainedGlass, + BlackStainedGlass, + WhiteStainedGlassPane, + OrangeStainedGlassPane, + MagentaStainedGlassPane, + LightBlueStainedGlassPane, + YellowStainedGlassPane, + LimeStainedGlassPane, + PinkStainedGlassPane, + GrayStainedGlassPane, + LightGrayStainedGlassPane, + CyanStainedGlassPane, + PurpleStainedGlassPane, + BlueStainedGlassPane, + BrownStainedGlassPane, + GreenStainedGlassPane, + RedStainedGlassPane, + BlackStainedGlassPane, + Prismarine, + PrismarineBricks, + DarkPrismarine, + PrismarineStairs, + PrismarineBrickStairs, + DarkPrismarineStairs, + SeaLantern, + RedSandstone, + ChiseledRedSandstone, + CutRedSandstone, + RedSandstoneStairs, + RepeatingCommandBlock, + ChainCommandBlock, + MagmaBlock, + NetherWartBlock, + RedNetherBricks, + BoneBlock, + StructureVoid, + Observer, + ShulkerBox, + WhiteShulkerBox, + OrangeShulkerBox, + MagentaShulkerBox, + LightBlueShulkerBox, + YellowShulkerBox, + LimeShulkerBox, + PinkShulkerBox, + GrayShulkerBox, + LightGrayShulkerBox, + CyanShulkerBox, + PurpleShulkerBox, + BlueShulkerBox, + BrownShulkerBox, + GreenShulkerBox, + RedShulkerBox, + BlackShulkerBox, + WhiteGlazedTerracotta, + OrangeGlazedTerracotta, + MagentaGlazedTerracotta, + LightBlueGlazedTerracotta, + YellowGlazedTerracotta, + LimeGlazedTerracotta, + PinkGlazedTerracotta, + GrayGlazedTerracotta, + LightGrayGlazedTerracotta, + CyanGlazedTerracotta, + PurpleGlazedTerracotta, + BlueGlazedTerracotta, + BrownGlazedTerracotta, + GreenGlazedTerracotta, + RedGlazedTerracotta, + BlackGlazedTerracotta, + WhiteConcrete, + OrangeConcrete, + MagentaConcrete, + LightBlueConcrete, + YellowConcrete, + LimeConcrete, + PinkConcrete, + GrayConcrete, + LightGrayConcrete, + CyanConcrete, + PurpleConcrete, + BlueConcrete, + BrownConcrete, + GreenConcrete, + RedConcrete, + BlackConcrete, + WhiteConcretePowder, + OrangeConcretePowder, + MagentaConcretePowder, + LightBlueConcretePowder, + YellowConcretePowder, + LimeConcretePowder, + PinkConcretePowder, + GrayConcretePowder, + LightGrayConcretePowder, + CyanConcretePowder, + PurpleConcretePowder, + BlueConcretePowder, + BrownConcretePowder, + GreenConcretePowder, + RedConcretePowder, + BlackConcretePowder, + TurtleEgg, + DeadTubeCoralBlock, + DeadBrainCoralBlock, + DeadBubbleCoralBlock, + DeadFireCoralBlock, + DeadHornCoralBlock, + TubeCoralBlock, + BrainCoralBlock, + BubbleCoralBlock, + FireCoralBlock, + HornCoralBlock, + TubeCoral, + BrainCoral, + BubbleCoral, + FireCoral, + HornCoral, + DeadBrainCoral, + DeadBubbleCoral, + DeadFireCoral, + DeadHornCoral, + DeadTubeCoral, + TubeCoralFan, + BrainCoralFan, + BubbleCoralFan, + FireCoralFan, + HornCoralFan, + DeadTubeCoralFan, + DeadBrainCoralFan, + DeadBubbleCoralFan, + DeadFireCoralFan, + DeadHornCoralFan, + BlueIce, + Conduit, + IronDoor, + OakDoor, + SpruceDoor, + BirchDoor, + JungleDoor, + AcaciaDoor, + DarkOakDoor, + Repeater, + Comparator, + StructureBlock, + TurtleHelmet, + Scute, + IronShovel, + IronPickaxe, + IronAxe, + FlintAndSteel, + Apple, + Bow, + Arrow, + Coal, + Charcoal, + Diamond, + IronIngot, + GoldIngot, + IronSword, + WoodenSword, + WoodenShovel, + WoodenPickaxe, + WoodenAxe, + StoneSword, + StoneShovel, + StonePickaxe, + StoneAxe, + DiamondSword, + DiamondShovel, + DiamondPickaxe, + DiamondAxe, + Stick, + Bowl, + MushroomStew, + GoldenSword, + GoldenShovel, + GoldenPickaxe, + GoldenAxe, + String, + Feather, + Gunpowder, + WoodenHoe, + StoneHoe, + IronHoe, + DiamondHoe, + GoldenHoe, + WheatSeeds, + Wheat, + Bread, + LeatherHelmet, + LeatherChestplate, + LeatherLeggings, + LeatherBoots, + ChainmailHelmet, + ChainmailChestplate, + ChainmailLeggings, + ChainmailBoots, + IronHelmet, + IronChestplate, + IronLeggings, + IronBoots, + DiamondHelmet, + DiamondChestplate, + DiamondLeggings, + DiamondBoots, + GoldenHelmet, + GoldenChestplate, + GoldenLeggings, + GoldenBoots, + Flint, + Porkchop, + CookedPorkchop, + Painting, + GoldenApple, + EnchantedGoldenApple, + Sign, + Bucket, + WaterBucket, + LavaBucket, + Minecart, + Saddle, + Redstone, + Snowball, + OakBoat, + Leather, + MilkBucket, + PufferfishBucket, + SalmonBucket, + CodBucket, + TropicalFishBucket, + Brick, + ClayBall, + SugarCane, + Kelp, + DriedKelpBlock, + Paper, + Book, + SlimeBall, + ChestMinecart, + FurnaceMinecart, + Egg, + Compass, + FishingRod, + Clock, + GlowstoneDust, + Cod, + Salmon, + TropicalFish, + Pufferfish, + CookedCod, + CookedSalmon, + InkSac, + RoseRed, + CactusGreen, + CocoaBeans, + LapisLazuli, + PurpleDye, + CyanDye, + LightGrayDye, + GrayDye, + PinkDye, + LimeDye, + DandelionYellow, + LightBlueDye, + MagentaDye, + OrangeDye, + BoneMeal, + Bone, + Sugar, + Cake, + WhiteBed, + OrangeBed, + MagentaBed, + LightBlueBed, + YellowBed, + LimeBed, + PinkBed, + GrayBed, + LightGrayBed, + CyanBed, + PurpleBed, + BlueBed, + BrownBed, + GreenBed, + RedBed, + BlackBed, + Cookie, + FilledMap, + Shears, + MelonSlice, + DriedKelp, + PumpkinSeeds, + MelonSeeds, + Beef, + CookedBeef, + Chicken, + CookedChicken, + RottenFlesh, + EnderPearl, + BlazeRod, + GhastTear, + GoldNugget, + NetherWart, + Potion, + GlassBottle, + SpiderEye, + FermentedSpiderEye, + BlazePowder, + MagmaCream, + BrewingStand, + Cauldron, + EnderEye, + GlisteringMelonSlice, + BatSpawnEgg, + BlazeSpawnEgg, + CaveSpiderSpawnEgg, + ChickenSpawnEgg, + CodSpawnEgg, + CowSpawnEgg, + CreeperSpawnEgg, + DolphinSpawnEgg, + DonkeySpawnEgg, + DrownedSpawnEgg, + ElderGuardianSpawnEgg, + EndermanSpawnEgg, + EndermiteSpawnEgg, + EvokerSpawnEgg, + GhastSpawnEgg, + GuardianSpawnEgg, + HorseSpawnEgg, + HuskSpawnEgg, + LlamaSpawnEgg, + MagmaCubeSpawnEgg, + MooshroomSpawnEgg, + MuleSpawnEgg, + OcelotSpawnEgg, + ParrotSpawnEgg, + PhantomSpawnEgg, + PigSpawnEgg, + PolarBearSpawnEgg, + PufferfishSpawnEgg, + RabbitSpawnEgg, + SalmonSpawnEgg, + SheepSpawnEgg, + ShulkerSpawnEgg, + SilverfishSpawnEgg, + SkeletonSpawnEgg, + SkeletonHorseSpawnEgg, + SlimeSpawnEgg, + SpiderSpawnEgg, + SquidSpawnEgg, + StraySpawnEgg, + TropicalFishSpawnEgg, + TurtleSpawnEgg, + VexSpawnEgg, + VillagerSpawnEgg, + VindicatorSpawnEgg, + WitchSpawnEgg, + WitherSkeletonSpawnEgg, + WolfSpawnEgg, + ZombieSpawnEgg, + ZombieHorseSpawnEgg, + ZombiePigmanSpawnEgg, + ZombieVillagerSpawnEgg, + ExperienceBottle, + FireCharge, + WritableBook, + WrittenBook, + Emerald, + ItemFrame, + FlowerPot, + Carrot, + Potato, + BakedPotato, + PoisonousPotato, + Map, + GoldenCarrot, + SkeletonSkull, + WitherSkeletonSkull, + PlayerHead, + ZombieHead, + CreeperHead, + DragonHead, + CarrotOnAStick, + NetherStar, + PumpkinPie, + FireworkRocket, + FireworkStar, + EnchantedBook, + NetherBrick, + Quartz, + TntMinecart, + HopperMinecart, + PrismarineShard, + PrismarineCrystals, + Rabbit, + CookedRabbit, + RabbitStew, + RabbitFoot, + RabbitHide, + ArmorStand, + IronHorseArmor, + GoldenHorseArmor, + DiamondHorseArmor, + Lead, + NameTag, + CommandBlockMinecart, + Mutton, + CookedMutton, + WhiteBanner, + OrangeBanner, + MagentaBanner, + LightBlueBanner, + YellowBanner, + LimeBanner, + PinkBanner, + GrayBanner, + LightGrayBanner, + CyanBanner, + PurpleBanner, + BlueBanner, + BrownBanner, + GreenBanner, + RedBanner, + BlackBanner, + EndCrystal, + ChorusFruit, + PoppedChorusFruit, + Beetroot, + BeetrootSeeds, + BeetrootSoup, + DragonBreath, + SplashPotion, + SpectralArrow, + TippedArrow, + LingeringPotion, + Shield, + Elytra, + SpruceBoat, + BirchBoat, + JungleBoat, + AcaciaBoat, + DarkOakBoat, + TotemOfUndying, + ShulkerShell, + IronNugget, + KnowledgeBook, + DebugStick, + MusicDisc13, + MusicDiscCat, + MusicDiscBlocks, + MusicDiscChirp, + MusicDiscFar, + MusicDiscMall, + MusicDiscMellohi, + MusicDiscStal, + MusicDiscStrad, + MusicDiscWard, + MusicDisc11, + MusicDiscWait, + Trident, + PhantomMembrane, + NautilusShell, + HeartOfTheSea, +} +impl crate::Item { + pub fn display_name(self) -> &'static str { + match self { + crate::Item::AcaciaBoat => "Acacia Boat", + crate::Item::AcaciaButton => "Acacia Button", + crate::Item::AcaciaDoor => "Acacia Door", + crate::Item::AcaciaFence => "Acacia Fence", + crate::Item::AcaciaFenceGate => "Acacia Fence Gate", + crate::Item::AcaciaLeaves => "Acacia Leaves", + crate::Item::AcaciaLog => "Acacia Log", + crate::Item::AcaciaPlanks => "Acacia Planks", + crate::Item::AcaciaPressurePlate => "Acacia Pressure Plate", + crate::Item::AcaciaSapling => "Acacia Sapling", + crate::Item::AcaciaSlab => "Acacia Slab", + crate::Item::AcaciaStairs => "Acacia Stairs", + crate::Item::AcaciaTrapdoor => "Acacia Trapdoor", + crate::Item::AcaciaWood => "Acacia Wood", + crate::Item::ActivatorRail => "Activator Rail", + crate::Item::Air => "Air", + crate::Item::Allium => "Allium", + crate::Item::Andesite => "Andesite", + crate::Item::Anvil => "Anvil", + crate::Item::Apple => "Apple", + crate::Item::ArmorStand => "Armor Stand", + crate::Item::Arrow => "Arrow", + crate::Item::AzureBluet => "Azure Bluet", + crate::Item::BakedPotato => "Baked Potato", + crate::Item::Barrier => "Barrier", + crate::Item::BatSpawnEgg => "Bat Spawn Egg", + crate::Item::Beacon => "Beacon", + crate::Item::Bedrock => "Bedrock", + crate::Item::Beef => "Raw Beef", + crate::Item::Beetroot => "Beetroot", + crate::Item::BeetrootSeeds => "Beetroot Seeds", + crate::Item::BeetrootSoup => "Beetroot Soup", + crate::Item::BirchBoat => "Birch Boat", + crate::Item::BirchButton => "Birch Button", + crate::Item::BirchDoor => "Birch Door", + crate::Item::BirchFence => "Birch Fence", + crate::Item::BirchFenceGate => "Birch Fence Gate", + crate::Item::BirchLeaves => "Birch Leaves", + crate::Item::BirchLog => "Birch Log", + crate::Item::BirchPlanks => "Birch Planks", + crate::Item::BirchPressurePlate => "Birch Pressure Plate", + crate::Item::BirchSapling => "Birch Sapling", + crate::Item::BirchSlab => "Birch Slab", + crate::Item::BirchStairs => "Birch Stairs", + crate::Item::BirchTrapdoor => "Birch Trapdoor", + crate::Item::BirchWood => "Birch Wood", + crate::Item::BlackBanner => "Black Banner", + crate::Item::BlackBed => "Black Bed", + crate::Item::BlackCarpet => "Black Carpet", + crate::Item::BlackConcrete => "Black Concrete", + crate::Item::BlackConcretePowder => "Black Concrete Powder", + crate::Item::BlackGlazedTerracotta => "Black Glazed Terracotta", + crate::Item::BlackShulkerBox => "Black Shulker Box", + crate::Item::BlackStainedGlass => "Black Stained Glass", + crate::Item::BlackStainedGlassPane => "Black Stained Glass Pane", + crate::Item::BlackTerracotta => "Black Terracotta", + crate::Item::BlackWool => "Black Wool", + crate::Item::BlazePowder => "Blaze Powder", + crate::Item::BlazeRod => "Blaze Rod", + crate::Item::BlazeSpawnEgg => "Blaze Spawn Egg", + crate::Item::BlueBanner => "Blue Banner", + crate::Item::BlueBed => "Blue Bed", + crate::Item::BlueCarpet => "Blue Carpet", + crate::Item::BlueConcrete => "Blue Concrete", + crate::Item::BlueConcretePowder => "Blue Concrete Powder", + crate::Item::BlueGlazedTerracotta => "Blue Glazed Terracotta", + crate::Item::BlueIce => "Blue Ice", + crate::Item::BlueOrchid => "Blue Orchid", + crate::Item::BlueShulkerBox => "Blue Shulker Box", + crate::Item::BlueStainedGlass => "Blue Stained Glass", + crate::Item::BlueStainedGlassPane => "Blue Stained Glass Pane", + crate::Item::BlueTerracotta => "Blue Terracotta", + crate::Item::BlueWool => "Blue Wool", + crate::Item::Bone => "Bone", + crate::Item::BoneBlock => "Bone Block", + crate::Item::BoneMeal => "Bone Meal", + crate::Item::Book => "Book", + crate::Item::Bookshelf => "Bookshelf", + crate::Item::Bow => "Bow", + crate::Item::Bowl => "Bowl", + crate::Item::BrainCoral => "Brain Coral", + crate::Item::BrainCoralBlock => "Brain Coral Block", + crate::Item::BrainCoralFan => "Brain Coral Fan", + crate::Item::Bread => "Bread", + crate::Item::BrewingStand => "Brewing Stand", + crate::Item::Brick => "Brick", + crate::Item::BrickSlab => "Brick Slab", + crate::Item::BrickStairs => "Brick Stairs", + crate::Item::Bricks => "Bricks", + crate::Item::BrownBanner => "Brown Banner", + crate::Item::BrownBed => "Brown Bed", + crate::Item::BrownCarpet => "Brown Carpet", + crate::Item::BrownConcrete => "Brown Concrete", + crate::Item::BrownConcretePowder => "Brown Concrete Powder", + crate::Item::BrownGlazedTerracotta => "Brown Glazed Terracotta", + crate::Item::BrownMushroom => "Brown Mushroom", + crate::Item::BrownMushroomBlock => "Brown Mushroom Block", + crate::Item::BrownShulkerBox => "Brown Shulker Box", + crate::Item::BrownStainedGlass => "Brown Stained Glass", + crate::Item::BrownStainedGlassPane => "Brown Stained Glass Pane", + crate::Item::BrownTerracotta => "Brown Terracotta", + crate::Item::BrownWool => "Brown Wool", + crate::Item::BubbleCoral => "Bubble Coral", + crate::Item::BubbleCoralBlock => "Bubble Coral Block", + crate::Item::BubbleCoralFan => "Bubble Coral Fan", + crate::Item::Bucket => "Bucket", + crate::Item::Cactus => "Cactus", + crate::Item::CactusGreen => "Cactus Green", + crate::Item::Cake => "Cake", + crate::Item::Carrot => "Carrot", + crate::Item::CarrotOnAStick => "Carrot on a Stick", + crate::Item::CarvedPumpkin => "Carved Pumpkin", + crate::Item::Cauldron => "Cauldron", + crate::Item::CaveSpiderSpawnEgg => "Cave Spider Spawn Egg", + crate::Item::ChainCommandBlock => "Chain Command Block", + crate::Item::ChainmailBoots => "Chainmail Boots", + crate::Item::ChainmailChestplate => "Chainmail Chestplate", + crate::Item::ChainmailHelmet => "Chainmail Helmet", + crate::Item::ChainmailLeggings => "Chainmail Leggings", + crate::Item::Charcoal => "Charcoal", + crate::Item::Chest => "Chest", + crate::Item::ChestMinecart => "Minecart with Chest", + crate::Item::Chicken => "Raw Chicken", + crate::Item::ChickenSpawnEgg => "Chicken Spawn Egg", + crate::Item::ChippedAnvil => "Chipped Anvil", + crate::Item::ChiseledQuartzBlock => "Chiseled Quartz Block", + crate::Item::ChiseledRedSandstone => "Chiseled Red Sandstone", + crate::Item::ChiseledSandstone => "Chiseled Sandstone", + crate::Item::ChiseledStoneBricks => "Chiseled Stone Bricks", + crate::Item::ChorusFlower => "Chorus Flower", + crate::Item::ChorusFruit => "Chorus Fruit", + crate::Item::ChorusPlant => "Chorus Plant", + crate::Item::Clay => "Clay", + crate::Item::ClayBall => "Clay", + crate::Item::Clock => "Clock", + crate::Item::Coal => "Coal", + crate::Item::CoalBlock => "Block of Coal", + crate::Item::CoalOre => "Coal Ore", + crate::Item::CoarseDirt => "Coarse Dirt", + crate::Item::Cobblestone => "Cobblestone", + crate::Item::CobblestoneSlab => "Cobblestone Slab", + crate::Item::CobblestoneStairs => "Cobblestone Stairs", + crate::Item::CobblestoneWall => "Cobblestone Wall", + crate::Item::Cobweb => "Cobweb", + crate::Item::CocoaBeans => "Cocoa Beans", + crate::Item::Cod => "Raw Cod", + crate::Item::CodBucket => "Bucket of Cod", + crate::Item::CodSpawnEgg => "Cod Spawn Egg", + crate::Item::CommandBlock => "Command Block", + crate::Item::CommandBlockMinecart => "Minecart with Command Block", + crate::Item::Comparator => "Redstone Comparator", + crate::Item::Compass => "Compass", + crate::Item::Conduit => "Conduit", + crate::Item::CookedBeef => "Steak", + crate::Item::CookedChicken => "Cooked Chicken", + crate::Item::CookedCod => "Cooked Cod", + crate::Item::CookedMutton => "Cooked Mutton", + crate::Item::CookedPorkchop => "Cooked Porkchop", + crate::Item::CookedRabbit => "Cooked Rabbit", + crate::Item::CookedSalmon => "Cooked Salmon", + crate::Item::Cookie => "Cookie", + crate::Item::CowSpawnEgg => "Cow Spawn Egg", + crate::Item::CrackedStoneBricks => "Cracked Stone Bricks", + crate::Item::CraftingTable => "Crafting Table", + crate::Item::CreeperHead => "Creeper Head", + crate::Item::CreeperSpawnEgg => "Creeper Spawn Egg", + crate::Item::CutRedSandstone => "Cut Red Sandstone", + crate::Item::CutSandstone => "Cut Sandstone", + crate::Item::CyanBanner => "Cyan Banner", + crate::Item::CyanBed => "Cyan Bed", + crate::Item::CyanCarpet => "Cyan Carpet", + crate::Item::CyanConcrete => "Cyan Concrete", + crate::Item::CyanConcretePowder => "Cyan Concrete Powder", + crate::Item::CyanDye => "Cyan Dye", + crate::Item::CyanGlazedTerracotta => "Cyan Glazed Terracotta", + crate::Item::CyanShulkerBox => "Cyan Shulker Box", + crate::Item::CyanStainedGlass => "Cyan Stained Glass", + crate::Item::CyanStainedGlassPane => "Cyan Stained Glass Pane", + crate::Item::CyanTerracotta => "Cyan Terracotta", + crate::Item::CyanWool => "Cyan Wool", + crate::Item::DamagedAnvil => "Damaged Anvil", + crate::Item::Dandelion => "Dandelion", + crate::Item::DandelionYellow => "Dandelion Yellow", + crate::Item::DarkOakBoat => "Dark Oak Boat", + crate::Item::DarkOakButton => "Dark Oak Button", + crate::Item::DarkOakDoor => "Dark Oak Door", + crate::Item::DarkOakFence => "Dark Oak Fence", + crate::Item::DarkOakFenceGate => "Dark Oak Fence Gate", + crate::Item::DarkOakLeaves => "Dark Oak Leaves", + crate::Item::DarkOakLog => "Dark Oak Log", + crate::Item::DarkOakPlanks => "Dark Oak Planks", + crate::Item::DarkOakPressurePlate => "Dark Oak Pressure Plate", + crate::Item::DarkOakSapling => "Dark Oak Sapling", + crate::Item::DarkOakSlab => "Dark Oak Slab", + crate::Item::DarkOakStairs => "Dark Oak Stairs", + crate::Item::DarkOakTrapdoor => "Dark Oak Trapdoor", + crate::Item::DarkOakWood => "Dark Oak Wood", + crate::Item::DarkPrismarine => "Dark Prismarine", + crate::Item::DarkPrismarineSlab => "Dark Prismarine Slab", + crate::Item::DarkPrismarineStairs => "Dark Prismarine Stairs", + crate::Item::DaylightDetector => "Daylight Detector", + crate::Item::DeadBrainCoral => "Dead Brain Coral", + crate::Item::DeadBrainCoralBlock => "Dead Brain Coral Block", + crate::Item::DeadBrainCoralFan => "Dead Brain Coral Fan", + crate::Item::DeadBubbleCoral => "Dead Bubble Coral", + crate::Item::DeadBubbleCoralBlock => "Dead Bubble Coral Block", + crate::Item::DeadBubbleCoralFan => "Dead Bubble Coral Fan", + crate::Item::DeadBush => "Dead Bush", + crate::Item::DeadFireCoral => "Dead Fire Coral", + crate::Item::DeadFireCoralBlock => "Dead Fire Coral Block", + crate::Item::DeadFireCoralFan => "Dead Fire Coral Fan", + crate::Item::DeadHornCoral => "Dead Horn Coral", + crate::Item::DeadHornCoralBlock => "Dead Horn Coral Block", + crate::Item::DeadHornCoralFan => "Dead Horn Coral Fan", + crate::Item::DeadTubeCoral => "Dead Tube Coral", + crate::Item::DeadTubeCoralBlock => "Dead Tube Coral Block", + crate::Item::DeadTubeCoralFan => "Dead Tube Coral Fan", + crate::Item::DebugStick => "Debug Stick", + crate::Item::DetectorRail => "Detector Rail", + crate::Item::Diamond => "Diamond", + crate::Item::DiamondAxe => "Diamond Axe", + crate::Item::DiamondBlock => "Block of Diamond", + crate::Item::DiamondBoots => "Diamond Boots", + crate::Item::DiamondChestplate => "Diamond Chestplate", + crate::Item::DiamondHelmet => "Diamond Helmet", + crate::Item::DiamondHoe => "Diamond Hoe", + crate::Item::DiamondHorseArmor => "Diamond Horse Armor", + crate::Item::DiamondLeggings => "Diamond Leggings", + crate::Item::DiamondOre => "Diamond Ore", + crate::Item::DiamondPickaxe => "Diamond Pickaxe", + crate::Item::DiamondShovel => "Diamond Shovel", + crate::Item::DiamondSword => "Diamond Sword", + crate::Item::Diorite => "Diorite", + crate::Item::Dirt => "Dirt", + crate::Item::Dispenser => "Dispenser", + crate::Item::DolphinSpawnEgg => "Dolphin Spawn Egg", + crate::Item::DonkeySpawnEgg => "Donkey Spawn Egg", + crate::Item::DragonBreath => "Dragon's Breath", + crate::Item::DragonEgg => "Dragon Egg", + crate::Item::DragonHead => "Dragon Head", + crate::Item::DriedKelp => "Dried Kelp", + crate::Item::DriedKelpBlock => "Dried Kelp Block", + crate::Item::Dropper => "Dropper", + crate::Item::DrownedSpawnEgg => "Drowned Spawn Egg", + crate::Item::Egg => "Egg", + crate::Item::ElderGuardianSpawnEgg => "Elder Guardian Spawn Egg", + crate::Item::Elytra => "Elytra", + crate::Item::Emerald => "Emerald", + crate::Item::EmeraldBlock => "Block of Emerald", + crate::Item::EmeraldOre => "Emerald Ore", + crate::Item::EnchantedBook => "Enchanted Book", + crate::Item::EnchantedGoldenApple => "Enchanted Golden Apple", + crate::Item::EnchantingTable => "Enchanting Table", + crate::Item::EndCrystal => "End Crystal", + crate::Item::EndPortalFrame => "End Portal Frame", + crate::Item::EndRod => "End Rod", + crate::Item::EndStone => "End Stone", + crate::Item::EndStoneBricks => "End Stone Bricks", + crate::Item::EnderChest => "Ender Chest", + crate::Item::EnderEye => "Eye of Ender", + crate::Item::EnderPearl => "Ender Pearl", + crate::Item::EndermanSpawnEgg => "Enderman Spawn Egg", + crate::Item::EndermiteSpawnEgg => "Endermite Spawn Egg", + crate::Item::EvokerSpawnEgg => "Evoker Spawn Egg", + crate::Item::ExperienceBottle => "Bottle o' Enchanting", + crate::Item::Farmland => "Farmland", + crate::Item::Feather => "Feather", + crate::Item::FermentedSpiderEye => "Fermented Spider Eye", + crate::Item::Fern => "Fern", + crate::Item::FilledMap => "Map", + crate::Item::FireCharge => "Fire Charge", + crate::Item::FireCoral => "Fire Coral", + crate::Item::FireCoralBlock => "Fire Coral Block", + crate::Item::FireCoralFan => "Fire Coral Fan", + crate::Item::FireworkRocket => "Firework Rocket", + crate::Item::FireworkStar => "Firework Star", + crate::Item::FishingRod => "Fishing Rod", + crate::Item::Flint => "Flint", + crate::Item::FlintAndSteel => "Flint and Steel", + crate::Item::FlowerPot => "Flower Pot", + crate::Item::Furnace => "Furnace", + crate::Item::FurnaceMinecart => "Minecart with Furnace", + crate::Item::GhastSpawnEgg => "Ghast Spawn Egg", + crate::Item::GhastTear => "Ghast Tear", + crate::Item::Glass => "Glass", + crate::Item::GlassBottle => "Glass Bottle", + crate::Item::GlassPane => "Glass Pane", + crate::Item::GlisteringMelonSlice => "Glistering Melon Slice", + crate::Item::Glowstone => "Glowstone", + crate::Item::GlowstoneDust => "Glowstone Dust", + crate::Item::GoldBlock => "Block of Gold", + crate::Item::GoldIngot => "Gold Ingot", + crate::Item::GoldNugget => "Gold Nugget", + crate::Item::GoldOre => "Gold Ore", + crate::Item::GoldenApple => "Golden Apple", + crate::Item::GoldenAxe => "Golden Axe", + crate::Item::GoldenBoots => "Golden Boots", + crate::Item::GoldenCarrot => "Golden Carrot", + crate::Item::GoldenChestplate => "Golden Chestplate", + crate::Item::GoldenHelmet => "Golden Helmet", + crate::Item::GoldenHoe => "Golden Hoe", + crate::Item::GoldenHorseArmor => "Golden Horse Armor", + crate::Item::GoldenLeggings => "Golden Leggings", + crate::Item::GoldenPickaxe => "Golden Pickaxe", + crate::Item::GoldenShovel => "Golden Shovel", + crate::Item::GoldenSword => "Golden Sword", + crate::Item::Granite => "Granite", + crate::Item::Grass => "Grass", + crate::Item::GrassBlock => "Grass Block", + crate::Item::GrassPath => "Grass Path", + crate::Item::Gravel => "Gravel", + crate::Item::GrayBanner => "Gray Banner", + crate::Item::GrayBed => "Gray Bed", + crate::Item::GrayCarpet => "Gray Carpet", + crate::Item::GrayConcrete => "Gray Concrete", + crate::Item::GrayConcretePowder => "Gray Concrete Powder", + crate::Item::GrayDye => "Gray Dye", + crate::Item::GrayGlazedTerracotta => "Gray Glazed Terracotta", + crate::Item::GrayShulkerBox => "Gray Shulker Box", + crate::Item::GrayStainedGlass => "Gray Stained Glass", + crate::Item::GrayStainedGlassPane => "Gray Stained Glass Pane", + crate::Item::GrayTerracotta => "Gray Terracotta", + crate::Item::GrayWool => "Gray Wool", + crate::Item::GreenBanner => "Green Banner", + crate::Item::GreenBed => "Green Bed", + crate::Item::GreenCarpet => "Green Carpet", + crate::Item::GreenConcrete => "Green Concrete", + crate::Item::GreenConcretePowder => "Green Concrete Powder", + crate::Item::GreenGlazedTerracotta => "Green Glazed Terracotta", + crate::Item::GreenShulkerBox => "Green Shulker Box", + crate::Item::GreenStainedGlass => "Green Stained Glass", + crate::Item::GreenStainedGlassPane => "Green Stained Glass Pane", + crate::Item::GreenTerracotta => "Green Terracotta", + crate::Item::GreenWool => "Green Wool", + crate::Item::GuardianSpawnEgg => "Guardian Spawn Egg", + crate::Item::Gunpowder => "Gunpowder", + crate::Item::HayBlock => "Hay Bale", + crate::Item::HeartOfTheSea => "Heart of the Sea", + crate::Item::HeavyWeightedPressurePlate => "Heavy Weighted Pressure Plate", + crate::Item::Hopper => "Hopper", + crate::Item::HopperMinecart => "Minecart with Hopper", + crate::Item::HornCoral => "Horn Coral", + crate::Item::HornCoralBlock => "Horn Coral Block", + crate::Item::HornCoralFan => "Horn Coral Fan", + crate::Item::HorseSpawnEgg => "Horse Spawn Egg", + crate::Item::HuskSpawnEgg => "Husk Spawn Egg", + crate::Item::Ice => "Ice", + crate::Item::InfestedChiseledStoneBricks => "Infested Chiseled Stone Bricks", + crate::Item::InfestedCobblestone => "Infested Cobblestone", + crate::Item::InfestedCrackedStoneBricks => "Infested Cracked Stone Bricks", + crate::Item::InfestedMossyStoneBricks => "Infested Mossy Stone Bricks", + crate::Item::InfestedStone => "Infested Stone", + crate::Item::InfestedStoneBricks => "Infested Stone Bricks", + crate::Item::InkSac => "Ink Sac", + crate::Item::IronAxe => "Iron Axe", + crate::Item::IronBars => "Iron Bars", + crate::Item::IronBlock => "Block of Iron", + crate::Item::IronBoots => "Iron Boots", + crate::Item::IronChestplate => "Iron Chestplate", + crate::Item::IronDoor => "Iron Door", + crate::Item::IronHelmet => "Iron Helmet", + crate::Item::IronHoe => "Iron Hoe", + crate::Item::IronHorseArmor => "Iron Horse Armor", + crate::Item::IronIngot => "Iron Ingot", + crate::Item::IronLeggings => "Iron Leggings", + crate::Item::IronNugget => "Iron Nugget", + crate::Item::IronOre => "Iron Ore", + crate::Item::IronPickaxe => "Iron Pickaxe", + crate::Item::IronShovel => "Iron Shovel", + crate::Item::IronSword => "Iron Sword", + crate::Item::IronTrapdoor => "Iron Trapdoor", + crate::Item::ItemFrame => "Item Frame", + crate::Item::JackOLantern => "Jack o'Lantern", + crate::Item::Jukebox => "Jukebox", + crate::Item::JungleBoat => "Jungle Boat", + crate::Item::JungleButton => "Jungle Button", + crate::Item::JungleDoor => "Jungle Door", + crate::Item::JungleFence => "Jungle Fence", + crate::Item::JungleFenceGate => "Jungle Fence Gate", + crate::Item::JungleLeaves => "Jungle Leaves", + crate::Item::JungleLog => "Jungle Log", + crate::Item::JunglePlanks => "Jungle Planks", + crate::Item::JunglePressurePlate => "Jungle Pressure Plate", + crate::Item::JungleSapling => "Jungle Sapling", + crate::Item::JungleSlab => "Jungle Slab", + crate::Item::JungleStairs => "Jungle Stairs", + crate::Item::JungleTrapdoor => "Jungle Trapdoor", + crate::Item::JungleWood => "Jungle Wood", + crate::Item::Kelp => "Kelp", + crate::Item::KnowledgeBook => "Knowledge Book", + crate::Item::Ladder => "Ladder", + crate::Item::LapisBlock => "Lapis Lazuli Block", + crate::Item::LapisLazuli => "Lapis Lazuli", + crate::Item::LapisOre => "Lapis Lazuli Ore", + crate::Item::LargeFern => "Large Fern", + crate::Item::LavaBucket => "Lava Bucket", + crate::Item::Lead => "Lead", + crate::Item::Leather => "Leather", + crate::Item::LeatherBoots => "Leather Boots", + crate::Item::LeatherChestplate => "Leather Tunic", + crate::Item::LeatherHelmet => "Leather Cap", + crate::Item::LeatherLeggings => "Leather Pants", + crate::Item::Lever => "Lever", + crate::Item::LightBlueBanner => "Light Blue Banner", + crate::Item::LightBlueBed => "Light Blue Bed", + crate::Item::LightBlueCarpet => "Light Blue Carpet", + crate::Item::LightBlueConcrete => "Light Blue Concrete", + crate::Item::LightBlueConcretePowder => "Light Blue Concrete Powder", + crate::Item::LightBlueDye => "Light Blue Dye", + crate::Item::LightBlueGlazedTerracotta => "Light Blue Glazed Terracotta", + crate::Item::LightBlueShulkerBox => "Light Blue Shulker Box", + crate::Item::LightBlueStainedGlass => "Light Blue Stained Glass", + crate::Item::LightBlueStainedGlassPane => "Light Blue Stained Glass Pane", + crate::Item::LightBlueTerracotta => "Light Blue Terracotta", + crate::Item::LightBlueWool => "Light Blue Wool", + crate::Item::LightGrayBanner => "Light Gray Banner", + crate::Item::LightGrayBed => "Light Gray Bed", + crate::Item::LightGrayCarpet => "Light Gray Carpet", + crate::Item::LightGrayConcrete => "Light Gray Concrete", + crate::Item::LightGrayConcretePowder => "Light Gray Concrete Powder", + crate::Item::LightGrayDye => "Light Gray Dye", + crate::Item::LightGrayGlazedTerracotta => "Light Gray Glazed Terracotta", + crate::Item::LightGrayShulkerBox => "Light Gray Shulker Box", + crate::Item::LightGrayStainedGlass => "Light Gray Stained Glass", + crate::Item::LightGrayStainedGlassPane => "Light Gray Stained Glass Pane", + crate::Item::LightGrayTerracotta => "Light Gray Terracotta", + crate::Item::LightGrayWool => "Light Gray Wool", + crate::Item::LightWeightedPressurePlate => "Light Weighted Pressure Plate", + crate::Item::Lilac => "Lilac", + crate::Item::LilyPad => "Lily Pad", + crate::Item::LimeBanner => "Lime Banner", + crate::Item::LimeBed => "Lime Bed", + crate::Item::LimeCarpet => "Lime Carpet", + crate::Item::LimeConcrete => "Lime Concrete", + crate::Item::LimeConcretePowder => "Lime Concrete Powder", + crate::Item::LimeDye => "Lime Dye", + crate::Item::LimeGlazedTerracotta => "Lime Glazed Terracotta", + crate::Item::LimeShulkerBox => "Lime Shulker Box", + crate::Item::LimeStainedGlass => "Lime Stained Glass", + crate::Item::LimeStainedGlassPane => "Lime Stained Glass Pane", + crate::Item::LimeTerracotta => "Lime Terracotta", + crate::Item::LimeWool => "Lime Wool", + crate::Item::LingeringPotion => "Lingering Potion", + crate::Item::LlamaSpawnEgg => "Llama Spawn Egg", + crate::Item::MagentaBanner => "Magenta Banner", + crate::Item::MagentaBed => "Magenta Bed", + crate::Item::MagentaCarpet => "Magenta Carpet", + crate::Item::MagentaConcrete => "Magenta Concrete", + crate::Item::MagentaConcretePowder => "Magenta Concrete Powder", + crate::Item::MagentaDye => "Magenta Dye", + crate::Item::MagentaGlazedTerracotta => "Magenta Glazed Terracotta", + crate::Item::MagentaShulkerBox => "Magenta Shulker Box", + crate::Item::MagentaStainedGlass => "Magenta Stained Glass", + crate::Item::MagentaStainedGlassPane => "Magenta Stained Glass Pane", + crate::Item::MagentaTerracotta => "Magenta Terracotta", + crate::Item::MagentaWool => "Magenta Wool", + crate::Item::MagmaBlock => "Magma Block", + crate::Item::MagmaCream => "Magma Cream", + crate::Item::MagmaCubeSpawnEgg => "Magma Cube Spawn Egg", + crate::Item::Map => "Empty Map", + crate::Item::Melon => "Melon", + crate::Item::MelonSeeds => "Melon Seeds", + crate::Item::MelonSlice => "Melon Slice", + crate::Item::MilkBucket => "Milk Bucket", + crate::Item::Minecart => "Minecart", + crate::Item::MooshroomSpawnEgg => "Mooshroom Spawn Egg", + crate::Item::MossyCobblestone => "Mossy Cobblestone", + crate::Item::MossyCobblestoneWall => "Mossy Cobblestone Wall", + crate::Item::MossyStoneBricks => "Mossy Stone Bricks", + crate::Item::MuleSpawnEgg => "Mule Spawn Egg", + crate::Item::MushroomStem => "Mushroom Stem", + crate::Item::MushroomStew => "Mushroom Stew", + crate::Item::MusicDisc11 => "11 Disc", + crate::Item::MusicDisc13 => "13 Disc", + crate::Item::MusicDiscBlocks => "Blocks Disc", + crate::Item::MusicDiscCat => "Cat Disc", + crate::Item::MusicDiscChirp => "Chirp Disc", + crate::Item::MusicDiscFar => "Far Disc", + crate::Item::MusicDiscMall => "Mall Disc", + crate::Item::MusicDiscMellohi => "Mellohi Disc", + crate::Item::MusicDiscStal => "Stal Disc", + crate::Item::MusicDiscStrad => "Strad Disc", + crate::Item::MusicDiscWait => "Wait Disc", + crate::Item::MusicDiscWard => "Ward Disc", + crate::Item::Mutton => "Raw Mutton", + crate::Item::Mycelium => "Mycelium", + crate::Item::NameTag => "Name Tag", + crate::Item::NautilusShell => "Nautilus Shell", + crate::Item::NetherBrick => "Nether Brick", + crate::Item::NetherBrickFence => "Nether Brick Fence", + crate::Item::NetherBrickSlab => "Nether Brick Slab", + crate::Item::NetherBrickStairs => "Nether Brick Stairs", + crate::Item::NetherBricks => "Nether Bricks", + crate::Item::NetherQuartzOre => "Nether Quartz Ore", + crate::Item::NetherStar => "Nether Star", + crate::Item::NetherWart => "Nether Wart", + crate::Item::NetherWartBlock => "Nether Wart Block", + crate::Item::Netherrack => "Netherrack", + crate::Item::NoteBlock => "Note Block", + crate::Item::OakBoat => "Oak Boat", + crate::Item::OakButton => "Oak Button", + crate::Item::OakDoor => "Oak Door", + crate::Item::OakFence => "Oak Fence", + crate::Item::OakFenceGate => "Oak Fence Gate", + crate::Item::OakLeaves => "Oak Leaves", + crate::Item::OakLog => "Oak Log", + crate::Item::OakPlanks => "Oak Planks", + crate::Item::OakPressurePlate => "Oak Pressure Plate", + crate::Item::OakSapling => "Oak Sapling", + crate::Item::OakSlab => "Oak Slab", + crate::Item::OakStairs => "Oak Stairs", + crate::Item::OakTrapdoor => "Oak Trapdoor", + crate::Item::OakWood => "Oak Wood", + crate::Item::Observer => "Observer", + crate::Item::Obsidian => "Obsidian", + crate::Item::OcelotSpawnEgg => "Ocelot Spawn Egg", + crate::Item::OrangeBanner => "Orange Banner", + crate::Item::OrangeBed => "Orange Bed", + crate::Item::OrangeCarpet => "Orange Carpet", + crate::Item::OrangeConcrete => "Orange Concrete", + crate::Item::OrangeConcretePowder => "Orange Concrete Powder", + crate::Item::OrangeDye => "Orange Dye", + crate::Item::OrangeGlazedTerracotta => "Orange Glazed Terracotta", + crate::Item::OrangeShulkerBox => "Orange Shulker Box", + crate::Item::OrangeStainedGlass => "Orange Stained Glass", + crate::Item::OrangeStainedGlassPane => "Orange Stained Glass Pane", + crate::Item::OrangeTerracotta => "Orange Terracotta", + crate::Item::OrangeTulip => "Orange Tulip", + crate::Item::OrangeWool => "Orange Wool", + crate::Item::OxeyeDaisy => "Oxeye Daisy", + crate::Item::PackedIce => "Packed Ice", + crate::Item::Painting => "Painting", + crate::Item::Paper => "Paper", + crate::Item::ParrotSpawnEgg => "Parrot Spawn Egg", + crate::Item::Peony => "Peony", + crate::Item::PetrifiedOakSlab => "Petrified Oak Slab", + crate::Item::PhantomMembrane => "Phantom Membrane", + crate::Item::PhantomSpawnEgg => "Phantom Spawn Egg", + crate::Item::PigSpawnEgg => "Pig Spawn Egg", + crate::Item::PinkBanner => "Pink Banner", + crate::Item::PinkBed => "Pink Bed", + crate::Item::PinkCarpet => "Pink Carpet", + crate::Item::PinkConcrete => "Pink Concrete", + crate::Item::PinkConcretePowder => "Pink Concrete Powder", + crate::Item::PinkDye => "Pink Dye", + crate::Item::PinkGlazedTerracotta => "Pink Glazed Terracotta", + crate::Item::PinkShulkerBox => "Pink Shulker Box", + crate::Item::PinkStainedGlass => "Pink Stained Glass", + crate::Item::PinkStainedGlassPane => "Pink Stained Glass Pane", + crate::Item::PinkTerracotta => "Pink Terracotta", + crate::Item::PinkTulip => "Pink Tulip", + crate::Item::PinkWool => "Pink Wool", + crate::Item::Piston => "Piston", + crate::Item::PlayerHead => "Player Head", + crate::Item::Podzol => "Podzol", + crate::Item::PoisonousPotato => "Poisonous Potato", + crate::Item::PolarBearSpawnEgg => "Polar Bear Spawn Egg", + crate::Item::PolishedAndesite => "Polished Andesite", + crate::Item::PolishedDiorite => "Polished Diorite", + crate::Item::PolishedGranite => "Polished Granite", + crate::Item::PoppedChorusFruit => "Popped Chorus Fruit", + crate::Item::Poppy => "Poppy", + crate::Item::Porkchop => "Raw Porkchop", + crate::Item::Potato => "Potato", + crate::Item::Potion => "Potion", + crate::Item::PoweredRail => "Powered Rail", + crate::Item::Prismarine => "Prismarine", + crate::Item::PrismarineBrickSlab => "Prismarine Brick Slab", + crate::Item::PrismarineBrickStairs => "Prismarine Brick Stairs", + crate::Item::PrismarineBricks => "Prismarine Bricks", + crate::Item::PrismarineCrystals => "Prismarine Crystals", + crate::Item::PrismarineShard => "Prismarine Shard", + crate::Item::PrismarineSlab => "Prismarine Slab", + crate::Item::PrismarineStairs => "Prismarine Stairs", + crate::Item::Pufferfish => "Pufferfish", + crate::Item::PufferfishBucket => "Bucket of Pufferfish", + crate::Item::PufferfishSpawnEgg => "Pufferfish Spawn Egg", + crate::Item::Pumpkin => "Pumpkin", + crate::Item::PumpkinPie => "Pumpkin Pie", + crate::Item::PumpkinSeeds => "Pumpkin Seeds", + crate::Item::PurpleBanner => "Purple Banner", + crate::Item::PurpleBed => "Purple Bed", + crate::Item::PurpleCarpet => "Purple Carpet", + crate::Item::PurpleConcrete => "Purple Concrete", + crate::Item::PurpleConcretePowder => "Purple Concrete Powder", + crate::Item::PurpleDye => "Purple Dye", + crate::Item::PurpleGlazedTerracotta => "Purple Glazed Terracotta", + crate::Item::PurpleShulkerBox => "Purple Shulker Box", + crate::Item::PurpleStainedGlass => "Purple Stained Glass", + crate::Item::PurpleStainedGlassPane => "Purple Stained Glass Pane", + crate::Item::PurpleTerracotta => "Purple Terracotta", + crate::Item::PurpleWool => "Purple Wool", + crate::Item::PurpurBlock => "Purpur Block", + crate::Item::PurpurPillar => "Purpur Pillar", + crate::Item::PurpurSlab => "Purpur Slab", + crate::Item::PurpurStairs => "Purpur Stairs", + crate::Item::Quartz => "Nether Quartz", + crate::Item::QuartzBlock => "Block of Quartz", + crate::Item::QuartzPillar => "Quartz Pillar", + crate::Item::QuartzSlab => "Quartz Slab", + crate::Item::QuartzStairs => "Quartz Stairs", + crate::Item::Rabbit => "Raw Rabbit", + crate::Item::RabbitFoot => "Rabbit's Foot", + crate::Item::RabbitHide => "Rabbit Hide", + crate::Item::RabbitSpawnEgg => "Rabbit Spawn Egg", + crate::Item::RabbitStew => "Rabbit Stew", + crate::Item::Rail => "Rail", + crate::Item::RedBanner => "Red Banner", + crate::Item::RedBed => "Red Bed", + crate::Item::RedCarpet => "Red Carpet", + crate::Item::RedConcrete => "Red Concrete", + crate::Item::RedConcretePowder => "Red Concrete Powder", + crate::Item::RedGlazedTerracotta => "Red Glazed Terracotta", + crate::Item::RedMushroom => "Red Mushroom", + crate::Item::RedMushroomBlock => "Red Mushroom Block", + crate::Item::RedNetherBricks => "Red Nether Bricks", + crate::Item::RedSand => "Red Sand", + crate::Item::RedSandstone => "Red Sandstone", + crate::Item::RedSandstoneSlab => "Red Sandstone Slab", + crate::Item::RedSandstoneStairs => "Red Sandstone Stairs", + crate::Item::RedShulkerBox => "Red Shulker Box", + crate::Item::RedStainedGlass => "Red Stained Glass", + crate::Item::RedStainedGlassPane => "Red Stained Glass Pane", + crate::Item::RedTerracotta => "Red Terracotta", + crate::Item::RedTulip => "Red Tulip", + crate::Item::RedWool => "Red Wool", + crate::Item::Redstone => "Redstone", + crate::Item::RedstoneBlock => "Block of Redstone", + crate::Item::RedstoneLamp => "Redstone Lamp", + crate::Item::RedstoneOre => "Redstone Ore", + crate::Item::RedstoneTorch => "Redstone Torch", + crate::Item::Repeater => "Redstone Repeater", + crate::Item::RepeatingCommandBlock => "Repeating Command Block", + crate::Item::RoseBush => "Rose Bush", + crate::Item::RoseRed => "Rose Red", + crate::Item::RottenFlesh => "Rotten Flesh", + crate::Item::Saddle => "Saddle", + crate::Item::Salmon => "Raw Salmon", + crate::Item::SalmonBucket => "Bucket of Salmon", + crate::Item::SalmonSpawnEgg => "Salmon Spawn Egg", + crate::Item::Sand => "Sand", + crate::Item::Sandstone => "Sandstone", + crate::Item::SandstoneSlab => "Sandstone Slab", + crate::Item::SandstoneStairs => "Sandstone Stairs", + crate::Item::Scute => "Scute", + crate::Item::SeaLantern => "Sea Lantern", + crate::Item::SeaPickle => "Sea Pickle", + crate::Item::Seagrass => "Seagrass", + crate::Item::Shears => "Shears", + crate::Item::SheepSpawnEgg => "Sheep Spawn Egg", + crate::Item::Shield => "Shield", + crate::Item::ShulkerBox => "Shulker Box", + crate::Item::ShulkerShell => "Shulker Shell", + crate::Item::ShulkerSpawnEgg => "Shulker Spawn Egg", + crate::Item::Sign => "Sign", + crate::Item::SilverfishSpawnEgg => "Silverfish Spawn Egg", + crate::Item::SkeletonHorseSpawnEgg => "Skeleton Horse Spawn Egg", + crate::Item::SkeletonSkull => "Skeleton Skull", + crate::Item::SkeletonSpawnEgg => "Skeleton Spawn Egg", + crate::Item::SlimeBall => "Slimeball", + crate::Item::SlimeBlock => "Slime Block", + crate::Item::SlimeSpawnEgg => "Slime Spawn Egg", + crate::Item::SmoothQuartz => "Smooth Quartz", + crate::Item::SmoothRedSandstone => "Smooth Red Sandstone", + crate::Item::SmoothSandstone => "Smooth Sandstone", + crate::Item::SmoothStone => "Smooth Stone", + crate::Item::Snow => "Snow", + crate::Item::SnowBlock => "Snow Block", + crate::Item::Snowball => "Snowball", + crate::Item::SoulSand => "Soul Sand", + crate::Item::Spawner => "Spawner", + crate::Item::SpectralArrow => "Spectral Arrow", + crate::Item::SpiderEye => "Spider Eye", + crate::Item::SpiderSpawnEgg => "Spider Spawn Egg", + crate::Item::SplashPotion => "Splash Potion", + crate::Item::Sponge => "Sponge", + crate::Item::SpruceBoat => "Spruce Boat", + crate::Item::SpruceButton => "Spruce Button", + crate::Item::SpruceDoor => "Spruce Door", + crate::Item::SpruceFence => "Spruce Fence", + crate::Item::SpruceFenceGate => "Spruce Fence Gate", + crate::Item::SpruceLeaves => "Spruce Leaves", + crate::Item::SpruceLog => "Spruce Log", + crate::Item::SprucePlanks => "Spruce Planks", + crate::Item::SprucePressurePlate => "Spruce Pressure Plate", + crate::Item::SpruceSapling => "Spruce Sapling", + crate::Item::SpruceSlab => "Spruce Slab", + crate::Item::SpruceStairs => "Spruce Stairs", + crate::Item::SpruceTrapdoor => "Spruce Trapdoor", + crate::Item::SpruceWood => "Spruce Wood", + crate::Item::SquidSpawnEgg => "Squid Spawn Egg", + crate::Item::Stick => "Stick", + crate::Item::StickyPiston => "Sticky Piston", + crate::Item::Stone => "Stone", + crate::Item::StoneAxe => "Stone Axe", + crate::Item::StoneBrickSlab => "Stone Brick Slab", + crate::Item::StoneBrickStairs => "Stone Brick Stairs", + crate::Item::StoneBricks => "Stone Bricks", + crate::Item::StoneButton => "Stone Button", + crate::Item::StoneHoe => "Stone Hoe", + crate::Item::StonePickaxe => "Stone Pickaxe", + crate::Item::StonePressurePlate => "Stone Pressure Plate", + crate::Item::StoneShovel => "Stone Shovel", + crate::Item::StoneSlab => "Stone Slab", + crate::Item::StoneSword => "Stone Sword", + crate::Item::StraySpawnEgg => "Stray Spawn Egg", + crate::Item::String => "String", + crate::Item::StrippedAcaciaLog => "Stripped Acacia Log", + crate::Item::StrippedAcaciaWood => "Stripped Acacia Wood", + crate::Item::StrippedBirchLog => "Stripped Birch Log", + crate::Item::StrippedBirchWood => "Stripped Birch Wood", + crate::Item::StrippedDarkOakLog => "Stripped Dark Oak Log", + crate::Item::StrippedDarkOakWood => "Stripped Dark Oak Wood", + crate::Item::StrippedJungleLog => "Stripped Jungle Log", + crate::Item::StrippedJungleWood => "Stripped Jungle Wood", + crate::Item::StrippedOakLog => "Stripped Oak Log", + crate::Item::StrippedOakWood => "Stripped Oak Wood", + crate::Item::StrippedSpruceLog => "Stripped Spruce Log", + crate::Item::StrippedSpruceWood => "Stripped Spruce Wood", + crate::Item::StructureBlock => "Structure Block", + crate::Item::StructureVoid => "Structure Void", + crate::Item::Sugar => "Sugar", + crate::Item::SugarCane => "Sugar Cane", + crate::Item::Sunflower => "Sunflower", + crate::Item::TallGrass => "Tall Grass", + crate::Item::Terracotta => "Terracotta", + crate::Item::TippedArrow => "Tipped Arrow", + crate::Item::Tnt => "TNT", + crate::Item::TntMinecart => "Minecart with TNT", + crate::Item::Torch => "Torch", + crate::Item::TotemOfUndying => "Totem of Undying", + crate::Item::TrappedChest => "Trapped Chest", + crate::Item::Trident => "Trident", + crate::Item::TripwireHook => "Tripwire Hook", + crate::Item::TropicalFish => "Tropical Fish", + crate::Item::TropicalFishBucket => "Bucket of Tropical Fish", + crate::Item::TropicalFishSpawnEgg => "Tropical Fish Spawn Egg", + crate::Item::TubeCoral => "Tube Coral", + crate::Item::TubeCoralBlock => "Tube Coral Block", + crate::Item::TubeCoralFan => "Tube Coral Fan", + crate::Item::TurtleEgg => "Turtle Egg", + crate::Item::TurtleHelmet => "Turtle Shell", + crate::Item::TurtleSpawnEgg => "Turtle Spawn Egg", + crate::Item::VexSpawnEgg => "Vex Spawn Egg", + crate::Item::VillagerSpawnEgg => "Villager Spawn Egg", + crate::Item::VindicatorSpawnEgg => "Vindicator Spawn Egg", + crate::Item::Vine => "Vines", + crate::Item::WaterBucket => "Water Bucket", + crate::Item::WetSponge => "Wet Sponge", + crate::Item::Wheat => "Wheat", + crate::Item::WheatSeeds => "Wheat Seeds", + crate::Item::WhiteBanner => "White Banner", + crate::Item::WhiteBed => "White Bed", + crate::Item::WhiteCarpet => "White Carpet", + crate::Item::WhiteConcrete => "White Concrete", + crate::Item::WhiteConcretePowder => "White Concrete Powder", + crate::Item::WhiteGlazedTerracotta => "White Glazed Terracotta", + crate::Item::WhiteShulkerBox => "White Shulker Box", + crate::Item::WhiteStainedGlass => "White Stained Glass", + crate::Item::WhiteStainedGlassPane => "White Stained Glass Pane", + crate::Item::WhiteTerracotta => "White Terracotta", + crate::Item::WhiteTulip => "White Tulip", + crate::Item::WhiteWool => "White Wool", + crate::Item::WitchSpawnEgg => "Witch Spawn Egg", + crate::Item::WitherSkeletonSkull => "Wither Skeleton Skull", + crate::Item::WitherSkeletonSpawnEgg => "Wither Skeleton Spawn Egg", + crate::Item::WolfSpawnEgg => "Wolf Spawn Egg", + crate::Item::WoodenAxe => "Wooden Axe", + crate::Item::WoodenHoe => "Wooden Hoe", + crate::Item::WoodenPickaxe => "Wooden Pickaxe", + crate::Item::WoodenShovel => "Wooden Shovel", + crate::Item::WoodenSword => "Wooden Sword", + crate::Item::WritableBook => "Book and Quill", + crate::Item::WrittenBook => "Written Book", + crate::Item::YellowBanner => "Yellow Banner", + crate::Item::YellowBed => "Yellow Bed", + crate::Item::YellowCarpet => "Yellow Carpet", + crate::Item::YellowConcrete => "Yellow Concrete", + crate::Item::YellowConcretePowder => "Yellow Concrete Powder", + crate::Item::YellowGlazedTerracotta => "Yellow Glazed Terracotta", + crate::Item::YellowShulkerBox => "Yellow Shulker Box", + crate::Item::YellowStainedGlass => "Yellow Stained Glass", + crate::Item::YellowStainedGlassPane => "Yellow Stained Glass Pane", + crate::Item::YellowTerracotta => "Yellow Terracotta", + crate::Item::YellowWool => "Yellow Wool", + crate::Item::ZombieHead => "Zombie Head", + crate::Item::ZombieHorseSpawnEgg => "Zombie Horse Spawn Egg", + crate::Item::ZombiePigmanSpawnEgg => "Zombie Pigman Spawn Egg", + crate::Item::ZombieSpawnEgg => "Zombie Spawn Egg", + crate::Item::ZombieVillagerSpawnEgg => "Zombie Villager Spawn Egg", + } + } +} +impl crate::Item { + pub fn stack_size(self) -> u32 { + match self { + crate::Item::AcaciaBoat => 1u32, + crate::Item::AcaciaButton => 64u32, + crate::Item::AcaciaDoor => 64u32, + crate::Item::AcaciaFence => 64u32, + crate::Item::AcaciaFenceGate => 64u32, + crate::Item::AcaciaLeaves => 64u32, + crate::Item::AcaciaLog => 64u32, + crate::Item::AcaciaPlanks => 64u32, + crate::Item::AcaciaPressurePlate => 64u32, + crate::Item::AcaciaSapling => 64u32, + crate::Item::AcaciaSlab => 64u32, + crate::Item::AcaciaStairs => 64u32, + crate::Item::AcaciaTrapdoor => 64u32, + crate::Item::AcaciaWood => 64u32, + crate::Item::ActivatorRail => 64u32, + crate::Item::Air => 64u32, + crate::Item::Allium => 64u32, + crate::Item::Andesite => 64u32, + crate::Item::Anvil => 64u32, + crate::Item::Apple => 64u32, + crate::Item::ArmorStand => 16u32, + crate::Item::Arrow => 64u32, + crate::Item::AzureBluet => 64u32, + crate::Item::BakedPotato => 64u32, + crate::Item::Barrier => 64u32, + crate::Item::BatSpawnEgg => 64u32, + crate::Item::Beacon => 64u32, + crate::Item::Bedrock => 64u32, + crate::Item::Beef => 64u32, + crate::Item::Beetroot => 64u32, + crate::Item::BeetrootSeeds => 64u32, + crate::Item::BeetrootSoup => 1u32, + crate::Item::BirchBoat => 1u32, + crate::Item::BirchButton => 64u32, + crate::Item::BirchDoor => 64u32, + crate::Item::BirchFence => 64u32, + crate::Item::BirchFenceGate => 64u32, + crate::Item::BirchLeaves => 64u32, + crate::Item::BirchLog => 64u32, + crate::Item::BirchPlanks => 64u32, + crate::Item::BirchPressurePlate => 64u32, + crate::Item::BirchSapling => 64u32, + crate::Item::BirchSlab => 64u32, + crate::Item::BirchStairs => 64u32, + crate::Item::BirchTrapdoor => 64u32, + crate::Item::BirchWood => 64u32, + crate::Item::BlackBanner => 16u32, + crate::Item::BlackBed => 1u32, + crate::Item::BlackCarpet => 64u32, + crate::Item::BlackConcrete => 64u32, + crate::Item::BlackConcretePowder => 64u32, + crate::Item::BlackGlazedTerracotta => 64u32, + crate::Item::BlackShulkerBox => 1u32, + crate::Item::BlackStainedGlass => 64u32, + crate::Item::BlackStainedGlassPane => 64u32, + crate::Item::BlackTerracotta => 64u32, + crate::Item::BlackWool => 64u32, + crate::Item::BlazePowder => 64u32, + crate::Item::BlazeRod => 64u32, + crate::Item::BlazeSpawnEgg => 64u32, + crate::Item::BlueBanner => 16u32, + crate::Item::BlueBed => 1u32, + crate::Item::BlueCarpet => 64u32, + crate::Item::BlueConcrete => 64u32, + crate::Item::BlueConcretePowder => 64u32, + crate::Item::BlueGlazedTerracotta => 64u32, + crate::Item::BlueIce => 64u32, + crate::Item::BlueOrchid => 64u32, + crate::Item::BlueShulkerBox => 1u32, + crate::Item::BlueStainedGlass => 64u32, + crate::Item::BlueStainedGlassPane => 64u32, + crate::Item::BlueTerracotta => 64u32, + crate::Item::BlueWool => 64u32, + crate::Item::Bone => 64u32, + crate::Item::BoneBlock => 64u32, + crate::Item::BoneMeal => 64u32, + crate::Item::Book => 64u32, + crate::Item::Bookshelf => 64u32, + crate::Item::Bow => 64u32, + crate::Item::Bowl => 64u32, + crate::Item::BrainCoral => 64u32, + crate::Item::BrainCoralBlock => 64u32, + crate::Item::BrainCoralFan => 64u32, + crate::Item::Bread => 64u32, + crate::Item::BrewingStand => 64u32, + crate::Item::Brick => 64u32, + crate::Item::BrickSlab => 64u32, + crate::Item::BrickStairs => 64u32, + crate::Item::Bricks => 64u32, + crate::Item::BrownBanner => 16u32, + crate::Item::BrownBed => 1u32, + crate::Item::BrownCarpet => 64u32, + crate::Item::BrownConcrete => 64u32, + crate::Item::BrownConcretePowder => 64u32, + crate::Item::BrownGlazedTerracotta => 64u32, + crate::Item::BrownMushroom => 64u32, + crate::Item::BrownMushroomBlock => 64u32, + crate::Item::BrownShulkerBox => 1u32, + crate::Item::BrownStainedGlass => 64u32, + crate::Item::BrownStainedGlassPane => 64u32, + crate::Item::BrownTerracotta => 64u32, + crate::Item::BrownWool => 64u32, + crate::Item::BubbleCoral => 64u32, + crate::Item::BubbleCoralBlock => 64u32, + crate::Item::BubbleCoralFan => 64u32, + crate::Item::Bucket => 16u32, + crate::Item::Cactus => 64u32, + crate::Item::CactusGreen => 64u32, + crate::Item::Cake => 1u32, + crate::Item::Carrot => 64u32, + crate::Item::CarrotOnAStick => 64u32, + crate::Item::CarvedPumpkin => 64u32, + crate::Item::Cauldron => 64u32, + crate::Item::CaveSpiderSpawnEgg => 64u32, + crate::Item::ChainCommandBlock => 64u32, + crate::Item::ChainmailBoots => 1u32, + crate::Item::ChainmailChestplate => 1u32, + crate::Item::ChainmailHelmet => 1u32, + crate::Item::ChainmailLeggings => 1u32, + crate::Item::Charcoal => 64u32, + crate::Item::Chest => 64u32, + crate::Item::ChestMinecart => 1u32, + crate::Item::Chicken => 64u32, + crate::Item::ChickenSpawnEgg => 64u32, + crate::Item::ChippedAnvil => 64u32, + crate::Item::ChiseledQuartzBlock => 64u32, + crate::Item::ChiseledRedSandstone => 64u32, + crate::Item::ChiseledSandstone => 64u32, + crate::Item::ChiseledStoneBricks => 64u32, + crate::Item::ChorusFlower => 64u32, + crate::Item::ChorusFruit => 64u32, + crate::Item::ChorusPlant => 64u32, + crate::Item::Clay => 64u32, + crate::Item::ClayBall => 64u32, + crate::Item::Clock => 64u32, + crate::Item::Coal => 64u32, + crate::Item::CoalBlock => 64u32, + crate::Item::CoalOre => 64u32, + crate::Item::CoarseDirt => 64u32, + crate::Item::Cobblestone => 64u32, + crate::Item::CobblestoneSlab => 64u32, + crate::Item::CobblestoneStairs => 64u32, + crate::Item::CobblestoneWall => 64u32, + crate::Item::Cobweb => 64u32, + crate::Item::CocoaBeans => 64u32, + crate::Item::Cod => 64u32, + crate::Item::CodBucket => 1u32, + crate::Item::CodSpawnEgg => 64u32, + crate::Item::CommandBlock => 64u32, + crate::Item::CommandBlockMinecart => 1u32, + crate::Item::Comparator => 64u32, + crate::Item::Compass => 64u32, + crate::Item::Conduit => 64u32, + crate::Item::CookedBeef => 64u32, + crate::Item::CookedChicken => 64u32, + crate::Item::CookedCod => 64u32, + crate::Item::CookedMutton => 64u32, + crate::Item::CookedPorkchop => 64u32, + crate::Item::CookedRabbit => 64u32, + crate::Item::CookedSalmon => 64u32, + crate::Item::Cookie => 64u32, + crate::Item::CowSpawnEgg => 64u32, + crate::Item::CrackedStoneBricks => 64u32, + crate::Item::CraftingTable => 64u32, + crate::Item::CreeperHead => 64u32, + crate::Item::CreeperSpawnEgg => 64u32, + crate::Item::CutRedSandstone => 64u32, + crate::Item::CutSandstone => 64u32, + crate::Item::CyanBanner => 16u32, + crate::Item::CyanBed => 1u32, + crate::Item::CyanCarpet => 64u32, + crate::Item::CyanConcrete => 64u32, + crate::Item::CyanConcretePowder => 64u32, + crate::Item::CyanDye => 64u32, + crate::Item::CyanGlazedTerracotta => 64u32, + crate::Item::CyanShulkerBox => 1u32, + crate::Item::CyanStainedGlass => 64u32, + crate::Item::CyanStainedGlassPane => 64u32, + crate::Item::CyanTerracotta => 64u32, + crate::Item::CyanWool => 64u32, + crate::Item::DamagedAnvil => 64u32, + crate::Item::Dandelion => 64u32, + crate::Item::DandelionYellow => 64u32, + crate::Item::DarkOakBoat => 1u32, + crate::Item::DarkOakButton => 64u32, + crate::Item::DarkOakDoor => 64u32, + crate::Item::DarkOakFence => 64u32, + crate::Item::DarkOakFenceGate => 64u32, + crate::Item::DarkOakLeaves => 64u32, + crate::Item::DarkOakLog => 64u32, + crate::Item::DarkOakPlanks => 64u32, + crate::Item::DarkOakPressurePlate => 64u32, + crate::Item::DarkOakSapling => 64u32, + crate::Item::DarkOakSlab => 64u32, + crate::Item::DarkOakStairs => 64u32, + crate::Item::DarkOakTrapdoor => 64u32, + crate::Item::DarkOakWood => 64u32, + crate::Item::DarkPrismarine => 64u32, + crate::Item::DarkPrismarineSlab => 64u32, + crate::Item::DarkPrismarineStairs => 64u32, + crate::Item::DaylightDetector => 64u32, + crate::Item::DeadBrainCoral => 64u32, + crate::Item::DeadBrainCoralBlock => 64u32, + crate::Item::DeadBrainCoralFan => 64u32, + crate::Item::DeadBubbleCoral => 64u32, + crate::Item::DeadBubbleCoralBlock => 64u32, + crate::Item::DeadBubbleCoralFan => 64u32, + crate::Item::DeadBush => 64u32, + crate::Item::DeadFireCoral => 64u32, + crate::Item::DeadFireCoralBlock => 64u32, + crate::Item::DeadFireCoralFan => 64u32, + crate::Item::DeadHornCoral => 64u32, + crate::Item::DeadHornCoralBlock => 64u32, + crate::Item::DeadHornCoralFan => 64u32, + crate::Item::DeadTubeCoral => 64u32, + crate::Item::DeadTubeCoralBlock => 64u32, + crate::Item::DeadTubeCoralFan => 64u32, + crate::Item::DebugStick => 1u32, + crate::Item::DetectorRail => 64u32, + crate::Item::Diamond => 64u32, + crate::Item::DiamondAxe => 64u32, + crate::Item::DiamondBlock => 64u32, + crate::Item::DiamondBoots => 1u32, + crate::Item::DiamondChestplate => 1u32, + crate::Item::DiamondHelmet => 1u32, + crate::Item::DiamondHoe => 64u32, + crate::Item::DiamondHorseArmor => 1u32, + crate::Item::DiamondLeggings => 1u32, + crate::Item::DiamondOre => 64u32, + crate::Item::DiamondPickaxe => 64u32, + crate::Item::DiamondShovel => 64u32, + crate::Item::DiamondSword => 64u32, + crate::Item::Diorite => 64u32, + crate::Item::Dirt => 64u32, + crate::Item::Dispenser => 64u32, + crate::Item::DolphinSpawnEgg => 64u32, + crate::Item::DonkeySpawnEgg => 64u32, + crate::Item::DragonBreath => 64u32, + crate::Item::DragonEgg => 64u32, + crate::Item::DragonHead => 64u32, + crate::Item::DriedKelp => 64u32, + crate::Item::DriedKelpBlock => 64u32, + crate::Item::Dropper => 64u32, + crate::Item::DrownedSpawnEgg => 64u32, + crate::Item::Egg => 16u32, + crate::Item::ElderGuardianSpawnEgg => 64u32, + crate::Item::Elytra => 64u32, + crate::Item::Emerald => 64u32, + crate::Item::EmeraldBlock => 64u32, + crate::Item::EmeraldOre => 64u32, + crate::Item::EnchantedBook => 1u32, + crate::Item::EnchantedGoldenApple => 64u32, + crate::Item::EnchantingTable => 64u32, + crate::Item::EndCrystal => 64u32, + crate::Item::EndPortalFrame => 64u32, + crate::Item::EndRod => 64u32, + crate::Item::EndStone => 64u32, + crate::Item::EndStoneBricks => 64u32, + crate::Item::EnderChest => 64u32, + crate::Item::EnderEye => 64u32, + crate::Item::EnderPearl => 16u32, + crate::Item::EndermanSpawnEgg => 64u32, + crate::Item::EndermiteSpawnEgg => 64u32, + crate::Item::EvokerSpawnEgg => 64u32, + crate::Item::ExperienceBottle => 64u32, + crate::Item::Farmland => 64u32, + crate::Item::Feather => 64u32, + crate::Item::FermentedSpiderEye => 64u32, + crate::Item::Fern => 64u32, + crate::Item::FilledMap => 64u32, + crate::Item::FireCharge => 64u32, + crate::Item::FireCoral => 64u32, + crate::Item::FireCoralBlock => 64u32, + crate::Item::FireCoralFan => 64u32, + crate::Item::FireworkRocket => 64u32, + crate::Item::FireworkStar => 64u32, + crate::Item::FishingRod => 64u32, + crate::Item::Flint => 64u32, + crate::Item::FlintAndSteel => 64u32, + crate::Item::FlowerPot => 64u32, + crate::Item::Furnace => 64u32, + crate::Item::FurnaceMinecart => 1u32, + crate::Item::GhastSpawnEgg => 64u32, + crate::Item::GhastTear => 64u32, + crate::Item::Glass => 64u32, + crate::Item::GlassBottle => 64u32, + crate::Item::GlassPane => 64u32, + crate::Item::GlisteringMelonSlice => 64u32, + crate::Item::Glowstone => 64u32, + crate::Item::GlowstoneDust => 64u32, + crate::Item::GoldBlock => 64u32, + crate::Item::GoldIngot => 64u32, + crate::Item::GoldNugget => 64u32, + crate::Item::GoldOre => 64u32, + crate::Item::GoldenApple => 64u32, + crate::Item::GoldenAxe => 64u32, + crate::Item::GoldenBoots => 1u32, + crate::Item::GoldenCarrot => 64u32, + crate::Item::GoldenChestplate => 1u32, + crate::Item::GoldenHelmet => 1u32, + crate::Item::GoldenHoe => 64u32, + crate::Item::GoldenHorseArmor => 1u32, + crate::Item::GoldenLeggings => 1u32, + crate::Item::GoldenPickaxe => 64u32, + crate::Item::GoldenShovel => 64u32, + crate::Item::GoldenSword => 64u32, + crate::Item::Granite => 64u32, + crate::Item::Grass => 64u32, + crate::Item::GrassBlock => 64u32, + crate::Item::GrassPath => 64u32, + crate::Item::Gravel => 64u32, + crate::Item::GrayBanner => 16u32, + crate::Item::GrayBed => 1u32, + crate::Item::GrayCarpet => 64u32, + crate::Item::GrayConcrete => 64u32, + crate::Item::GrayConcretePowder => 64u32, + crate::Item::GrayDye => 64u32, + crate::Item::GrayGlazedTerracotta => 64u32, + crate::Item::GrayShulkerBox => 1u32, + crate::Item::GrayStainedGlass => 64u32, + crate::Item::GrayStainedGlassPane => 64u32, + crate::Item::GrayTerracotta => 64u32, + crate::Item::GrayWool => 64u32, + crate::Item::GreenBanner => 16u32, + crate::Item::GreenBed => 1u32, + crate::Item::GreenCarpet => 64u32, + crate::Item::GreenConcrete => 64u32, + crate::Item::GreenConcretePowder => 64u32, + crate::Item::GreenGlazedTerracotta => 64u32, + crate::Item::GreenShulkerBox => 1u32, + crate::Item::GreenStainedGlass => 64u32, + crate::Item::GreenStainedGlassPane => 64u32, + crate::Item::GreenTerracotta => 64u32, + crate::Item::GreenWool => 64u32, + crate::Item::GuardianSpawnEgg => 64u32, + crate::Item::Gunpowder => 64u32, + crate::Item::HayBlock => 64u32, + crate::Item::HeartOfTheSea => 64u32, + crate::Item::HeavyWeightedPressurePlate => 64u32, + crate::Item::Hopper => 64u32, + crate::Item::HopperMinecart => 1u32, + crate::Item::HornCoral => 64u32, + crate::Item::HornCoralBlock => 64u32, + crate::Item::HornCoralFan => 64u32, + crate::Item::HorseSpawnEgg => 64u32, + crate::Item::HuskSpawnEgg => 64u32, + crate::Item::Ice => 64u32, + crate::Item::InfestedChiseledStoneBricks => 64u32, + crate::Item::InfestedCobblestone => 64u32, + crate::Item::InfestedCrackedStoneBricks => 64u32, + crate::Item::InfestedMossyStoneBricks => 64u32, + crate::Item::InfestedStone => 64u32, + crate::Item::InfestedStoneBricks => 64u32, + crate::Item::InkSac => 64u32, + crate::Item::IronAxe => 64u32, + crate::Item::IronBars => 64u32, + crate::Item::IronBlock => 64u32, + crate::Item::IronBoots => 1u32, + crate::Item::IronChestplate => 1u32, + crate::Item::IronDoor => 64u32, + crate::Item::IronHelmet => 1u32, + crate::Item::IronHoe => 64u32, + crate::Item::IronHorseArmor => 1u32, + crate::Item::IronIngot => 64u32, + crate::Item::IronLeggings => 1u32, + crate::Item::IronNugget => 64u32, + crate::Item::IronOre => 64u32, + crate::Item::IronPickaxe => 64u32, + crate::Item::IronShovel => 64u32, + crate::Item::IronSword => 64u32, + crate::Item::IronTrapdoor => 64u32, + crate::Item::ItemFrame => 64u32, + crate::Item::JackOLantern => 64u32, + crate::Item::Jukebox => 64u32, + crate::Item::JungleBoat => 1u32, + crate::Item::JungleButton => 64u32, + crate::Item::JungleDoor => 64u32, + crate::Item::JungleFence => 64u32, + crate::Item::JungleFenceGate => 64u32, + crate::Item::JungleLeaves => 64u32, + crate::Item::JungleLog => 64u32, + crate::Item::JunglePlanks => 64u32, + crate::Item::JunglePressurePlate => 64u32, + crate::Item::JungleSapling => 64u32, + crate::Item::JungleSlab => 64u32, + crate::Item::JungleStairs => 64u32, + crate::Item::JungleTrapdoor => 64u32, + crate::Item::JungleWood => 64u32, + crate::Item::Kelp => 64u32, + crate::Item::KnowledgeBook => 1u32, + crate::Item::Ladder => 64u32, + crate::Item::LapisBlock => 64u32, + crate::Item::LapisLazuli => 64u32, + crate::Item::LapisOre => 64u32, + crate::Item::LargeFern => 64u32, + crate::Item::LavaBucket => 1u32, + crate::Item::Lead => 64u32, + crate::Item::Leather => 64u32, + crate::Item::LeatherBoots => 1u32, + crate::Item::LeatherChestplate => 1u32, + crate::Item::LeatherHelmet => 1u32, + crate::Item::LeatherLeggings => 1u32, + crate::Item::Lever => 64u32, + crate::Item::LightBlueBanner => 16u32, + crate::Item::LightBlueBed => 1u32, + crate::Item::LightBlueCarpet => 64u32, + crate::Item::LightBlueConcrete => 64u32, + crate::Item::LightBlueConcretePowder => 64u32, + crate::Item::LightBlueDye => 64u32, + crate::Item::LightBlueGlazedTerracotta => 64u32, + crate::Item::LightBlueShulkerBox => 1u32, + crate::Item::LightBlueStainedGlass => 64u32, + crate::Item::LightBlueStainedGlassPane => 64u32, + crate::Item::LightBlueTerracotta => 64u32, + crate::Item::LightBlueWool => 64u32, + crate::Item::LightGrayBanner => 16u32, + crate::Item::LightGrayBed => 1u32, + crate::Item::LightGrayCarpet => 64u32, + crate::Item::LightGrayConcrete => 64u32, + crate::Item::LightGrayConcretePowder => 64u32, + crate::Item::LightGrayDye => 64u32, + crate::Item::LightGrayGlazedTerracotta => 64u32, + crate::Item::LightGrayShulkerBox => 1u32, + crate::Item::LightGrayStainedGlass => 64u32, + crate::Item::LightGrayStainedGlassPane => 64u32, + crate::Item::LightGrayTerracotta => 64u32, + crate::Item::LightGrayWool => 64u32, + crate::Item::LightWeightedPressurePlate => 64u32, + crate::Item::Lilac => 64u32, + crate::Item::LilyPad => 64u32, + crate::Item::LimeBanner => 16u32, + crate::Item::LimeBed => 1u32, + crate::Item::LimeCarpet => 64u32, + crate::Item::LimeConcrete => 64u32, + crate::Item::LimeConcretePowder => 64u32, + crate::Item::LimeDye => 64u32, + crate::Item::LimeGlazedTerracotta => 64u32, + crate::Item::LimeShulkerBox => 1u32, + crate::Item::LimeStainedGlass => 64u32, + crate::Item::LimeStainedGlassPane => 64u32, + crate::Item::LimeTerracotta => 64u32, + crate::Item::LimeWool => 64u32, + crate::Item::LingeringPotion => 1u32, + crate::Item::LlamaSpawnEgg => 64u32, + crate::Item::MagentaBanner => 16u32, + crate::Item::MagentaBed => 1u32, + crate::Item::MagentaCarpet => 64u32, + crate::Item::MagentaConcrete => 64u32, + crate::Item::MagentaConcretePowder => 64u32, + crate::Item::MagentaDye => 64u32, + crate::Item::MagentaGlazedTerracotta => 64u32, + crate::Item::MagentaShulkerBox => 1u32, + crate::Item::MagentaStainedGlass => 64u32, + crate::Item::MagentaStainedGlassPane => 64u32, + crate::Item::MagentaTerracotta => 64u32, + crate::Item::MagentaWool => 64u32, + crate::Item::MagmaBlock => 64u32, + crate::Item::MagmaCream => 64u32, + crate::Item::MagmaCubeSpawnEgg => 64u32, + crate::Item::Map => 64u32, + crate::Item::Melon => 64u32, + crate::Item::MelonSeeds => 64u32, + crate::Item::MelonSlice => 64u32, + crate::Item::MilkBucket => 1u32, + crate::Item::Minecart => 1u32, + crate::Item::MooshroomSpawnEgg => 64u32, + crate::Item::MossyCobblestone => 64u32, + crate::Item::MossyCobblestoneWall => 64u32, + crate::Item::MossyStoneBricks => 64u32, + crate::Item::MuleSpawnEgg => 64u32, + crate::Item::MushroomStem => 64u32, + crate::Item::MushroomStew => 1u32, + crate::Item::MusicDisc11 => 1u32, + crate::Item::MusicDisc13 => 1u32, + crate::Item::MusicDiscBlocks => 1u32, + crate::Item::MusicDiscCat => 1u32, + crate::Item::MusicDiscChirp => 1u32, + crate::Item::MusicDiscFar => 1u32, + crate::Item::MusicDiscMall => 1u32, + crate::Item::MusicDiscMellohi => 1u32, + crate::Item::MusicDiscStal => 1u32, + crate::Item::MusicDiscStrad => 1u32, + crate::Item::MusicDiscWait => 1u32, + crate::Item::MusicDiscWard => 1u32, + crate::Item::Mutton => 64u32, + crate::Item::Mycelium => 64u32, + crate::Item::NameTag => 64u32, + crate::Item::NautilusShell => 64u32, + crate::Item::NetherBrick => 64u32, + crate::Item::NetherBrickFence => 64u32, + crate::Item::NetherBrickSlab => 64u32, + crate::Item::NetherBrickStairs => 64u32, + crate::Item::NetherBricks => 64u32, + crate::Item::NetherQuartzOre => 64u32, + crate::Item::NetherStar => 64u32, + crate::Item::NetherWart => 64u32, + crate::Item::NetherWartBlock => 64u32, + crate::Item::Netherrack => 64u32, + crate::Item::NoteBlock => 64u32, + crate::Item::OakBoat => 1u32, + crate::Item::OakButton => 64u32, + crate::Item::OakDoor => 64u32, + crate::Item::OakFence => 64u32, + crate::Item::OakFenceGate => 64u32, + crate::Item::OakLeaves => 64u32, + crate::Item::OakLog => 64u32, + crate::Item::OakPlanks => 64u32, + crate::Item::OakPressurePlate => 64u32, + crate::Item::OakSapling => 64u32, + crate::Item::OakSlab => 64u32, + crate::Item::OakStairs => 64u32, + crate::Item::OakTrapdoor => 64u32, + crate::Item::OakWood => 64u32, + crate::Item::Observer => 64u32, + crate::Item::Obsidian => 64u32, + crate::Item::OcelotSpawnEgg => 64u32, + crate::Item::OrangeBanner => 16u32, + crate::Item::OrangeBed => 1u32, + crate::Item::OrangeCarpet => 64u32, + crate::Item::OrangeConcrete => 64u32, + crate::Item::OrangeConcretePowder => 64u32, + crate::Item::OrangeDye => 64u32, + crate::Item::OrangeGlazedTerracotta => 64u32, + crate::Item::OrangeShulkerBox => 1u32, + crate::Item::OrangeStainedGlass => 64u32, + crate::Item::OrangeStainedGlassPane => 64u32, + crate::Item::OrangeTerracotta => 64u32, + crate::Item::OrangeTulip => 64u32, + crate::Item::OrangeWool => 64u32, + crate::Item::OxeyeDaisy => 64u32, + crate::Item::PackedIce => 64u32, + crate::Item::Painting => 64u32, + crate::Item::Paper => 64u32, + crate::Item::ParrotSpawnEgg => 64u32, + crate::Item::Peony => 64u32, + crate::Item::PetrifiedOakSlab => 64u32, + crate::Item::PhantomMembrane => 64u32, + crate::Item::PhantomSpawnEgg => 64u32, + crate::Item::PigSpawnEgg => 64u32, + crate::Item::PinkBanner => 16u32, + crate::Item::PinkBed => 1u32, + crate::Item::PinkCarpet => 64u32, + crate::Item::PinkConcrete => 64u32, + crate::Item::PinkConcretePowder => 64u32, + crate::Item::PinkDye => 64u32, + crate::Item::PinkGlazedTerracotta => 64u32, + crate::Item::PinkShulkerBox => 1u32, + crate::Item::PinkStainedGlass => 64u32, + crate::Item::PinkStainedGlassPane => 64u32, + crate::Item::PinkTerracotta => 64u32, + crate::Item::PinkTulip => 64u32, + crate::Item::PinkWool => 64u32, + crate::Item::Piston => 64u32, + crate::Item::PlayerHead => 64u32, + crate::Item::Podzol => 64u32, + crate::Item::PoisonousPotato => 64u32, + crate::Item::PolarBearSpawnEgg => 64u32, + crate::Item::PolishedAndesite => 64u32, + crate::Item::PolishedDiorite => 64u32, + crate::Item::PolishedGranite => 64u32, + crate::Item::PoppedChorusFruit => 64u32, + crate::Item::Poppy => 64u32, + crate::Item::Porkchop => 64u32, + crate::Item::Potato => 64u32, + crate::Item::Potion => 1u32, + crate::Item::PoweredRail => 64u32, + crate::Item::Prismarine => 64u32, + crate::Item::PrismarineBrickSlab => 64u32, + crate::Item::PrismarineBrickStairs => 64u32, + crate::Item::PrismarineBricks => 64u32, + crate::Item::PrismarineCrystals => 64u32, + crate::Item::PrismarineShard => 64u32, + crate::Item::PrismarineSlab => 64u32, + crate::Item::PrismarineStairs => 64u32, + crate::Item::Pufferfish => 64u32, + crate::Item::PufferfishBucket => 1u32, + crate::Item::PufferfishSpawnEgg => 64u32, + crate::Item::Pumpkin => 64u32, + crate::Item::PumpkinPie => 64u32, + crate::Item::PumpkinSeeds => 64u32, + crate::Item::PurpleBanner => 16u32, + crate::Item::PurpleBed => 1u32, + crate::Item::PurpleCarpet => 64u32, + crate::Item::PurpleConcrete => 64u32, + crate::Item::PurpleConcretePowder => 64u32, + crate::Item::PurpleDye => 64u32, + crate::Item::PurpleGlazedTerracotta => 64u32, + crate::Item::PurpleShulkerBox => 1u32, + crate::Item::PurpleStainedGlass => 64u32, + crate::Item::PurpleStainedGlassPane => 64u32, + crate::Item::PurpleTerracotta => 64u32, + crate::Item::PurpleWool => 64u32, + crate::Item::PurpurBlock => 64u32, + crate::Item::PurpurPillar => 64u32, + crate::Item::PurpurSlab => 64u32, + crate::Item::PurpurStairs => 64u32, + crate::Item::Quartz => 64u32, + crate::Item::QuartzBlock => 64u32, + crate::Item::QuartzPillar => 64u32, + crate::Item::QuartzSlab => 64u32, + crate::Item::QuartzStairs => 64u32, + crate::Item::Rabbit => 64u32, + crate::Item::RabbitFoot => 64u32, + crate::Item::RabbitHide => 64u32, + crate::Item::RabbitSpawnEgg => 64u32, + crate::Item::RabbitStew => 1u32, + crate::Item::Rail => 64u32, + crate::Item::RedBanner => 16u32, + crate::Item::RedBed => 1u32, + crate::Item::RedCarpet => 64u32, + crate::Item::RedConcrete => 64u32, + crate::Item::RedConcretePowder => 64u32, + crate::Item::RedGlazedTerracotta => 64u32, + crate::Item::RedMushroom => 64u32, + crate::Item::RedMushroomBlock => 64u32, + crate::Item::RedNetherBricks => 64u32, + crate::Item::RedSand => 64u32, + crate::Item::RedSandstone => 64u32, + crate::Item::RedSandstoneSlab => 64u32, + crate::Item::RedSandstoneStairs => 64u32, + crate::Item::RedShulkerBox => 1u32, + crate::Item::RedStainedGlass => 64u32, + crate::Item::RedStainedGlassPane => 64u32, + crate::Item::RedTerracotta => 64u32, + crate::Item::RedTulip => 64u32, + crate::Item::RedWool => 64u32, + crate::Item::Redstone => 64u32, + crate::Item::RedstoneBlock => 64u32, + crate::Item::RedstoneLamp => 64u32, + crate::Item::RedstoneOre => 64u32, + crate::Item::RedstoneTorch => 64u32, + crate::Item::Repeater => 64u32, + crate::Item::RepeatingCommandBlock => 64u32, + crate::Item::RoseBush => 64u32, + crate::Item::RoseRed => 64u32, + crate::Item::RottenFlesh => 64u32, + crate::Item::Saddle => 1u32, + crate::Item::Salmon => 64u32, + crate::Item::SalmonBucket => 1u32, + crate::Item::SalmonSpawnEgg => 64u32, + crate::Item::Sand => 64u32, + crate::Item::Sandstone => 64u32, + crate::Item::SandstoneSlab => 64u32, + crate::Item::SandstoneStairs => 64u32, + crate::Item::Scute => 64u32, + crate::Item::SeaLantern => 64u32, + crate::Item::SeaPickle => 64u32, + crate::Item::Seagrass => 64u32, + crate::Item::Shears => 64u32, + crate::Item::SheepSpawnEgg => 64u32, + crate::Item::Shield => 64u32, + crate::Item::ShulkerBox => 1u32, + crate::Item::ShulkerShell => 64u32, + crate::Item::ShulkerSpawnEgg => 64u32, + crate::Item::Sign => 16u32, + crate::Item::SilverfishSpawnEgg => 64u32, + crate::Item::SkeletonHorseSpawnEgg => 64u32, + crate::Item::SkeletonSkull => 64u32, + crate::Item::SkeletonSpawnEgg => 64u32, + crate::Item::SlimeBall => 64u32, + crate::Item::SlimeBlock => 64u32, + crate::Item::SlimeSpawnEgg => 64u32, + crate::Item::SmoothQuartz => 64u32, + crate::Item::SmoothRedSandstone => 64u32, + crate::Item::SmoothSandstone => 64u32, + crate::Item::SmoothStone => 64u32, + crate::Item::Snow => 64u32, + crate::Item::SnowBlock => 64u32, + crate::Item::Snowball => 16u32, + crate::Item::SoulSand => 64u32, + crate::Item::Spawner => 64u32, + crate::Item::SpectralArrow => 64u32, + crate::Item::SpiderEye => 64u32, + crate::Item::SpiderSpawnEgg => 64u32, + crate::Item::SplashPotion => 1u32, + crate::Item::Sponge => 64u32, + crate::Item::SpruceBoat => 1u32, + crate::Item::SpruceButton => 64u32, + crate::Item::SpruceDoor => 64u32, + crate::Item::SpruceFence => 64u32, + crate::Item::SpruceFenceGate => 64u32, + crate::Item::SpruceLeaves => 64u32, + crate::Item::SpruceLog => 64u32, + crate::Item::SprucePlanks => 64u32, + crate::Item::SprucePressurePlate => 64u32, + crate::Item::SpruceSapling => 64u32, + crate::Item::SpruceSlab => 64u32, + crate::Item::SpruceStairs => 64u32, + crate::Item::SpruceTrapdoor => 64u32, + crate::Item::SpruceWood => 64u32, + crate::Item::SquidSpawnEgg => 64u32, + crate::Item::Stick => 64u32, + crate::Item::StickyPiston => 64u32, + crate::Item::Stone => 64u32, + crate::Item::StoneAxe => 64u32, + crate::Item::StoneBrickSlab => 64u32, + crate::Item::StoneBrickStairs => 64u32, + crate::Item::StoneBricks => 64u32, + crate::Item::StoneButton => 64u32, + crate::Item::StoneHoe => 64u32, + crate::Item::StonePickaxe => 64u32, + crate::Item::StonePressurePlate => 64u32, + crate::Item::StoneShovel => 64u32, + crate::Item::StoneSlab => 64u32, + crate::Item::StoneSword => 64u32, + crate::Item::StraySpawnEgg => 64u32, + crate::Item::String => 64u32, + crate::Item::StrippedAcaciaLog => 64u32, + crate::Item::StrippedAcaciaWood => 64u32, + crate::Item::StrippedBirchLog => 64u32, + crate::Item::StrippedBirchWood => 64u32, + crate::Item::StrippedDarkOakLog => 64u32, + crate::Item::StrippedDarkOakWood => 64u32, + crate::Item::StrippedJungleLog => 64u32, + crate::Item::StrippedJungleWood => 64u32, + crate::Item::StrippedOakLog => 64u32, + crate::Item::StrippedOakWood => 64u32, + crate::Item::StrippedSpruceLog => 64u32, + crate::Item::StrippedSpruceWood => 64u32, + crate::Item::StructureBlock => 64u32, + crate::Item::StructureVoid => 64u32, + crate::Item::Sugar => 64u32, + crate::Item::SugarCane => 64u32, + crate::Item::Sunflower => 64u32, + crate::Item::TallGrass => 64u32, + crate::Item::Terracotta => 64u32, + crate::Item::TippedArrow => 64u32, + crate::Item::Tnt => 64u32, + crate::Item::TntMinecart => 1u32, + crate::Item::Torch => 64u32, + crate::Item::TotemOfUndying => 1u32, + crate::Item::TrappedChest => 64u32, + crate::Item::Trident => 1u32, + crate::Item::TripwireHook => 64u32, + crate::Item::TropicalFish => 64u32, + crate::Item::TropicalFishBucket => 1u32, + crate::Item::TropicalFishSpawnEgg => 64u32, + crate::Item::TubeCoral => 64u32, + crate::Item::TubeCoralBlock => 64u32, + crate::Item::TubeCoralFan => 64u32, + crate::Item::TurtleEgg => 64u32, + crate::Item::TurtleHelmet => 1u32, + crate::Item::TurtleSpawnEgg => 64u32, + crate::Item::VexSpawnEgg => 64u32, + crate::Item::VillagerSpawnEgg => 64u32, + crate::Item::VindicatorSpawnEgg => 64u32, + crate::Item::Vine => 64u32, + crate::Item::WaterBucket => 1u32, + crate::Item::WetSponge => 64u32, + crate::Item::Wheat => 64u32, + crate::Item::WheatSeeds => 64u32, + crate::Item::WhiteBanner => 16u32, + crate::Item::WhiteBed => 1u32, + crate::Item::WhiteCarpet => 64u32, + crate::Item::WhiteConcrete => 64u32, + crate::Item::WhiteConcretePowder => 64u32, + crate::Item::WhiteGlazedTerracotta => 64u32, + crate::Item::WhiteShulkerBox => 1u32, + crate::Item::WhiteStainedGlass => 64u32, + crate::Item::WhiteStainedGlassPane => 64u32, + crate::Item::WhiteTerracotta => 64u32, + crate::Item::WhiteTulip => 64u32, + crate::Item::WhiteWool => 64u32, + crate::Item::WitchSpawnEgg => 64u32, + crate::Item::WitherSkeletonSkull => 64u32, + crate::Item::WitherSkeletonSpawnEgg => 64u32, + crate::Item::WolfSpawnEgg => 64u32, + crate::Item::WoodenAxe => 64u32, + crate::Item::WoodenHoe => 64u32, + crate::Item::WoodenPickaxe => 64u32, + crate::Item::WoodenShovel => 64u32, + crate::Item::WoodenSword => 64u32, + crate::Item::WritableBook => 1u32, + crate::Item::WrittenBook => 16u32, + crate::Item::YellowBanner => 16u32, + crate::Item::YellowBed => 1u32, + crate::Item::YellowCarpet => 64u32, + crate::Item::YellowConcrete => 64u32, + crate::Item::YellowConcretePowder => 64u32, + crate::Item::YellowGlazedTerracotta => 64u32, + crate::Item::YellowShulkerBox => 1u32, + crate::Item::YellowStainedGlass => 64u32, + crate::Item::YellowStainedGlassPane => 64u32, + crate::Item::YellowTerracotta => 64u32, + crate::Item::YellowWool => 64u32, + crate::Item::ZombieHead => 64u32, + crate::Item::ZombieHorseSpawnEgg => 64u32, + crate::Item::ZombiePigmanSpawnEgg => 64u32, + crate::Item::ZombieSpawnEgg => 64u32, + crate::Item::ZombieVillagerSpawnEgg => 64u32, + } + } +} +impl crate::Item { + pub fn vanilla_id(self) -> u32 { + match self { + crate::Item::AcaciaBoat => 767u32, + crate::Item::AcaciaButton => 245u32, + crate::Item::AcaciaDoor => 465u32, + crate::Item::AcaciaFence => 179u32, + crate::Item::AcaciaFenceGate => 214u32, + crate::Item::AcaciaLeaves => 60u32, + crate::Item::AcaciaLog => 36u32, + crate::Item::AcaciaPlanks => 17u32, + crate::Item::AcaciaPressurePlate => 164u32, + crate::Item::AcaciaSapling => 23u32, + crate::Item::AcaciaSlab => 116u32, + crate::Item::AcaciaStairs => 301u32, + crate::Item::AcaciaTrapdoor => 191u32, + crate::Item::AcaciaWood => 54u32, + crate::Item::ActivatorRail => 261u32, + crate::Item::Air => 0u32, + crate::Item::Allium => 101u32, + crate::Item::Andesite => 6u32, + crate::Item::Anvil => 247u32, + crate::Item::Apple => 476u32, + crate::Item::ArmorStand => 726u32, + crate::Item::Arrow => 478u32, + crate::Item::AzureBluet => 102u32, + crate::Item::BakedPotato => 699u32, + crate::Item::Barrier => 279u32, + crate::Item::BatSpawnEgg => 639u32, + crate::Item::Beacon => 238u32, + crate::Item::Bedrock => 25u32, + crate::Item::Beef => 619u32, + crate::Item::Beetroot => 754u32, + crate::Item::BeetrootSeeds => 755u32, + crate::Item::BeetrootSoup => 756u32, + crate::Item::BirchBoat => 765u32, + crate::Item::BirchButton => 243u32, + crate::Item::BirchDoor => 463u32, + crate::Item::BirchFence => 177u32, + crate::Item::BirchFenceGate => 212u32, + crate::Item::BirchLeaves => 58u32, + crate::Item::BirchLog => 34u32, + crate::Item::BirchPlanks => 15u32, + crate::Item::BirchPressurePlate => 162u32, + crate::Item::BirchSapling => 21u32, + crate::Item::BirchSlab => 114u32, + crate::Item::BirchStairs => 235u32, + crate::Item::BirchTrapdoor => 189u32, + crate::Item::BirchWood => 52u32, + crate::Item::BlackBanner => 750u32, + crate::Item::BlackBed => 611u32, + crate::Item::BlackCarpet => 297u32, + crate::Item::BlackConcrete => 410u32, + crate::Item::BlackConcretePowder => 426u32, + crate::Item::BlackGlazedTerracotta => 394u32, + crate::Item::BlackShulkerBox => 378u32, + crate::Item::BlackStainedGlass => 326u32, + crate::Item::BlackStainedGlassPane => 342u32, + crate::Item::BlackTerracotta => 278u32, + crate::Item::BlackWool => 97u32, + crate::Item::BlazePowder => 633u32, + crate::Item::BlazeRod => 625u32, + crate::Item::BlazeSpawnEgg => 640u32, + crate::Item::BlueBanner => 746u32, + crate::Item::BlueBed => 607u32, + crate::Item::BlueCarpet => 293u32, + crate::Item::BlueConcrete => 406u32, + crate::Item::BlueConcretePowder => 422u32, + crate::Item::BlueGlazedTerracotta => 390u32, + crate::Item::BlueIce => 458u32, + crate::Item::BlueOrchid => 100u32, + crate::Item::BlueShulkerBox => 374u32, + crate::Item::BlueStainedGlass => 322u32, + crate::Item::BlueStainedGlassPane => 338u32, + crate::Item::BlueTerracotta => 274u32, + crate::Item::BlueWool => 93u32, + crate::Item::Bone => 593u32, + crate::Item::BoneBlock => 359u32, + crate::Item::BoneMeal => 592u32, + crate::Item::Book => 562u32, + crate::Item::Bookshelf => 137u32, + crate::Item::Bow => 477u32, + crate::Item::Bowl => 498u32, + crate::Item::BrainCoral => 439u32, + crate::Item::BrainCoralBlock => 434u32, + crate::Item::BrainCoralFan => 449u32, + crate::Item::Bread => 514u32, + crate::Item::BrewingStand => 635u32, + crate::Item::Brick => 556u32, + crate::Item::BrickSlab => 122u32, + crate::Item::BrickStairs => 216u32, + crate::Item::Bricks => 135u32, + crate::Item::BrownBanner => 747u32, + crate::Item::BrownBed => 608u32, + crate::Item::BrownCarpet => 294u32, + crate::Item::BrownConcrete => 407u32, + crate::Item::BrownConcretePowder => 423u32, + crate::Item::BrownGlazedTerracotta => 391u32, + crate::Item::BrownMushroom => 108u32, + crate::Item::BrownMushroomBlock => 203u32, + crate::Item::BrownShulkerBox => 375u32, + crate::Item::BrownStainedGlass => 323u32, + crate::Item::BrownStainedGlassPane => 339u32, + crate::Item::BrownTerracotta => 275u32, + crate::Item::BrownWool => 94u32, + crate::Item::BubbleCoral => 440u32, + crate::Item::BubbleCoralBlock => 435u32, + crate::Item::BubbleCoralFan => 450u32, + crate::Item::Bucket => 542u32, + crate::Item::Cactus => 172u32, + crate::Item::CactusGreen => 579u32, + crate::Item::Cake => 595u32, + crate::Item::Carrot => 697u32, + crate::Item::CarrotOnAStick => 709u32, + crate::Item::CarvedPumpkin => 182u32, + crate::Item::Cauldron => 636u32, + crate::Item::CaveSpiderSpawnEgg => 641u32, + crate::Item::ChainCommandBlock => 355u32, + crate::Item::ChainmailBoots => 522u32, + crate::Item::ChainmailChestplate => 520u32, + crate::Item::ChainmailHelmet => 519u32, + crate::Item::ChainmailLeggings => 521u32, + crate::Item::Charcoal => 480u32, + crate::Item::Chest => 149u32, + crate::Item::ChestMinecart => 564u32, + crate::Item::Chicken => 621u32, + crate::Item::ChickenSpawnEgg => 642u32, + crate::Item::ChippedAnvil => 248u32, + crate::Item::ChiseledQuartzBlock => 257u32, + crate::Item::ChiseledRedSandstone => 351u32, + crate::Item::ChiseledSandstone => 69u32, + crate::Item::ChiseledStoneBricks => 202u32, + crate::Item::ChorusFlower => 143u32, + crate::Item::ChorusFruit => 752u32, + crate::Item::ChorusPlant => 142u32, + crate::Item::Clay => 173u32, + crate::Item::ClayBall => 557u32, + crate::Item::Clock => 569u32, + crate::Item::Coal => 479u32, + crate::Item::CoalBlock => 299u32, + crate::Item::CoalOre => 31u32, + crate::Item::CoarseDirt => 10u32, + crate::Item::Cobblestone => 12u32, + crate::Item::CobblestoneSlab => 121u32, + crate::Item::CobblestoneStairs => 157u32, + crate::Item::CobblestoneWall => 239u32, + crate::Item::Cobweb => 75u32, + crate::Item::CocoaBeans => 580u32, + crate::Item::Cod => 571u32, + crate::Item::CodBucket => 554u32, + crate::Item::CodSpawnEgg => 643u32, + crate::Item::CommandBlock => 237u32, + crate::Item::CommandBlockMinecart => 732u32, + crate::Item::Comparator => 468u32, + crate::Item::Compass => 567u32, + crate::Item::Conduit => 459u32, + crate::Item::CookedBeef => 620u32, + crate::Item::CookedChicken => 622u32, + crate::Item::CookedCod => 575u32, + crate::Item::CookedMutton => 734u32, + crate::Item::CookedPorkchop => 537u32, + crate::Item::CookedRabbit => 722u32, + crate::Item::CookedSalmon => 576u32, + crate::Item::Cookie => 612u32, + crate::Item::CowSpawnEgg => 644u32, + crate::Item::CrackedStoneBricks => 201u32, + crate::Item::CraftingTable => 152u32, + crate::Item::CreeperHead => 707u32, + crate::Item::CreeperSpawnEgg => 645u32, + crate::Item::CutRedSandstone => 352u32, + crate::Item::CutSandstone => 70u32, + crate::Item::CyanBanner => 744u32, + crate::Item::CyanBed => 605u32, + crate::Item::CyanCarpet => 291u32, + crate::Item::CyanConcrete => 404u32, + crate::Item::CyanConcretePowder => 420u32, + crate::Item::CyanDye => 583u32, + crate::Item::CyanGlazedTerracotta => 388u32, + crate::Item::CyanShulkerBox => 372u32, + crate::Item::CyanStainedGlass => 320u32, + crate::Item::CyanStainedGlassPane => 336u32, + crate::Item::CyanTerracotta => 272u32, + crate::Item::CyanWool => 91u32, + crate::Item::DamagedAnvil => 249u32, + crate::Item::Dandelion => 98u32, + crate::Item::DandelionYellow => 588u32, + crate::Item::DarkOakBoat => 768u32, + crate::Item::DarkOakButton => 246u32, + crate::Item::DarkOakDoor => 466u32, + crate::Item::DarkOakFence => 180u32, + crate::Item::DarkOakFenceGate => 215u32, + crate::Item::DarkOakLeaves => 61u32, + crate::Item::DarkOakLog => 37u32, + crate::Item::DarkOakPlanks => 18u32, + crate::Item::DarkOakPressurePlate => 165u32, + crate::Item::DarkOakSapling => 24u32, + crate::Item::DarkOakSlab => 117u32, + crate::Item::DarkOakStairs => 302u32, + crate::Item::DarkOakTrapdoor => 192u32, + crate::Item::DarkOakWood => 55u32, + crate::Item::DarkPrismarine => 345u32, + crate::Item::DarkPrismarineSlab => 130u32, + crate::Item::DarkPrismarineStairs => 348u32, + crate::Item::DaylightDetector => 253u32, + crate::Item::DeadBrainCoral => 443u32, + crate::Item::DeadBrainCoralBlock => 429u32, + crate::Item::DeadBrainCoralFan => 454u32, + crate::Item::DeadBubbleCoral => 444u32, + crate::Item::DeadBubbleCoralBlock => 430u32, + crate::Item::DeadBubbleCoralFan => 455u32, + crate::Item::DeadBush => 78u32, + crate::Item::DeadFireCoral => 445u32, + crate::Item::DeadFireCoralBlock => 431u32, + crate::Item::DeadFireCoralFan => 456u32, + crate::Item::DeadHornCoral => 446u32, + crate::Item::DeadHornCoralBlock => 432u32, + crate::Item::DeadHornCoralFan => 457u32, + crate::Item::DeadTubeCoral => 447u32, + crate::Item::DeadTubeCoralBlock => 428u32, + crate::Item::DeadTubeCoralFan => 453u32, + crate::Item::DebugStick => 773u32, + crate::Item::DetectorRail => 73u32, + crate::Item::Diamond => 481u32, + crate::Item::DiamondAxe => 496u32, + crate::Item::DiamondBlock => 151u32, + crate::Item::DiamondBoots => 530u32, + crate::Item::DiamondChestplate => 528u32, + crate::Item::DiamondHelmet => 527u32, + crate::Item::DiamondHoe => 510u32, + crate::Item::DiamondHorseArmor => 729u32, + crate::Item::DiamondLeggings => 529u32, + crate::Item::DiamondOre => 150u32, + crate::Item::DiamondPickaxe => 495u32, + crate::Item::DiamondShovel => 494u32, + crate::Item::DiamondSword => 493u32, + crate::Item::Diorite => 4u32, + crate::Item::Dirt => 9u32, + crate::Item::Dispenser => 67u32, + crate::Item::DolphinSpawnEgg => 646u32, + crate::Item::DonkeySpawnEgg => 647u32, + crate::Item::DragonBreath => 757u32, + crate::Item::DragonEgg => 227u32, + crate::Item::DragonHead => 708u32, + crate::Item::DriedKelp => 616u32, + crate::Item::DriedKelpBlock => 560u32, + crate::Item::Dropper => 262u32, + crate::Item::DrownedSpawnEgg => 648u32, + crate::Item::Egg => 566u32, + crate::Item::ElderGuardianSpawnEgg => 649u32, + crate::Item::Elytra => 763u32, + crate::Item::Emerald => 694u32, + crate::Item::EmeraldBlock => 233u32, + crate::Item::EmeraldOre => 230u32, + crate::Item::EnchantedBook => 714u32, + crate::Item::EnchantedGoldenApple => 540u32, + crate::Item::EnchantingTable => 223u32, + crate::Item::EndCrystal => 751u32, + crate::Item::EndPortalFrame => 224u32, + crate::Item::EndRod => 141u32, + crate::Item::EndStone => 225u32, + crate::Item::EndStoneBricks => 226u32, + crate::Item::EnderChest => 231u32, + crate::Item::EnderEye => 637u32, + crate::Item::EnderPearl => 624u32, + crate::Item::EndermanSpawnEgg => 650u32, + crate::Item::EndermiteSpawnEgg => 651u32, + crate::Item::EvokerSpawnEgg => 652u32, + crate::Item::ExperienceBottle => 690u32, + crate::Item::Farmland => 153u32, + crate::Item::Feather => 505u32, + crate::Item::FermentedSpiderEye => 632u32, + crate::Item::Fern => 77u32, + crate::Item::FilledMap => 613u32, + crate::Item::FireCharge => 691u32, + crate::Item::FireCoral => 441u32, + crate::Item::FireCoralBlock => 436u32, + crate::Item::FireCoralFan => 451u32, + crate::Item::FireworkRocket => 712u32, + crate::Item::FireworkStar => 713u32, + crate::Item::FishingRod => 568u32, + crate::Item::Flint => 535u32, + crate::Item::FlintAndSteel => 475u32, + crate::Item::FlowerPot => 696u32, + crate::Item::Furnace => 154u32, + crate::Item::FurnaceMinecart => 565u32, + crate::Item::GhastSpawnEgg => 653u32, + crate::Item::GhastTear => 626u32, + crate::Item::Glass => 64u32, + crate::Item::GlassBottle => 630u32, + crate::Item::GlassPane => 207u32, + crate::Item::GlisteringMelonSlice => 638u32, + crate::Item::Glowstone => 185u32, + crate::Item::GlowstoneDust => 570u32, + crate::Item::GoldBlock => 110u32, + crate::Item::GoldIngot => 483u32, + crate::Item::GoldNugget => 627u32, + crate::Item::GoldOre => 29u32, + crate::Item::GoldenApple => 539u32, + crate::Item::GoldenAxe => 503u32, + crate::Item::GoldenBoots => 534u32, + crate::Item::GoldenCarrot => 702u32, + crate::Item::GoldenChestplate => 532u32, + crate::Item::GoldenHelmet => 531u32, + crate::Item::GoldenHoe => 511u32, + crate::Item::GoldenHorseArmor => 728u32, + crate::Item::GoldenLeggings => 533u32, + crate::Item::GoldenPickaxe => 502u32, + crate::Item::GoldenShovel => 501u32, + crate::Item::GoldenSword => 500u32, + crate::Item::Granite => 2u32, + crate::Item::Grass => 76u32, + crate::Item::GrassBlock => 8u32, + crate::Item::GrassPath => 304u32, + crate::Item::Gravel => 28u32, + crate::Item::GrayBanner => 742u32, + crate::Item::GrayBed => 603u32, + crate::Item::GrayCarpet => 289u32, + crate::Item::GrayConcrete => 402u32, + crate::Item::GrayConcretePowder => 418u32, + crate::Item::GrayDye => 585u32, + crate::Item::GrayGlazedTerracotta => 386u32, + crate::Item::GrayShulkerBox => 370u32, + crate::Item::GrayStainedGlass => 318u32, + crate::Item::GrayStainedGlassPane => 334u32, + crate::Item::GrayTerracotta => 270u32, + crate::Item::GrayWool => 89u32, + crate::Item::GreenBanner => 748u32, + crate::Item::GreenBed => 609u32, + crate::Item::GreenCarpet => 295u32, + crate::Item::GreenConcrete => 408u32, + crate::Item::GreenConcretePowder => 424u32, + crate::Item::GreenGlazedTerracotta => 392u32, + crate::Item::GreenShulkerBox => 376u32, + crate::Item::GreenStainedGlass => 324u32, + crate::Item::GreenStainedGlassPane => 340u32, + crate::Item::GreenTerracotta => 276u32, + crate::Item::GreenWool => 95u32, + crate::Item::GuardianSpawnEgg => 654u32, + crate::Item::Gunpowder => 506u32, + crate::Item::HayBlock => 281u32, + crate::Item::HeartOfTheSea => 789u32, + crate::Item::HeavyWeightedPressurePlate => 252u32, + crate::Item::Hopper => 256u32, + crate::Item::HopperMinecart => 718u32, + crate::Item::HornCoral => 442u32, + crate::Item::HornCoralBlock => 437u32, + crate::Item::HornCoralFan => 452u32, + crate::Item::HorseSpawnEgg => 655u32, + crate::Item::HuskSpawnEgg => 656u32, + crate::Item::Ice => 170u32, + crate::Item::InfestedChiseledStoneBricks => 198u32, + crate::Item::InfestedCobblestone => 194u32, + crate::Item::InfestedCrackedStoneBricks => 197u32, + crate::Item::InfestedMossyStoneBricks => 196u32, + crate::Item::InfestedStone => 193u32, + crate::Item::InfestedStoneBricks => 195u32, + crate::Item::InkSac => 577u32, + crate::Item::IronAxe => 474u32, + crate::Item::IronBars => 206u32, + crate::Item::IronBlock => 111u32, + crate::Item::IronBoots => 526u32, + crate::Item::IronChestplate => 524u32, + crate::Item::IronDoor => 460u32, + crate::Item::IronHelmet => 523u32, + crate::Item::IronHoe => 509u32, + crate::Item::IronHorseArmor => 727u32, + crate::Item::IronIngot => 482u32, + crate::Item::IronLeggings => 525u32, + crate::Item::IronNugget => 771u32, + crate::Item::IronOre => 30u32, + crate::Item::IronPickaxe => 473u32, + crate::Item::IronShovel => 472u32, + crate::Item::IronSword => 484u32, + crate::Item::IronTrapdoor => 280u32, + crate::Item::ItemFrame => 695u32, + crate::Item::JackOLantern => 186u32, + crate::Item::Jukebox => 174u32, + crate::Item::JungleBoat => 766u32, + crate::Item::JungleButton => 244u32, + crate::Item::JungleDoor => 464u32, + crate::Item::JungleFence => 178u32, + crate::Item::JungleFenceGate => 213u32, + crate::Item::JungleLeaves => 59u32, + crate::Item::JungleLog => 35u32, + crate::Item::JunglePlanks => 16u32, + crate::Item::JunglePressurePlate => 163u32, + crate::Item::JungleSapling => 22u32, + crate::Item::JungleSlab => 115u32, + crate::Item::JungleStairs => 236u32, + crate::Item::JungleTrapdoor => 190u32, + crate::Item::JungleWood => 53u32, + crate::Item::Kelp => 559u32, + crate::Item::KnowledgeBook => 772u32, + crate::Item::Ladder => 155u32, + crate::Item::LapisBlock => 66u32, + crate::Item::LapisLazuli => 581u32, + crate::Item::LapisOre => 65u32, + crate::Item::LargeFern => 310u32, + crate::Item::LavaBucket => 544u32, + crate::Item::Lead => 730u32, + crate::Item::Leather => 550u32, + crate::Item::LeatherBoots => 518u32, + crate::Item::LeatherChestplate => 516u32, + crate::Item::LeatherHelmet => 515u32, + crate::Item::LeatherLeggings => 517u32, + crate::Item::Lever => 158u32, + crate::Item::LightBlueBanner => 738u32, + crate::Item::LightBlueBed => 599u32, + crate::Item::LightBlueCarpet => 285u32, + crate::Item::LightBlueConcrete => 398u32, + crate::Item::LightBlueConcretePowder => 414u32, + crate::Item::LightBlueDye => 589u32, + crate::Item::LightBlueGlazedTerracotta => 382u32, + crate::Item::LightBlueShulkerBox => 366u32, + crate::Item::LightBlueStainedGlass => 314u32, + crate::Item::LightBlueStainedGlassPane => 330u32, + crate::Item::LightBlueTerracotta => 266u32, + crate::Item::LightBlueWool => 85u32, + crate::Item::LightGrayBanner => 743u32, + crate::Item::LightGrayBed => 604u32, + crate::Item::LightGrayCarpet => 290u32, + crate::Item::LightGrayConcrete => 403u32, + crate::Item::LightGrayConcretePowder => 419u32, + crate::Item::LightGrayDye => 584u32, + crate::Item::LightGrayGlazedTerracotta => 387u32, + crate::Item::LightGrayShulkerBox => 371u32, + crate::Item::LightGrayStainedGlass => 319u32, + crate::Item::LightGrayStainedGlassPane => 335u32, + crate::Item::LightGrayTerracotta => 271u32, + crate::Item::LightGrayWool => 90u32, + crate::Item::LightWeightedPressurePlate => 251u32, + crate::Item::Lilac => 306u32, + crate::Item::LilyPad => 219u32, + crate::Item::LimeBanner => 740u32, + crate::Item::LimeBed => 601u32, + crate::Item::LimeCarpet => 287u32, + crate::Item::LimeConcrete => 400u32, + crate::Item::LimeConcretePowder => 416u32, + crate::Item::LimeDye => 587u32, + crate::Item::LimeGlazedTerracotta => 384u32, + crate::Item::LimeShulkerBox => 368u32, + crate::Item::LimeStainedGlass => 316u32, + crate::Item::LimeStainedGlassPane => 332u32, + crate::Item::LimeTerracotta => 268u32, + crate::Item::LimeWool => 87u32, + crate::Item::LingeringPotion => 761u32, + crate::Item::LlamaSpawnEgg => 657u32, + crate::Item::MagentaBanner => 737u32, + crate::Item::MagentaBed => 598u32, + crate::Item::MagentaCarpet => 284u32, + crate::Item::MagentaConcrete => 397u32, + crate::Item::MagentaConcretePowder => 413u32, + crate::Item::MagentaDye => 590u32, + crate::Item::MagentaGlazedTerracotta => 381u32, + crate::Item::MagentaShulkerBox => 365u32, + crate::Item::MagentaStainedGlass => 313u32, + crate::Item::MagentaStainedGlassPane => 329u32, + crate::Item::MagentaTerracotta => 265u32, + crate::Item::MagentaWool => 84u32, + crate::Item::MagmaBlock => 356u32, + crate::Item::MagmaCream => 634u32, + crate::Item::MagmaCubeSpawnEgg => 658u32, + crate::Item::Map => 701u32, + crate::Item::Melon => 208u32, + crate::Item::MelonSeeds => 618u32, + crate::Item::MelonSlice => 615u32, + crate::Item::MilkBucket => 551u32, + crate::Item::Minecart => 545u32, + crate::Item::MooshroomSpawnEgg => 659u32, + crate::Item::MossyCobblestone => 138u32, + crate::Item::MossyCobblestoneWall => 240u32, + crate::Item::MossyStoneBricks => 200u32, + crate::Item::MuleSpawnEgg => 660u32, + crate::Item::MushroomStem => 205u32, + crate::Item::MushroomStew => 499u32, + crate::Item::MusicDisc11 => 784u32, + crate::Item::MusicDisc13 => 774u32, + crate::Item::MusicDiscBlocks => 776u32, + crate::Item::MusicDiscCat => 775u32, + crate::Item::MusicDiscChirp => 777u32, + crate::Item::MusicDiscFar => 778u32, + crate::Item::MusicDiscMall => 779u32, + crate::Item::MusicDiscMellohi => 780u32, + crate::Item::MusicDiscStal => 781u32, + crate::Item::MusicDiscStrad => 782u32, + crate::Item::MusicDiscWait => 785u32, + crate::Item::MusicDiscWard => 783u32, + crate::Item::Mutton => 733u32, + crate::Item::Mycelium => 218u32, + crate::Item::NameTag => 731u32, + crate::Item::NautilusShell => 788u32, + crate::Item::NetherBrick => 715u32, + crate::Item::NetherBrickFence => 221u32, + crate::Item::NetherBrickSlab => 124u32, + crate::Item::NetherBrickStairs => 222u32, + crate::Item::NetherBricks => 220u32, + crate::Item::NetherQuartzOre => 255u32, + crate::Item::NetherStar => 710u32, + crate::Item::NetherWart => 628u32, + crate::Item::NetherWartBlock => 357u32, + crate::Item::Netherrack => 183u32, + crate::Item::NoteBlock => 71u32, + crate::Item::OakBoat => 549u32, + crate::Item::OakButton => 241u32, + crate::Item::OakDoor => 461u32, + crate::Item::OakFence => 175u32, + crate::Item::OakFenceGate => 210u32, + crate::Item::OakLeaves => 56u32, + crate::Item::OakLog => 32u32, + crate::Item::OakPlanks => 13u32, + crate::Item::OakPressurePlate => 160u32, + crate::Item::OakSapling => 19u32, + crate::Item::OakSlab => 112u32, + crate::Item::OakStairs => 148u32, + crate::Item::OakTrapdoor => 187u32, + crate::Item::OakWood => 50u32, + crate::Item::Observer => 361u32, + crate::Item::Obsidian => 139u32, + crate::Item::OcelotSpawnEgg => 661u32, + crate::Item::OrangeBanner => 736u32, + crate::Item::OrangeBed => 597u32, + crate::Item::OrangeCarpet => 283u32, + crate::Item::OrangeConcrete => 396u32, + crate::Item::OrangeConcretePowder => 412u32, + crate::Item::OrangeDye => 591u32, + crate::Item::OrangeGlazedTerracotta => 380u32, + crate::Item::OrangeShulkerBox => 364u32, + crate::Item::OrangeStainedGlass => 312u32, + crate::Item::OrangeStainedGlassPane => 328u32, + crate::Item::OrangeTerracotta => 264u32, + crate::Item::OrangeTulip => 104u32, + crate::Item::OrangeWool => 83u32, + crate::Item::OxeyeDaisy => 107u32, + crate::Item::PackedIce => 300u32, + crate::Item::Painting => 538u32, + crate::Item::Paper => 561u32, + crate::Item::ParrotSpawnEgg => 662u32, + crate::Item::Peony => 308u32, + crate::Item::PetrifiedOakSlab => 120u32, + crate::Item::PhantomMembrane => 787u32, + crate::Item::PhantomSpawnEgg => 663u32, + crate::Item::PigSpawnEgg => 664u32, + crate::Item::PinkBanner => 741u32, + crate::Item::PinkBed => 602u32, + crate::Item::PinkCarpet => 288u32, + crate::Item::PinkConcrete => 401u32, + crate::Item::PinkConcretePowder => 417u32, + crate::Item::PinkDye => 586u32, + crate::Item::PinkGlazedTerracotta => 385u32, + crate::Item::PinkShulkerBox => 369u32, + crate::Item::PinkStainedGlass => 317u32, + crate::Item::PinkStainedGlassPane => 333u32, + crate::Item::PinkTerracotta => 269u32, + crate::Item::PinkTulip => 106u32, + crate::Item::PinkWool => 88u32, + crate::Item::Piston => 81u32, + crate::Item::PlayerHead => 705u32, + crate::Item::Podzol => 11u32, + crate::Item::PoisonousPotato => 700u32, + crate::Item::PolarBearSpawnEgg => 665u32, + crate::Item::PolishedAndesite => 7u32, + crate::Item::PolishedDiorite => 5u32, + crate::Item::PolishedGranite => 3u32, + crate::Item::PoppedChorusFruit => 753u32, + crate::Item::Poppy => 99u32, + crate::Item::Porkchop => 536u32, + crate::Item::Potato => 698u32, + crate::Item::Potion => 629u32, + crate::Item::PoweredRail => 72u32, + crate::Item::Prismarine => 343u32, + crate::Item::PrismarineBrickSlab => 129u32, + crate::Item::PrismarineBrickStairs => 347u32, + crate::Item::PrismarineBricks => 344u32, + crate::Item::PrismarineCrystals => 720u32, + crate::Item::PrismarineShard => 719u32, + crate::Item::PrismarineSlab => 128u32, + crate::Item::PrismarineStairs => 346u32, + crate::Item::Pufferfish => 574u32, + crate::Item::PufferfishBucket => 552u32, + crate::Item::PufferfishSpawnEgg => 666u32, + crate::Item::Pumpkin => 181u32, + crate::Item::PumpkinPie => 711u32, + crate::Item::PumpkinSeeds => 617u32, + crate::Item::PurpleBanner => 745u32, + crate::Item::PurpleBed => 606u32, + crate::Item::PurpleCarpet => 292u32, + crate::Item::PurpleConcrete => 405u32, + crate::Item::PurpleConcretePowder => 421u32, + crate::Item::PurpleDye => 582u32, + crate::Item::PurpleGlazedTerracotta => 389u32, + crate::Item::PurpleShulkerBox => 373u32, + crate::Item::PurpleStainedGlass => 321u32, + crate::Item::PurpleStainedGlassPane => 337u32, + crate::Item::PurpleTerracotta => 273u32, + crate::Item::PurpleWool => 92u32, + crate::Item::PurpurBlock => 144u32, + crate::Item::PurpurPillar => 145u32, + crate::Item::PurpurSlab => 127u32, + crate::Item::PurpurStairs => 146u32, + crate::Item::Quartz => 716u32, + crate::Item::QuartzBlock => 258u32, + crate::Item::QuartzPillar => 259u32, + crate::Item::QuartzSlab => 125u32, + crate::Item::QuartzStairs => 260u32, + crate::Item::Rabbit => 721u32, + crate::Item::RabbitFoot => 724u32, + crate::Item::RabbitHide => 725u32, + crate::Item::RabbitSpawnEgg => 667u32, + crate::Item::RabbitStew => 723u32, + crate::Item::Rail => 156u32, + crate::Item::RedBanner => 749u32, + crate::Item::RedBed => 610u32, + crate::Item::RedCarpet => 296u32, + crate::Item::RedConcrete => 409u32, + crate::Item::RedConcretePowder => 425u32, + crate::Item::RedGlazedTerracotta => 393u32, + crate::Item::RedMushroom => 109u32, + crate::Item::RedMushroomBlock => 204u32, + crate::Item::RedNetherBricks => 358u32, + crate::Item::RedSand => 27u32, + crate::Item::RedSandstone => 350u32, + crate::Item::RedSandstoneSlab => 126u32, + crate::Item::RedSandstoneStairs => 353u32, + crate::Item::RedShulkerBox => 377u32, + crate::Item::RedStainedGlass => 325u32, + crate::Item::RedStainedGlassPane => 341u32, + crate::Item::RedTerracotta => 277u32, + crate::Item::RedTulip => 103u32, + crate::Item::RedWool => 96u32, + crate::Item::Redstone => 547u32, + crate::Item::RedstoneBlock => 254u32, + crate::Item::RedstoneLamp => 228u32, + crate::Item::RedstoneOre => 166u32, + crate::Item::RedstoneTorch => 167u32, + crate::Item::Repeater => 467u32, + crate::Item::RepeatingCommandBlock => 354u32, + crate::Item::RoseBush => 307u32, + crate::Item::RoseRed => 578u32, + crate::Item::RottenFlesh => 623u32, + crate::Item::Saddle => 546u32, + crate::Item::Salmon => 572u32, + crate::Item::SalmonBucket => 553u32, + crate::Item::SalmonSpawnEgg => 668u32, + crate::Item::Sand => 26u32, + crate::Item::Sandstone => 68u32, + crate::Item::SandstoneSlab => 119u32, + crate::Item::SandstoneStairs => 229u32, + crate::Item::Scute => 471u32, + crate::Item::SeaLantern => 349u32, + crate::Item::SeaPickle => 80u32, + crate::Item::Seagrass => 79u32, + crate::Item::Shears => 614u32, + crate::Item::SheepSpawnEgg => 669u32, + crate::Item::Shield => 762u32, + crate::Item::ShulkerBox => 362u32, + crate::Item::ShulkerShell => 770u32, + crate::Item::ShulkerSpawnEgg => 670u32, + crate::Item::Sign => 541u32, + crate::Item::SilverfishSpawnEgg => 671u32, + crate::Item::SkeletonHorseSpawnEgg => 673u32, + crate::Item::SkeletonSkull => 703u32, + crate::Item::SkeletonSpawnEgg => 672u32, + crate::Item::SlimeBall => 563u32, + crate::Item::SlimeBlock => 303u32, + crate::Item::SlimeSpawnEgg => 674u32, + crate::Item::SmoothQuartz => 131u32, + crate::Item::SmoothRedSandstone => 132u32, + crate::Item::SmoothSandstone => 133u32, + crate::Item::SmoothStone => 134u32, + crate::Item::Snow => 169u32, + crate::Item::SnowBlock => 171u32, + crate::Item::Snowball => 548u32, + crate::Item::SoulSand => 184u32, + crate::Item::Spawner => 147u32, + crate::Item::SpectralArrow => 759u32, + crate::Item::SpiderEye => 631u32, + crate::Item::SpiderSpawnEgg => 675u32, + crate::Item::SplashPotion => 758u32, + crate::Item::Sponge => 62u32, + crate::Item::SpruceBoat => 764u32, + crate::Item::SpruceButton => 242u32, + crate::Item::SpruceDoor => 462u32, + crate::Item::SpruceFence => 176u32, + crate::Item::SpruceFenceGate => 211u32, + crate::Item::SpruceLeaves => 57u32, + crate::Item::SpruceLog => 33u32, + crate::Item::SprucePlanks => 14u32, + crate::Item::SprucePressurePlate => 161u32, + crate::Item::SpruceSapling => 20u32, + crate::Item::SpruceSlab => 113u32, + crate::Item::SpruceStairs => 234u32, + crate::Item::SpruceTrapdoor => 188u32, + crate::Item::SpruceWood => 51u32, + crate::Item::SquidSpawnEgg => 676u32, + crate::Item::Stick => 497u32, + crate::Item::StickyPiston => 74u32, + crate::Item::Stone => 1u32, + crate::Item::StoneAxe => 492u32, + crate::Item::StoneBrickSlab => 123u32, + crate::Item::StoneBrickStairs => 217u32, + crate::Item::StoneBricks => 199u32, + crate::Item::StoneButton => 168u32, + crate::Item::StoneHoe => 508u32, + crate::Item::StonePickaxe => 491u32, + crate::Item::StonePressurePlate => 159u32, + crate::Item::StoneShovel => 490u32, + crate::Item::StoneSlab => 118u32, + crate::Item::StoneSword => 489u32, + crate::Item::StraySpawnEgg => 677u32, + crate::Item::String => 504u32, + crate::Item::StrippedAcaciaLog => 42u32, + crate::Item::StrippedAcaciaWood => 48u32, + crate::Item::StrippedBirchLog => 40u32, + crate::Item::StrippedBirchWood => 46u32, + crate::Item::StrippedDarkOakLog => 43u32, + crate::Item::StrippedDarkOakWood => 49u32, + crate::Item::StrippedJungleLog => 41u32, + crate::Item::StrippedJungleWood => 47u32, + crate::Item::StrippedOakLog => 38u32, + crate::Item::StrippedOakWood => 44u32, + crate::Item::StrippedSpruceLog => 39u32, + crate::Item::StrippedSpruceWood => 45u32, + crate::Item::StructureBlock => 469u32, + crate::Item::StructureVoid => 360u32, + crate::Item::Sugar => 594u32, + crate::Item::SugarCane => 558u32, + crate::Item::Sunflower => 305u32, + crate::Item::TallGrass => 309u32, + crate::Item::Terracotta => 298u32, + crate::Item::TippedArrow => 760u32, + crate::Item::Tnt => 136u32, + crate::Item::TntMinecart => 717u32, + crate::Item::Torch => 140u32, + crate::Item::TotemOfUndying => 769u32, + crate::Item::TrappedChest => 250u32, + crate::Item::Trident => 786u32, + crate::Item::TripwireHook => 232u32, + crate::Item::TropicalFish => 573u32, + crate::Item::TropicalFishBucket => 555u32, + crate::Item::TropicalFishSpawnEgg => 678u32, + crate::Item::TubeCoral => 438u32, + crate::Item::TubeCoralBlock => 433u32, + crate::Item::TubeCoralFan => 448u32, + crate::Item::TurtleEgg => 427u32, + crate::Item::TurtleHelmet => 470u32, + crate::Item::TurtleSpawnEgg => 679u32, + crate::Item::VexSpawnEgg => 680u32, + crate::Item::VillagerSpawnEgg => 681u32, + crate::Item::VindicatorSpawnEgg => 682u32, + crate::Item::Vine => 209u32, + crate::Item::WaterBucket => 543u32, + crate::Item::WetSponge => 63u32, + crate::Item::Wheat => 513u32, + crate::Item::WheatSeeds => 512u32, + crate::Item::WhiteBanner => 735u32, + crate::Item::WhiteBed => 596u32, + crate::Item::WhiteCarpet => 282u32, + crate::Item::WhiteConcrete => 395u32, + crate::Item::WhiteConcretePowder => 411u32, + crate::Item::WhiteGlazedTerracotta => 379u32, + crate::Item::WhiteShulkerBox => 363u32, + crate::Item::WhiteStainedGlass => 311u32, + crate::Item::WhiteStainedGlassPane => 327u32, + crate::Item::WhiteTerracotta => 263u32, + crate::Item::WhiteTulip => 105u32, + crate::Item::WhiteWool => 82u32, + crate::Item::WitchSpawnEgg => 683u32, + crate::Item::WitherSkeletonSkull => 704u32, + crate::Item::WitherSkeletonSpawnEgg => 684u32, + crate::Item::WolfSpawnEgg => 685u32, + crate::Item::WoodenAxe => 488u32, + crate::Item::WoodenHoe => 507u32, + crate::Item::WoodenPickaxe => 487u32, + crate::Item::WoodenShovel => 486u32, + crate::Item::WoodenSword => 485u32, + crate::Item::WritableBook => 692u32, + crate::Item::WrittenBook => 693u32, + crate::Item::YellowBanner => 739u32, + crate::Item::YellowBed => 600u32, + crate::Item::YellowCarpet => 286u32, + crate::Item::YellowConcrete => 399u32, + crate::Item::YellowConcretePowder => 415u32, + crate::Item::YellowGlazedTerracotta => 383u32, + crate::Item::YellowShulkerBox => 367u32, + crate::Item::YellowStainedGlass => 315u32, + crate::Item::YellowStainedGlassPane => 331u32, + crate::Item::YellowTerracotta => 267u32, + crate::Item::YellowWool => 86u32, + crate::Item::ZombieHead => 706u32, + crate::Item::ZombieHorseSpawnEgg => 687u32, + crate::Item::ZombiePigmanSpawnEgg => 688u32, + crate::Item::ZombieSpawnEgg => 686u32, + crate::Item::ZombieVillagerSpawnEgg => 689u32, + } + } + pub fn from_vanilla_id(prop: u32) -> Option<Item> { + match prop { + 767u32 => Some(crate::Item::AcaciaBoat), + 245u32 => Some(crate::Item::AcaciaButton), + 465u32 => Some(crate::Item::AcaciaDoor), + 179u32 => Some(crate::Item::AcaciaFence), + 214u32 => Some(crate::Item::AcaciaFenceGate), + 60u32 => Some(crate::Item::AcaciaLeaves), + 36u32 => Some(crate::Item::AcaciaLog), + 17u32 => Some(crate::Item::AcaciaPlanks), + 164u32 => Some(crate::Item::AcaciaPressurePlate), + 23u32 => Some(crate::Item::AcaciaSapling), + 116u32 => Some(crate::Item::AcaciaSlab), + 301u32 => Some(crate::Item::AcaciaStairs), + 191u32 => Some(crate::Item::AcaciaTrapdoor), + 54u32 => Some(crate::Item::AcaciaWood), + 261u32 => Some(crate::Item::ActivatorRail), + 0u32 => Some(crate::Item::Air), + 101u32 => Some(crate::Item::Allium), + 6u32 => Some(crate::Item::Andesite), + 247u32 => Some(crate::Item::Anvil), + 476u32 => Some(crate::Item::Apple), + 726u32 => Some(crate::Item::ArmorStand), + 478u32 => Some(crate::Item::Arrow), + 102u32 => Some(crate::Item::AzureBluet), + 699u32 => Some(crate::Item::BakedPotato), + 279u32 => Some(crate::Item::Barrier), + 639u32 => Some(crate::Item::BatSpawnEgg), + 238u32 => Some(crate::Item::Beacon), + 25u32 => Some(crate::Item::Bedrock), + 619u32 => Some(crate::Item::Beef), + 754u32 => Some(crate::Item::Beetroot), + 755u32 => Some(crate::Item::BeetrootSeeds), + 756u32 => Some(crate::Item::BeetrootSoup), + 765u32 => Some(crate::Item::BirchBoat), + 243u32 => Some(crate::Item::BirchButton), + 463u32 => Some(crate::Item::BirchDoor), + 177u32 => Some(crate::Item::BirchFence), + 212u32 => Some(crate::Item::BirchFenceGate), + 58u32 => Some(crate::Item::BirchLeaves), + 34u32 => Some(crate::Item::BirchLog), + 15u32 => Some(crate::Item::BirchPlanks), + 162u32 => Some(crate::Item::BirchPressurePlate), + 21u32 => Some(crate::Item::BirchSapling), + 114u32 => Some(crate::Item::BirchSlab), + 235u32 => Some(crate::Item::BirchStairs), + 189u32 => Some(crate::Item::BirchTrapdoor), + 52u32 => Some(crate::Item::BirchWood), + 750u32 => Some(crate::Item::BlackBanner), + 611u32 => Some(crate::Item::BlackBed), + 297u32 => Some(crate::Item::BlackCarpet), + 410u32 => Some(crate::Item::BlackConcrete), + 426u32 => Some(crate::Item::BlackConcretePowder), + 394u32 => Some(crate::Item::BlackGlazedTerracotta), + 378u32 => Some(crate::Item::BlackShulkerBox), + 326u32 => Some(crate::Item::BlackStainedGlass), + 342u32 => Some(crate::Item::BlackStainedGlassPane), + 278u32 => Some(crate::Item::BlackTerracotta), + 97u32 => Some(crate::Item::BlackWool), + 633u32 => Some(crate::Item::BlazePowder), + 625u32 => Some(crate::Item::BlazeRod), + 640u32 => Some(crate::Item::BlazeSpawnEgg), + 746u32 => Some(crate::Item::BlueBanner), + 607u32 => Some(crate::Item::BlueBed), + 293u32 => Some(crate::Item::BlueCarpet), + 406u32 => Some(crate::Item::BlueConcrete), + 422u32 => Some(crate::Item::BlueConcretePowder), + 390u32 => Some(crate::Item::BlueGlazedTerracotta), + 458u32 => Some(crate::Item::BlueIce), + 100u32 => Some(crate::Item::BlueOrchid), + 374u32 => Some(crate::Item::BlueShulkerBox), + 322u32 => Some(crate::Item::BlueStainedGlass), + 338u32 => Some(crate::Item::BlueStainedGlassPane), + 274u32 => Some(crate::Item::BlueTerracotta), + 93u32 => Some(crate::Item::BlueWool), + 593u32 => Some(crate::Item::Bone), + 359u32 => Some(crate::Item::BoneBlock), + 592u32 => Some(crate::Item::BoneMeal), + 562u32 => Some(crate::Item::Book), + 137u32 => Some(crate::Item::Bookshelf), + 477u32 => Some(crate::Item::Bow), + 498u32 => Some(crate::Item::Bowl), + 439u32 => Some(crate::Item::BrainCoral), + 434u32 => Some(crate::Item::BrainCoralBlock), + 449u32 => Some(crate::Item::BrainCoralFan), + 514u32 => Some(crate::Item::Bread), + 635u32 => Some(crate::Item::BrewingStand), + 556u32 => Some(crate::Item::Brick), + 122u32 => Some(crate::Item::BrickSlab), + 216u32 => Some(crate::Item::BrickStairs), + 135u32 => Some(crate::Item::Bricks), + 747u32 => Some(crate::Item::BrownBanner), + 608u32 => Some(crate::Item::BrownBed), + 294u32 => Some(crate::Item::BrownCarpet), + 407u32 => Some(crate::Item::BrownConcrete), + 423u32 => Some(crate::Item::BrownConcretePowder), + 391u32 => Some(crate::Item::BrownGlazedTerracotta), + 108u32 => Some(crate::Item::BrownMushroom), + 203u32 => Some(crate::Item::BrownMushroomBlock), + 375u32 => Some(crate::Item::BrownShulkerBox), + 323u32 => Some(crate::Item::BrownStainedGlass), + 339u32 => Some(crate::Item::BrownStainedGlassPane), + 275u32 => Some(crate::Item::BrownTerracotta), + 94u32 => Some(crate::Item::BrownWool), + 440u32 => Some(crate::Item::BubbleCoral), + 435u32 => Some(crate::Item::BubbleCoralBlock), + 450u32 => Some(crate::Item::BubbleCoralFan), + 542u32 => Some(crate::Item::Bucket), + 172u32 => Some(crate::Item::Cactus), + 579u32 => Some(crate::Item::CactusGreen), + 595u32 => Some(crate::Item::Cake), + 697u32 => Some(crate::Item::Carrot), + 709u32 => Some(crate::Item::CarrotOnAStick), + 182u32 => Some(crate::Item::CarvedPumpkin), + 636u32 => Some(crate::Item::Cauldron), + 641u32 => Some(crate::Item::CaveSpiderSpawnEgg), + 355u32 => Some(crate::Item::ChainCommandBlock), + 522u32 => Some(crate::Item::ChainmailBoots), + 520u32 => Some(crate::Item::ChainmailChestplate), + 519u32 => Some(crate::Item::ChainmailHelmet), + 521u32 => Some(crate::Item::ChainmailLeggings), + 480u32 => Some(crate::Item::Charcoal), + 149u32 => Some(crate::Item::Chest), + 564u32 => Some(crate::Item::ChestMinecart), + 621u32 => Some(crate::Item::Chicken), + 642u32 => Some(crate::Item::ChickenSpawnEgg), + 248u32 => Some(crate::Item::ChippedAnvil), + 257u32 => Some(crate::Item::ChiseledQuartzBlock), + 351u32 => Some(crate::Item::ChiseledRedSandstone), + 69u32 => Some(crate::Item::ChiseledSandstone), + 202u32 => Some(crate::Item::ChiseledStoneBricks), + 143u32 => Some(crate::Item::ChorusFlower), + 752u32 => Some(crate::Item::ChorusFruit), + 142u32 => Some(crate::Item::ChorusPlant), + 173u32 => Some(crate::Item::Clay), + 557u32 => Some(crate::Item::ClayBall), + 569u32 => Some(crate::Item::Clock), + 479u32 => Some(crate::Item::Coal), + 299u32 => Some(crate::Item::CoalBlock), + 31u32 => Some(crate::Item::CoalOre), + 10u32 => Some(crate::Item::CoarseDirt), + 12u32 => Some(crate::Item::Cobblestone), + 121u32 => Some(crate::Item::CobblestoneSlab), + 157u32 => Some(crate::Item::CobblestoneStairs), + 239u32 => Some(crate::Item::CobblestoneWall), + 75u32 => Some(crate::Item::Cobweb), + 580u32 => Some(crate::Item::CocoaBeans), + 571u32 => Some(crate::Item::Cod), + 554u32 => Some(crate::Item::CodBucket), + 643u32 => Some(crate::Item::CodSpawnEgg), + 237u32 => Some(crate::Item::CommandBlock), + 732u32 => Some(crate::Item::CommandBlockMinecart), + 468u32 => Some(crate::Item::Comparator), + 567u32 => Some(crate::Item::Compass), + 459u32 => Some(crate::Item::Conduit), + 620u32 => Some(crate::Item::CookedBeef), + 622u32 => Some(crate::Item::CookedChicken), + 575u32 => Some(crate::Item::CookedCod), + 734u32 => Some(crate::Item::CookedMutton), + 537u32 => Some(crate::Item::CookedPorkchop), + 722u32 => Some(crate::Item::CookedRabbit), + 576u32 => Some(crate::Item::CookedSalmon), + 612u32 => Some(crate::Item::Cookie), + 644u32 => Some(crate::Item::CowSpawnEgg), + 201u32 => Some(crate::Item::CrackedStoneBricks), + 152u32 => Some(crate::Item::CraftingTable), + 707u32 => Some(crate::Item::CreeperHead), + 645u32 => Some(crate::Item::CreeperSpawnEgg), + 352u32 => Some(crate::Item::CutRedSandstone), + 70u32 => Some(crate::Item::CutSandstone), + 744u32 => Some(crate::Item::CyanBanner), + 605u32 => Some(crate::Item::CyanBed), + 291u32 => Some(crate::Item::CyanCarpet), + 404u32 => Some(crate::Item::CyanConcrete), + 420u32 => Some(crate::Item::CyanConcretePowder), + 583u32 => Some(crate::Item::CyanDye), + 388u32 => Some(crate::Item::CyanGlazedTerracotta), + 372u32 => Some(crate::Item::CyanShulkerBox), + 320u32 => Some(crate::Item::CyanStainedGlass), + 336u32 => Some(crate::Item::CyanStainedGlassPane), + 272u32 => Some(crate::Item::CyanTerracotta), + 91u32 => Some(crate::Item::CyanWool), + 249u32 => Some(crate::Item::DamagedAnvil), + 98u32 => Some(crate::Item::Dandelion), + 588u32 => Some(crate::Item::DandelionYellow), + 768u32 => Some(crate::Item::DarkOakBoat), + 246u32 => Some(crate::Item::DarkOakButton), + 466u32 => Some(crate::Item::DarkOakDoor), + 180u32 => Some(crate::Item::DarkOakFence), + 215u32 => Some(crate::Item::DarkOakFenceGate), + 61u32 => Some(crate::Item::DarkOakLeaves), + 37u32 => Some(crate::Item::DarkOakLog), + 18u32 => Some(crate::Item::DarkOakPlanks), + 165u32 => Some(crate::Item::DarkOakPressurePlate), + 24u32 => Some(crate::Item::DarkOakSapling), + 117u32 => Some(crate::Item::DarkOakSlab), + 302u32 => Some(crate::Item::DarkOakStairs), + 192u32 => Some(crate::Item::DarkOakTrapdoor), + 55u32 => Some(crate::Item::DarkOakWood), + 345u32 => Some(crate::Item::DarkPrismarine), + 130u32 => Some(crate::Item::DarkPrismarineSlab), + 348u32 => Some(crate::Item::DarkPrismarineStairs), + 253u32 => Some(crate::Item::DaylightDetector), + 443u32 => Some(crate::Item::DeadBrainCoral), + 429u32 => Some(crate::Item::DeadBrainCoralBlock), + 454u32 => Some(crate::Item::DeadBrainCoralFan), + 444u32 => Some(crate::Item::DeadBubbleCoral), + 430u32 => Some(crate::Item::DeadBubbleCoralBlock), + 455u32 => Some(crate::Item::DeadBubbleCoralFan), + 78u32 => Some(crate::Item::DeadBush), + 445u32 => Some(crate::Item::DeadFireCoral), + 431u32 => Some(crate::Item::DeadFireCoralBlock), + 456u32 => Some(crate::Item::DeadFireCoralFan), + 446u32 => Some(crate::Item::DeadHornCoral), + 432u32 => Some(crate::Item::DeadHornCoralBlock), + 457u32 => Some(crate::Item::DeadHornCoralFan), + 447u32 => Some(crate::Item::DeadTubeCoral), + 428u32 => Some(crate::Item::DeadTubeCoralBlock), + 453u32 => Some(crate::Item::DeadTubeCoralFan), + 773u32 => Some(crate::Item::DebugStick), + 73u32 => Some(crate::Item::DetectorRail), + 481u32 => Some(crate::Item::Diamond), + 496u32 => Some(crate::Item::DiamondAxe), + 151u32 => Some(crate::Item::DiamondBlock), + 530u32 => Some(crate::Item::DiamondBoots), + 528u32 => Some(crate::Item::DiamondChestplate), + 527u32 => Some(crate::Item::DiamondHelmet), + 510u32 => Some(crate::Item::DiamondHoe), + 729u32 => Some(crate::Item::DiamondHorseArmor), + 529u32 => Some(crate::Item::DiamondLeggings), + 150u32 => Some(crate::Item::DiamondOre), + 495u32 => Some(crate::Item::DiamondPickaxe), + 494u32 => Some(crate::Item::DiamondShovel), + 493u32 => Some(crate::Item::DiamondSword), + 4u32 => Some(crate::Item::Diorite), + 9u32 => Some(crate::Item::Dirt), + 67u32 => Some(crate::Item::Dispenser), + 646u32 => Some(crate::Item::DolphinSpawnEgg), + 647u32 => Some(crate::Item::DonkeySpawnEgg), + 757u32 => Some(crate::Item::DragonBreath), + 227u32 => Some(crate::Item::DragonEgg), + 708u32 => Some(crate::Item::DragonHead), + 616u32 => Some(crate::Item::DriedKelp), + 560u32 => Some(crate::Item::DriedKelpBlock), + 262u32 => Some(crate::Item::Dropper), + 648u32 => Some(crate::Item::DrownedSpawnEgg), + 566u32 => Some(crate::Item::Egg), + 649u32 => Some(crate::Item::ElderGuardianSpawnEgg), + 763u32 => Some(crate::Item::Elytra), + 694u32 => Some(crate::Item::Emerald), + 233u32 => Some(crate::Item::EmeraldBlock), + 230u32 => Some(crate::Item::EmeraldOre), + 714u32 => Some(crate::Item::EnchantedBook), + 540u32 => Some(crate::Item::EnchantedGoldenApple), + 223u32 => Some(crate::Item::EnchantingTable), + 751u32 => Some(crate::Item::EndCrystal), + 224u32 => Some(crate::Item::EndPortalFrame), + 141u32 => Some(crate::Item::EndRod), + 225u32 => Some(crate::Item::EndStone), + 226u32 => Some(crate::Item::EndStoneBricks), + 231u32 => Some(crate::Item::EnderChest), + 637u32 => Some(crate::Item::EnderEye), + 624u32 => Some(crate::Item::EnderPearl), + 650u32 => Some(crate::Item::EndermanSpawnEgg), + 651u32 => Some(crate::Item::EndermiteSpawnEgg), + 652u32 => Some(crate::Item::EvokerSpawnEgg), + 690u32 => Some(crate::Item::ExperienceBottle), + 153u32 => Some(crate::Item::Farmland), + 505u32 => Some(crate::Item::Feather), + 632u32 => Some(crate::Item::FermentedSpiderEye), + 77u32 => Some(crate::Item::Fern), + 613u32 => Some(crate::Item::FilledMap), + 691u32 => Some(crate::Item::FireCharge), + 441u32 => Some(crate::Item::FireCoral), + 436u32 => Some(crate::Item::FireCoralBlock), + 451u32 => Some(crate::Item::FireCoralFan), + 712u32 => Some(crate::Item::FireworkRocket), + 713u32 => Some(crate::Item::FireworkStar), + 568u32 => Some(crate::Item::FishingRod), + 535u32 => Some(crate::Item::Flint), + 475u32 => Some(crate::Item::FlintAndSteel), + 696u32 => Some(crate::Item::FlowerPot), + 154u32 => Some(crate::Item::Furnace), + 565u32 => Some(crate::Item::FurnaceMinecart), + 653u32 => Some(crate::Item::GhastSpawnEgg), + 626u32 => Some(crate::Item::GhastTear), + 64u32 => Some(crate::Item::Glass), + 630u32 => Some(crate::Item::GlassBottle), + 207u32 => Some(crate::Item::GlassPane), + 638u32 => Some(crate::Item::GlisteringMelonSlice), + 185u32 => Some(crate::Item::Glowstone), + 570u32 => Some(crate::Item::GlowstoneDust), + 110u32 => Some(crate::Item::GoldBlock), + 483u32 => Some(crate::Item::GoldIngot), + 627u32 => Some(crate::Item::GoldNugget), + 29u32 => Some(crate::Item::GoldOre), + 539u32 => Some(crate::Item::GoldenApple), + 503u32 => Some(crate::Item::GoldenAxe), + 534u32 => Some(crate::Item::GoldenBoots), + 702u32 => Some(crate::Item::GoldenCarrot), + 532u32 => Some(crate::Item::GoldenChestplate), + 531u32 => Some(crate::Item::GoldenHelmet), + 511u32 => Some(crate::Item::GoldenHoe), + 728u32 => Some(crate::Item::GoldenHorseArmor), + 533u32 => Some(crate::Item::GoldenLeggings), + 502u32 => Some(crate::Item::GoldenPickaxe), + 501u32 => Some(crate::Item::GoldenShovel), + 500u32 => Some(crate::Item::GoldenSword), + 2u32 => Some(crate::Item::Granite), + 76u32 => Some(crate::Item::Grass), + 8u32 => Some(crate::Item::GrassBlock), + 304u32 => Some(crate::Item::GrassPath), + 28u32 => Some(crate::Item::Gravel), + 742u32 => Some(crate::Item::GrayBanner), + 603u32 => Some(crate::Item::GrayBed), + 289u32 => Some(crate::Item::GrayCarpet), + 402u32 => Some(crate::Item::GrayConcrete), + 418u32 => Some(crate::Item::GrayConcretePowder), + 585u32 => Some(crate::Item::GrayDye), + 386u32 => Some(crate::Item::GrayGlazedTerracotta), + 370u32 => Some(crate::Item::GrayShulkerBox), + 318u32 => Some(crate::Item::GrayStainedGlass), + 334u32 => Some(crate::Item::GrayStainedGlassPane), + 270u32 => Some(crate::Item::GrayTerracotta), + 89u32 => Some(crate::Item::GrayWool), + 748u32 => Some(crate::Item::GreenBanner), + 609u32 => Some(crate::Item::GreenBed), + 295u32 => Some(crate::Item::GreenCarpet), + 408u32 => Some(crate::Item::GreenConcrete), + 424u32 => Some(crate::Item::GreenConcretePowder), + 392u32 => Some(crate::Item::GreenGlazedTerracotta), + 376u32 => Some(crate::Item::GreenShulkerBox), + 324u32 => Some(crate::Item::GreenStainedGlass), + 340u32 => Some(crate::Item::GreenStainedGlassPane), + 276u32 => Some(crate::Item::GreenTerracotta), + 95u32 => Some(crate::Item::GreenWool), + 654u32 => Some(crate::Item::GuardianSpawnEgg), + 506u32 => Some(crate::Item::Gunpowder), + 281u32 => Some(crate::Item::HayBlock), + 789u32 => Some(crate::Item::HeartOfTheSea), + 252u32 => Some(crate::Item::HeavyWeightedPressurePlate), + 256u32 => Some(crate::Item::Hopper), + 718u32 => Some(crate::Item::HopperMinecart), + 442u32 => Some(crate::Item::HornCoral), + 437u32 => Some(crate::Item::HornCoralBlock), + 452u32 => Some(crate::Item::HornCoralFan), + 655u32 => Some(crate::Item::HorseSpawnEgg), + 656u32 => Some(crate::Item::HuskSpawnEgg), + 170u32 => Some(crate::Item::Ice), + 198u32 => Some(crate::Item::InfestedChiseledStoneBricks), + 194u32 => Some(crate::Item::InfestedCobblestone), + 197u32 => Some(crate::Item::InfestedCrackedStoneBricks), + 196u32 => Some(crate::Item::InfestedMossyStoneBricks), + 193u32 => Some(crate::Item::InfestedStone), + 195u32 => Some(crate::Item::InfestedStoneBricks), + 577u32 => Some(crate::Item::InkSac), + 474u32 => Some(crate::Item::IronAxe), + 206u32 => Some(crate::Item::IronBars), + 111u32 => Some(crate::Item::IronBlock), + 526u32 => Some(crate::Item::IronBoots), + 524u32 => Some(crate::Item::IronChestplate), + 460u32 => Some(crate::Item::IronDoor), + 523u32 => Some(crate::Item::IronHelmet), + 509u32 => Some(crate::Item::IronHoe), + 727u32 => Some(crate::Item::IronHorseArmor), + 482u32 => Some(crate::Item::IronIngot), + 525u32 => Some(crate::Item::IronLeggings), + 771u32 => Some(crate::Item::IronNugget), + 30u32 => Some(crate::Item::IronOre), + 473u32 => Some(crate::Item::IronPickaxe), + 472u32 => Some(crate::Item::IronShovel), + 484u32 => Some(crate::Item::IronSword), + 280u32 => Some(crate::Item::IronTrapdoor), + 695u32 => Some(crate::Item::ItemFrame), + 186u32 => Some(crate::Item::JackOLantern), + 174u32 => Some(crate::Item::Jukebox), + 766u32 => Some(crate::Item::JungleBoat), + 244u32 => Some(crate::Item::JungleButton), + 464u32 => Some(crate::Item::JungleDoor), + 178u32 => Some(crate::Item::JungleFence), + 213u32 => Some(crate::Item::JungleFenceGate), + 59u32 => Some(crate::Item::JungleLeaves), + 35u32 => Some(crate::Item::JungleLog), + 16u32 => Some(crate::Item::JunglePlanks), + 163u32 => Some(crate::Item::JunglePressurePlate), + 22u32 => Some(crate::Item::JungleSapling), + 115u32 => Some(crate::Item::JungleSlab), + 236u32 => Some(crate::Item::JungleStairs), + 190u32 => Some(crate::Item::JungleTrapdoor), + 53u32 => Some(crate::Item::JungleWood), + 559u32 => Some(crate::Item::Kelp), + 772u32 => Some(crate::Item::KnowledgeBook), + 155u32 => Some(crate::Item::Ladder), + 66u32 => Some(crate::Item::LapisBlock), + 581u32 => Some(crate::Item::LapisLazuli), + 65u32 => Some(crate::Item::LapisOre), + 310u32 => Some(crate::Item::LargeFern), + 544u32 => Some(crate::Item::LavaBucket), + 730u32 => Some(crate::Item::Lead), + 550u32 => Some(crate::Item::Leather), + 518u32 => Some(crate::Item::LeatherBoots), + 516u32 => Some(crate::Item::LeatherChestplate), + 515u32 => Some(crate::Item::LeatherHelmet), + 517u32 => Some(crate::Item::LeatherLeggings), + 158u32 => Some(crate::Item::Lever), + 738u32 => Some(crate::Item::LightBlueBanner), + 599u32 => Some(crate::Item::LightBlueBed), + 285u32 => Some(crate::Item::LightBlueCarpet), + 398u32 => Some(crate::Item::LightBlueConcrete), + 414u32 => Some(crate::Item::LightBlueConcretePowder), + 589u32 => Some(crate::Item::LightBlueDye), + 382u32 => Some(crate::Item::LightBlueGlazedTerracotta), + 366u32 => Some(crate::Item::LightBlueShulkerBox), + 314u32 => Some(crate::Item::LightBlueStainedGlass), + 330u32 => Some(crate::Item::LightBlueStainedGlassPane), + 266u32 => Some(crate::Item::LightBlueTerracotta), + 85u32 => Some(crate::Item::LightBlueWool), + 743u32 => Some(crate::Item::LightGrayBanner), + 604u32 => Some(crate::Item::LightGrayBed), + 290u32 => Some(crate::Item::LightGrayCarpet), + 403u32 => Some(crate::Item::LightGrayConcrete), + 419u32 => Some(crate::Item::LightGrayConcretePowder), + 584u32 => Some(crate::Item::LightGrayDye), + 387u32 => Some(crate::Item::LightGrayGlazedTerracotta), + 371u32 => Some(crate::Item::LightGrayShulkerBox), + 319u32 => Some(crate::Item::LightGrayStainedGlass), + 335u32 => Some(crate::Item::LightGrayStainedGlassPane), + 271u32 => Some(crate::Item::LightGrayTerracotta), + 90u32 => Some(crate::Item::LightGrayWool), + 251u32 => Some(crate::Item::LightWeightedPressurePlate), + 306u32 => Some(crate::Item::Lilac), + 219u32 => Some(crate::Item::LilyPad), + 740u32 => Some(crate::Item::LimeBanner), + 601u32 => Some(crate::Item::LimeBed), + 287u32 => Some(crate::Item::LimeCarpet), + 400u32 => Some(crate::Item::LimeConcrete), + 416u32 => Some(crate::Item::LimeConcretePowder), + 587u32 => Some(crate::Item::LimeDye), + 384u32 => Some(crate::Item::LimeGlazedTerracotta), + 368u32 => Some(crate::Item::LimeShulkerBox), + 316u32 => Some(crate::Item::LimeStainedGlass), + 332u32 => Some(crate::Item::LimeStainedGlassPane), + 268u32 => Some(crate::Item::LimeTerracotta), + 87u32 => Some(crate::Item::LimeWool), + 761u32 => Some(crate::Item::LingeringPotion), + 657u32 => Some(crate::Item::LlamaSpawnEgg), + 737u32 => Some(crate::Item::MagentaBanner), + 598u32 => Some(crate::Item::MagentaBed), + 284u32 => Some(crate::Item::MagentaCarpet), + 397u32 => Some(crate::Item::MagentaConcrete), + 413u32 => Some(crate::Item::MagentaConcretePowder), + 590u32 => Some(crate::Item::MagentaDye), + 381u32 => Some(crate::Item::MagentaGlazedTerracotta), + 365u32 => Some(crate::Item::MagentaShulkerBox), + 313u32 => Some(crate::Item::MagentaStainedGlass), + 329u32 => Some(crate::Item::MagentaStainedGlassPane), + 265u32 => Some(crate::Item::MagentaTerracotta), + 84u32 => Some(crate::Item::MagentaWool), + 356u32 => Some(crate::Item::MagmaBlock), + 634u32 => Some(crate::Item::MagmaCream), + 658u32 => Some(crate::Item::MagmaCubeSpawnEgg), + 701u32 => Some(crate::Item::Map), + 208u32 => Some(crate::Item::Melon), + 618u32 => Some(crate::Item::MelonSeeds), + 615u32 => Some(crate::Item::MelonSlice), + 551u32 => Some(crate::Item::MilkBucket), + 545u32 => Some(crate::Item::Minecart), + 659u32 => Some(crate::Item::MooshroomSpawnEgg), + 138u32 => Some(crate::Item::MossyCobblestone), + 240u32 => Some(crate::Item::MossyCobblestoneWall), + 200u32 => Some(crate::Item::MossyStoneBricks), + 660u32 => Some(crate::Item::MuleSpawnEgg), + 205u32 => Some(crate::Item::MushroomStem), + 499u32 => Some(crate::Item::MushroomStew), + 784u32 => Some(crate::Item::MusicDisc11), + 774u32 => Some(crate::Item::MusicDisc13), + 776u32 => Some(crate::Item::MusicDiscBlocks), + 775u32 => Some(crate::Item::MusicDiscCat), + 777u32 => Some(crate::Item::MusicDiscChirp), + 778u32 => Some(crate::Item::MusicDiscFar), + 779u32 => Some(crate::Item::MusicDiscMall), + 780u32 => Some(crate::Item::MusicDiscMellohi), + 781u32 => Some(crate::Item::MusicDiscStal), + 782u32 => Some(crate::Item::MusicDiscStrad), + 785u32 => Some(crate::Item::MusicDiscWait), + 783u32 => Some(crate::Item::MusicDiscWard), + 733u32 => Some(crate::Item::Mutton), + 218u32 => Some(crate::Item::Mycelium), + 731u32 => Some(crate::Item::NameTag), + 788u32 => Some(crate::Item::NautilusShell), + 715u32 => Some(crate::Item::NetherBrick), + 221u32 => Some(crate::Item::NetherBrickFence), + 124u32 => Some(crate::Item::NetherBrickSlab), + 222u32 => Some(crate::Item::NetherBrickStairs), + 220u32 => Some(crate::Item::NetherBricks), + 255u32 => Some(crate::Item::NetherQuartzOre), + 710u32 => Some(crate::Item::NetherStar), + 628u32 => Some(crate::Item::NetherWart), + 357u32 => Some(crate::Item::NetherWartBlock), + 183u32 => Some(crate::Item::Netherrack), + 71u32 => Some(crate::Item::NoteBlock), + 549u32 => Some(crate::Item::OakBoat), + 241u32 => Some(crate::Item::OakButton), + 461u32 => Some(crate::Item::OakDoor), + 175u32 => Some(crate::Item::OakFence), + 210u32 => Some(crate::Item::OakFenceGate), + 56u32 => Some(crate::Item::OakLeaves), + 32u32 => Some(crate::Item::OakLog), + 13u32 => Some(crate::Item::OakPlanks), + 160u32 => Some(crate::Item::OakPressurePlate), + 19u32 => Some(crate::Item::OakSapling), + 112u32 => Some(crate::Item::OakSlab), + 148u32 => Some(crate::Item::OakStairs), + 187u32 => Some(crate::Item::OakTrapdoor), + 50u32 => Some(crate::Item::OakWood), + 361u32 => Some(crate::Item::Observer), + 139u32 => Some(crate::Item::Obsidian), + 661u32 => Some(crate::Item::OcelotSpawnEgg), + 736u32 => Some(crate::Item::OrangeBanner), + 597u32 => Some(crate::Item::OrangeBed), + 283u32 => Some(crate::Item::OrangeCarpet), + 396u32 => Some(crate::Item::OrangeConcrete), + 412u32 => Some(crate::Item::OrangeConcretePowder), + 591u32 => Some(crate::Item::OrangeDye), + 380u32 => Some(crate::Item::OrangeGlazedTerracotta), + 364u32 => Some(crate::Item::OrangeShulkerBox), + 312u32 => Some(crate::Item::OrangeStainedGlass), + 328u32 => Some(crate::Item::OrangeStainedGlassPane), + 264u32 => Some(crate::Item::OrangeTerracotta), + 104u32 => Some(crate::Item::OrangeTulip), + 83u32 => Some(crate::Item::OrangeWool), + 107u32 => Some(crate::Item::OxeyeDaisy), + 300u32 => Some(crate::Item::PackedIce), + 538u32 => Some(crate::Item::Painting), + 561u32 => Some(crate::Item::Paper), + 662u32 => Some(crate::Item::ParrotSpawnEgg), + 308u32 => Some(crate::Item::Peony), + 120u32 => Some(crate::Item::PetrifiedOakSlab), + 787u32 => Some(crate::Item::PhantomMembrane), + 663u32 => Some(crate::Item::PhantomSpawnEgg), + 664u32 => Some(crate::Item::PigSpawnEgg), + 741u32 => Some(crate::Item::PinkBanner), + 602u32 => Some(crate::Item::PinkBed), + 288u32 => Some(crate::Item::PinkCarpet), + 401u32 => Some(crate::Item::PinkConcrete), + 417u32 => Some(crate::Item::PinkConcretePowder), + 586u32 => Some(crate::Item::PinkDye), + 385u32 => Some(crate::Item::PinkGlazedTerracotta), + 369u32 => Some(crate::Item::PinkShulkerBox), + 317u32 => Some(crate::Item::PinkStainedGlass), + 333u32 => Some(crate::Item::PinkStainedGlassPane), + 269u32 => Some(crate::Item::PinkTerracotta), + 106u32 => Some(crate::Item::PinkTulip), + 88u32 => Some(crate::Item::PinkWool), + 81u32 => Some(crate::Item::Piston), + 705u32 => Some(crate::Item::PlayerHead), + 11u32 => Some(crate::Item::Podzol), + 700u32 => Some(crate::Item::PoisonousPotato), + 665u32 => Some(crate::Item::PolarBearSpawnEgg), + 7u32 => Some(crate::Item::PolishedAndesite), + 5u32 => Some(crate::Item::PolishedDiorite), + 3u32 => Some(crate::Item::PolishedGranite), + 753u32 => Some(crate::Item::PoppedChorusFruit), + 99u32 => Some(crate::Item::Poppy), + 536u32 => Some(crate::Item::Porkchop), + 698u32 => Some(crate::Item::Potato), + 629u32 => Some(crate::Item::Potion), + 72u32 => Some(crate::Item::PoweredRail), + 343u32 => Some(crate::Item::Prismarine), + 129u32 => Some(crate::Item::PrismarineBrickSlab), + 347u32 => Some(crate::Item::PrismarineBrickStairs), + 344u32 => Some(crate::Item::PrismarineBricks), + 720u32 => Some(crate::Item::PrismarineCrystals), + 719u32 => Some(crate::Item::PrismarineShard), + 128u32 => Some(crate::Item::PrismarineSlab), + 346u32 => Some(crate::Item::PrismarineStairs), + 574u32 => Some(crate::Item::Pufferfish), + 552u32 => Some(crate::Item::PufferfishBucket), + 666u32 => Some(crate::Item::PufferfishSpawnEgg), + 181u32 => Some(crate::Item::Pumpkin), + 711u32 => Some(crate::Item::PumpkinPie), + 617u32 => Some(crate::Item::PumpkinSeeds), + 745u32 => Some(crate::Item::PurpleBanner), + 606u32 => Some(crate::Item::PurpleBed), + 292u32 => Some(crate::Item::PurpleCarpet), + 405u32 => Some(crate::Item::PurpleConcrete), + 421u32 => Some(crate::Item::PurpleConcretePowder), + 582u32 => Some(crate::Item::PurpleDye), + 389u32 => Some(crate::Item::PurpleGlazedTerracotta), + 373u32 => Some(crate::Item::PurpleShulkerBox), + 321u32 => Some(crate::Item::PurpleStainedGlass), + 337u32 => Some(crate::Item::PurpleStainedGlassPane), + 273u32 => Some(crate::Item::PurpleTerracotta), + 92u32 => Some(crate::Item::PurpleWool), + 144u32 => Some(crate::Item::PurpurBlock), + 145u32 => Some(crate::Item::PurpurPillar), + 127u32 => Some(crate::Item::PurpurSlab), + 146u32 => Some(crate::Item::PurpurStairs), + 716u32 => Some(crate::Item::Quartz), + 258u32 => Some(crate::Item::QuartzBlock), + 259u32 => Some(crate::Item::QuartzPillar), + 125u32 => Some(crate::Item::QuartzSlab), + 260u32 => Some(crate::Item::QuartzStairs), + 721u32 => Some(crate::Item::Rabbit), + 724u32 => Some(crate::Item::RabbitFoot), + 725u32 => Some(crate::Item::RabbitHide), + 667u32 => Some(crate::Item::RabbitSpawnEgg), + 723u32 => Some(crate::Item::RabbitStew), + 156u32 => Some(crate::Item::Rail), + 749u32 => Some(crate::Item::RedBanner), + 610u32 => Some(crate::Item::RedBed), + 296u32 => Some(crate::Item::RedCarpet), + 409u32 => Some(crate::Item::RedConcrete), + 425u32 => Some(crate::Item::RedConcretePowder), + 393u32 => Some(crate::Item::RedGlazedTerracotta), + 109u32 => Some(crate::Item::RedMushroom), + 204u32 => Some(crate::Item::RedMushroomBlock), + 358u32 => Some(crate::Item::RedNetherBricks), + 27u32 => Some(crate::Item::RedSand), + 350u32 => Some(crate::Item::RedSandstone), + 126u32 => Some(crate::Item::RedSandstoneSlab), + 353u32 => Some(crate::Item::RedSandstoneStairs), + 377u32 => Some(crate::Item::RedShulkerBox), + 325u32 => Some(crate::Item::RedStainedGlass), + 341u32 => Some(crate::Item::RedStainedGlassPane), + 277u32 => Some(crate::Item::RedTerracotta), + 103u32 => Some(crate::Item::RedTulip), + 96u32 => Some(crate::Item::RedWool), + 547u32 => Some(crate::Item::Redstone), + 254u32 => Some(crate::Item::RedstoneBlock), + 228u32 => Some(crate::Item::RedstoneLamp), + 166u32 => Some(crate::Item::RedstoneOre), + 167u32 => Some(crate::Item::RedstoneTorch), + 467u32 => Some(crate::Item::Repeater), + 354u32 => Some(crate::Item::RepeatingCommandBlock), + 307u32 => Some(crate::Item::RoseBush), + 578u32 => Some(crate::Item::RoseRed), + 623u32 => Some(crate::Item::RottenFlesh), + 546u32 => Some(crate::Item::Saddle), + 572u32 => Some(crate::Item::Salmon), + 553u32 => Some(crate::Item::SalmonBucket), + 668u32 => Some(crate::Item::SalmonSpawnEgg), + 26u32 => Some(crate::Item::Sand), + 68u32 => Some(crate::Item::Sandstone), + 119u32 => Some(crate::Item::SandstoneSlab), + 229u32 => Some(crate::Item::SandstoneStairs), + 471u32 => Some(crate::Item::Scute), + 349u32 => Some(crate::Item::SeaLantern), + 80u32 => Some(crate::Item::SeaPickle), + 79u32 => Some(crate::Item::Seagrass), + 614u32 => Some(crate::Item::Shears), + 669u32 => Some(crate::Item::SheepSpawnEgg), + 762u32 => Some(crate::Item::Shield), + 362u32 => Some(crate::Item::ShulkerBox), + 770u32 => Some(crate::Item::ShulkerShell), + 670u32 => Some(crate::Item::ShulkerSpawnEgg), + 541u32 => Some(crate::Item::Sign), + 671u32 => Some(crate::Item::SilverfishSpawnEgg), + 673u32 => Some(crate::Item::SkeletonHorseSpawnEgg), + 703u32 => Some(crate::Item::SkeletonSkull), + 672u32 => Some(crate::Item::SkeletonSpawnEgg), + 563u32 => Some(crate::Item::SlimeBall), + 303u32 => Some(crate::Item::SlimeBlock), + 674u32 => Some(crate::Item::SlimeSpawnEgg), + 131u32 => Some(crate::Item::SmoothQuartz), + 132u32 => Some(crate::Item::SmoothRedSandstone), + 133u32 => Some(crate::Item::SmoothSandstone), + 134u32 => Some(crate::Item::SmoothStone), + 169u32 => Some(crate::Item::Snow), + 171u32 => Some(crate::Item::SnowBlock), + 548u32 => Some(crate::Item::Snowball), + 184u32 => Some(crate::Item::SoulSand), + 147u32 => Some(crate::Item::Spawner), + 759u32 => Some(crate::Item::SpectralArrow), + 631u32 => Some(crate::Item::SpiderEye), + 675u32 => Some(crate::Item::SpiderSpawnEgg), + 758u32 => Some(crate::Item::SplashPotion), + 62u32 => Some(crate::Item::Sponge), + 764u32 => Some(crate::Item::SpruceBoat), + 242u32 => Some(crate::Item::SpruceButton), + 462u32 => Some(crate::Item::SpruceDoor), + 176u32 => Some(crate::Item::SpruceFence), + 211u32 => Some(crate::Item::SpruceFenceGate), + 57u32 => Some(crate::Item::SpruceLeaves), + 33u32 => Some(crate::Item::SpruceLog), + 14u32 => Some(crate::Item::SprucePlanks), + 161u32 => Some(crate::Item::SprucePressurePlate), + 20u32 => Some(crate::Item::SpruceSapling), + 113u32 => Some(crate::Item::SpruceSlab), + 234u32 => Some(crate::Item::SpruceStairs), + 188u32 => Some(crate::Item::SpruceTrapdoor), + 51u32 => Some(crate::Item::SpruceWood), + 676u32 => Some(crate::Item::SquidSpawnEgg), + 497u32 => Some(crate::Item::Stick), + 74u32 => Some(crate::Item::StickyPiston), + 1u32 => Some(crate::Item::Stone), + 492u32 => Some(crate::Item::StoneAxe), + 123u32 => Some(crate::Item::StoneBrickSlab), + 217u32 => Some(crate::Item::StoneBrickStairs), + 199u32 => Some(crate::Item::StoneBricks), + 168u32 => Some(crate::Item::StoneButton), + 508u32 => Some(crate::Item::StoneHoe), + 491u32 => Some(crate::Item::StonePickaxe), + 159u32 => Some(crate::Item::StonePressurePlate), + 490u32 => Some(crate::Item::StoneShovel), + 118u32 => Some(crate::Item::StoneSlab), + 489u32 => Some(crate::Item::StoneSword), + 677u32 => Some(crate::Item::StraySpawnEgg), + 504u32 => Some(crate::Item::String), + 42u32 => Some(crate::Item::StrippedAcaciaLog), + 48u32 => Some(crate::Item::StrippedAcaciaWood), + 40u32 => Some(crate::Item::StrippedBirchLog), + 46u32 => Some(crate::Item::StrippedBirchWood), + 43u32 => Some(crate::Item::StrippedDarkOakLog), + 49u32 => Some(crate::Item::StrippedDarkOakWood), + 41u32 => Some(crate::Item::StrippedJungleLog), + 47u32 => Some(crate::Item::StrippedJungleWood), + 38u32 => Some(crate::Item::StrippedOakLog), + 44u32 => Some(crate::Item::StrippedOakWood), + 39u32 => Some(crate::Item::StrippedSpruceLog), + 45u32 => Some(crate::Item::StrippedSpruceWood), + 469u32 => Some(crate::Item::StructureBlock), + 360u32 => Some(crate::Item::StructureVoid), + 594u32 => Some(crate::Item::Sugar), + 558u32 => Some(crate::Item::SugarCane), + 305u32 => Some(crate::Item::Sunflower), + 309u32 => Some(crate::Item::TallGrass), + 298u32 => Some(crate::Item::Terracotta), + 760u32 => Some(crate::Item::TippedArrow), + 136u32 => Some(crate::Item::Tnt), + 717u32 => Some(crate::Item::TntMinecart), + 140u32 => Some(crate::Item::Torch), + 769u32 => Some(crate::Item::TotemOfUndying), + 250u32 => Some(crate::Item::TrappedChest), + 786u32 => Some(crate::Item::Trident), + 232u32 => Some(crate::Item::TripwireHook), + 573u32 => Some(crate::Item::TropicalFish), + 555u32 => Some(crate::Item::TropicalFishBucket), + 678u32 => Some(crate::Item::TropicalFishSpawnEgg), + 438u32 => Some(crate::Item::TubeCoral), + 433u32 => Some(crate::Item::TubeCoralBlock), + 448u32 => Some(crate::Item::TubeCoralFan), + 427u32 => Some(crate::Item::TurtleEgg), + 470u32 => Some(crate::Item::TurtleHelmet), + 679u32 => Some(crate::Item::TurtleSpawnEgg), + 680u32 => Some(crate::Item::VexSpawnEgg), + 681u32 => Some(crate::Item::VillagerSpawnEgg), + 682u32 => Some(crate::Item::VindicatorSpawnEgg), + 209u32 => Some(crate::Item::Vine), + 543u32 => Some(crate::Item::WaterBucket), + 63u32 => Some(crate::Item::WetSponge), + 513u32 => Some(crate::Item::Wheat), + 512u32 => Some(crate::Item::WheatSeeds), + 735u32 => Some(crate::Item::WhiteBanner), + 596u32 => Some(crate::Item::WhiteBed), + 282u32 => Some(crate::Item::WhiteCarpet), + 395u32 => Some(crate::Item::WhiteConcrete), + 411u32 => Some(crate::Item::WhiteConcretePowder), + 379u32 => Some(crate::Item::WhiteGlazedTerracotta), + 363u32 => Some(crate::Item::WhiteShulkerBox), + 311u32 => Some(crate::Item::WhiteStainedGlass), + 327u32 => Some(crate::Item::WhiteStainedGlassPane), + 263u32 => Some(crate::Item::WhiteTerracotta), + 105u32 => Some(crate::Item::WhiteTulip), + 82u32 => Some(crate::Item::WhiteWool), + 683u32 => Some(crate::Item::WitchSpawnEgg), + 704u32 => Some(crate::Item::WitherSkeletonSkull), + 684u32 => Some(crate::Item::WitherSkeletonSpawnEgg), + 685u32 => Some(crate::Item::WolfSpawnEgg), + 488u32 => Some(crate::Item::WoodenAxe), + 507u32 => Some(crate::Item::WoodenHoe), + 487u32 => Some(crate::Item::WoodenPickaxe), + 486u32 => Some(crate::Item::WoodenShovel), + 485u32 => Some(crate::Item::WoodenSword), + 692u32 => Some(crate::Item::WritableBook), + 693u32 => Some(crate::Item::WrittenBook), + 739u32 => Some(crate::Item::YellowBanner), + 600u32 => Some(crate::Item::YellowBed), + 286u32 => Some(crate::Item::YellowCarpet), + 399u32 => Some(crate::Item::YellowConcrete), + 415u32 => Some(crate::Item::YellowConcretePowder), + 383u32 => Some(crate::Item::YellowGlazedTerracotta), + 367u32 => Some(crate::Item::YellowShulkerBox), + 315u32 => Some(crate::Item::YellowStainedGlass), + 331u32 => Some(crate::Item::YellowStainedGlassPane), + 267u32 => Some(crate::Item::YellowTerracotta), + 86u32 => Some(crate::Item::YellowWool), + 706u32 => Some(crate::Item::ZombieHead), + 687u32 => Some(crate::Item::ZombieHorseSpawnEgg), + 688u32 => Some(crate::Item::ZombiePigmanSpawnEgg), + 686u32 => Some(crate::Item::ZombieSpawnEgg), + 689u32 => Some(crate::Item::ZombieVillagerSpawnEgg), + _ => None, + } + } +} +impl crate::Item { + pub fn identifier(self) -> &'static str { + match self { + crate::Item::AcaciaBoat => "minecraft:acacia_boat", + crate::Item::AcaciaButton => "minecraft:acacia_button", + crate::Item::AcaciaDoor => "minecraft:acacia_door", + crate::Item::AcaciaFence => "minecraft:acacia_fence", + crate::Item::AcaciaFenceGate => "minecraft:acacia_fence_gate", + crate::Item::AcaciaLeaves => "minecraft:acacia_leaves", + crate::Item::AcaciaLog => "minecraft:acacia_log", + crate::Item::AcaciaPlanks => "minecraft:acacia_planks", + crate::Item::AcaciaPressurePlate => "minecraft:acacia_pressure_plate", + crate::Item::AcaciaSapling => "minecraft:acacia_sapling", + crate::Item::AcaciaSlab => "minecraft:acacia_slab", + crate::Item::AcaciaStairs => "minecraft:acacia_stairs", + crate::Item::AcaciaTrapdoor => "minecraft:acacia_trapdoor", + crate::Item::AcaciaWood => "minecraft:acacia_wood", + crate::Item::ActivatorRail => "minecraft:activator_rail", + crate::Item::Air => "minecraft:air", + crate::Item::Allium => "minecraft:allium", + crate::Item::Andesite => "minecraft:andesite", + crate::Item::Anvil => "minecraft:anvil", + crate::Item::Apple => "minecraft:apple", + crate::Item::ArmorStand => "minecraft:armor_stand", + crate::Item::Arrow => "minecraft:arrow", + crate::Item::AzureBluet => "minecraft:azure_bluet", + crate::Item::BakedPotato => "minecraft:baked_potato", + crate::Item::Barrier => "minecraft:barrier", + crate::Item::BatSpawnEgg => "minecraft:bat_spawn_egg", + crate::Item::Beacon => "minecraft:beacon", + crate::Item::Bedrock => "minecraft:bedrock", + crate::Item::Beef => "minecraft:beef", + crate::Item::Beetroot => "minecraft:beetroot", + crate::Item::BeetrootSeeds => "minecraft:beetroot_seeds", + crate::Item::BeetrootSoup => "minecraft:beetroot_soup", + crate::Item::BirchBoat => "minecraft:birch_boat", + crate::Item::BirchButton => "minecraft:birch_button", + crate::Item::BirchDoor => "minecraft:birch_door", + crate::Item::BirchFence => "minecraft:birch_fence", + crate::Item::BirchFenceGate => "minecraft:birch_fence_gate", + crate::Item::BirchLeaves => "minecraft:birch_leaves", + crate::Item::BirchLog => "minecraft:birch_log", + crate::Item::BirchPlanks => "minecraft:birch_planks", + crate::Item::BirchPressurePlate => "minecraft:birch_pressure_plate", + crate::Item::BirchSapling => "minecraft:birch_sapling", + crate::Item::BirchSlab => "minecraft:birch_slab", + crate::Item::BirchStairs => "minecraft:birch_stairs", + crate::Item::BirchTrapdoor => "minecraft:birch_trapdoor", + crate::Item::BirchWood => "minecraft:birch_wood", + crate::Item::BlackBanner => "minecraft:black_banner", + crate::Item::BlackBed => "minecraft:black_bed", + crate::Item::BlackCarpet => "minecraft:black_carpet", + crate::Item::BlackConcrete => "minecraft:black_concrete", + crate::Item::BlackConcretePowder => "minecraft:black_concrete_powder", + crate::Item::BlackGlazedTerracotta => "minecraft:black_glazed_terracotta", + crate::Item::BlackShulkerBox => "minecraft:black_shulker_box", + crate::Item::BlackStainedGlass => "minecraft:black_stained_glass", + crate::Item::BlackStainedGlassPane => "minecraft:black_stained_glass_pane", + crate::Item::BlackTerracotta => "minecraft:black_terracotta", + crate::Item::BlackWool => "minecraft:black_wool", + crate::Item::BlazePowder => "minecraft:blaze_powder", + crate::Item::BlazeRod => "minecraft:blaze_rod", + crate::Item::BlazeSpawnEgg => "minecraft:blaze_spawn_egg", + crate::Item::BlueBanner => "minecraft:blue_banner", + crate::Item::BlueBed => "minecraft:blue_bed", + crate::Item::BlueCarpet => "minecraft:blue_carpet", + crate::Item::BlueConcrete => "minecraft:blue_concrete", + crate::Item::BlueConcretePowder => "minecraft:blue_concrete_powder", + crate::Item::BlueGlazedTerracotta => "minecraft:blue_glazed_terracotta", + crate::Item::BlueIce => "minecraft:blue_ice", + crate::Item::BlueOrchid => "minecraft:blue_orchid", + crate::Item::BlueShulkerBox => "minecraft:blue_shulker_box", + crate::Item::BlueStainedGlass => "minecraft:blue_stained_glass", + crate::Item::BlueStainedGlassPane => "minecraft:blue_stained_glass_pane", + crate::Item::BlueTerracotta => "minecraft:blue_terracotta", + crate::Item::BlueWool => "minecraft:blue_wool", + crate::Item::Bone => "minecraft:bone", + crate::Item::BoneBlock => "minecraft:bone_block", + crate::Item::BoneMeal => "minecraft:bone_meal", + crate::Item::Book => "minecraft:book", + crate::Item::Bookshelf => "minecraft:bookshelf", + crate::Item::Bow => "minecraft:bow", + crate::Item::Bowl => "minecraft:bowl", + crate::Item::BrainCoral => "minecraft:brain_coral", + crate::Item::BrainCoralBlock => "minecraft:brain_coral_block", + crate::Item::BrainCoralFan => "minecraft:brain_coral_fan", + crate::Item::Bread => "minecraft:bread", + crate::Item::BrewingStand => "minecraft:brewing_stand", + crate::Item::Brick => "minecraft:brick", + crate::Item::BrickSlab => "minecraft:brick_slab", + crate::Item::BrickStairs => "minecraft:brick_stairs", + crate::Item::Bricks => "minecraft:bricks", + crate::Item::BrownBanner => "minecraft:brown_banner", + crate::Item::BrownBed => "minecraft:brown_bed", + crate::Item::BrownCarpet => "minecraft:brown_carpet", + crate::Item::BrownConcrete => "minecraft:brown_concrete", + crate::Item::BrownConcretePowder => "minecraft:brown_concrete_powder", + crate::Item::BrownGlazedTerracotta => "minecraft:brown_glazed_terracotta", + crate::Item::BrownMushroom => "minecraft:brown_mushroom", + crate::Item::BrownMushroomBlock => "minecraft:brown_mushroom_block", + crate::Item::BrownShulkerBox => "minecraft:brown_shulker_box", + crate::Item::BrownStainedGlass => "minecraft:brown_stained_glass", + crate::Item::BrownStainedGlassPane => "minecraft:brown_stained_glass_pane", + crate::Item::BrownTerracotta => "minecraft:brown_terracotta", + crate::Item::BrownWool => "minecraft:brown_wool", + crate::Item::BubbleCoral => "minecraft:bubble_coral", + crate::Item::BubbleCoralBlock => "minecraft:bubble_coral_block", + crate::Item::BubbleCoralFan => "minecraft:bubble_coral_fan", + crate::Item::Bucket => "minecraft:bucket", + crate::Item::Cactus => "minecraft:cactus", + crate::Item::CactusGreen => "minecraft:cactus_green", + crate::Item::Cake => "minecraft:cake", + crate::Item::Carrot => "minecraft:carrot", + crate::Item::CarrotOnAStick => "minecraft:carrot_on_a_stick", + crate::Item::CarvedPumpkin => "minecraft:carved_pumpkin", + crate::Item::Cauldron => "minecraft:cauldron", + crate::Item::CaveSpiderSpawnEgg => "minecraft:cave_spider_spawn_egg", + crate::Item::ChainCommandBlock => "minecraft:chain_command_block", + crate::Item::ChainmailBoots => "minecraft:chainmail_boots", + crate::Item::ChainmailChestplate => "minecraft:chainmail_chestplate", + crate::Item::ChainmailHelmet => "minecraft:chainmail_helmet", + crate::Item::ChainmailLeggings => "minecraft:chainmail_leggings", + crate::Item::Charcoal => "minecraft:charcoal", + crate::Item::Chest => "minecraft:chest", + crate::Item::ChestMinecart => "minecraft:chest_minecart", + crate::Item::Chicken => "minecraft:chicken", + crate::Item::ChickenSpawnEgg => "minecraft:chicken_spawn_egg", + crate::Item::ChippedAnvil => "minecraft:chipped_anvil", + crate::Item::ChiseledQuartzBlock => "minecraft:chiseled_quartz_block", + crate::Item::ChiseledRedSandstone => "minecraft:chiseled_red_sandstone", + crate::Item::ChiseledSandstone => "minecraft:chiseled_sandstone", + crate::Item::ChiseledStoneBricks => "minecraft:chiseled_stone_bricks", + crate::Item::ChorusFlower => "minecraft:chorus_flower", + crate::Item::ChorusFruit => "minecraft:chorus_fruit", + crate::Item::ChorusPlant => "minecraft:chorus_plant", + crate::Item::Clay => "minecraft:clay", + crate::Item::ClayBall => "minecraft:clay_ball", + crate::Item::Clock => "minecraft:clock", + crate::Item::Coal => "minecraft:coal", + crate::Item::CoalBlock => "minecraft:coal_block", + crate::Item::CoalOre => "minecraft:coal_ore", + crate::Item::CoarseDirt => "minecraft:coarse_dirt", + crate::Item::Cobblestone => "minecraft:cobblestone", + crate::Item::CobblestoneSlab => "minecraft:cobblestone_slab", + crate::Item::CobblestoneStairs => "minecraft:cobblestone_stairs", + crate::Item::CobblestoneWall => "minecraft:cobblestone_wall", + crate::Item::Cobweb => "minecraft:cobweb", + crate::Item::CocoaBeans => "minecraft:cocoa_beans", + crate::Item::Cod => "minecraft:cod", + crate::Item::CodBucket => "minecraft:cod_bucket", + crate::Item::CodSpawnEgg => "minecraft:cod_spawn_egg", + crate::Item::CommandBlock => "minecraft:command_block", + crate::Item::CommandBlockMinecart => "minecraft:command_block_minecart", + crate::Item::Comparator => "minecraft:comparator", + crate::Item::Compass => "minecraft:compass", + crate::Item::Conduit => "minecraft:conduit", + crate::Item::CookedBeef => "minecraft:cooked_beef", + crate::Item::CookedChicken => "minecraft:cooked_chicken", + crate::Item::CookedCod => "minecraft:cooked_cod", + crate::Item::CookedMutton => "minecraft:cooked_mutton", + crate::Item::CookedPorkchop => "minecraft:cooked_porkchop", + crate::Item::CookedRabbit => "minecraft:cooked_rabbit", + crate::Item::CookedSalmon => "minecraft:cooked_salmon", + crate::Item::Cookie => "minecraft:cookie", + crate::Item::CowSpawnEgg => "minecraft:cow_spawn_egg", + crate::Item::CrackedStoneBricks => "minecraft:cracked_stone_bricks", + crate::Item::CraftingTable => "minecraft:crafting_table", + crate::Item::CreeperHead => "minecraft:creeper_head", + crate::Item::CreeperSpawnEgg => "minecraft:creeper_spawn_egg", + crate::Item::CutRedSandstone => "minecraft:cut_red_sandstone", + crate::Item::CutSandstone => "minecraft:cut_sandstone", + crate::Item::CyanBanner => "minecraft:cyan_banner", + crate::Item::CyanBed => "minecraft:cyan_bed", + crate::Item::CyanCarpet => "minecraft:cyan_carpet", + crate::Item::CyanConcrete => "minecraft:cyan_concrete", + crate::Item::CyanConcretePowder => "minecraft:cyan_concrete_powder", + crate::Item::CyanDye => "minecraft:cyan_dye", + crate::Item::CyanGlazedTerracotta => "minecraft:cyan_glazed_terracotta", + crate::Item::CyanShulkerBox => "minecraft:cyan_shulker_box", + crate::Item::CyanStainedGlass => "minecraft:cyan_stained_glass", + crate::Item::CyanStainedGlassPane => "minecraft:cyan_stained_glass_pane", + crate::Item::CyanTerracotta => "minecraft:cyan_terracotta", + crate::Item::CyanWool => "minecraft:cyan_wool", + crate::Item::DamagedAnvil => "minecraft:damaged_anvil", + crate::Item::Dandelion => "minecraft:dandelion", + crate::Item::DandelionYellow => "minecraft:dandelion_yellow", + crate::Item::DarkOakBoat => "minecraft:dark_oak_boat", + crate::Item::DarkOakButton => "minecraft:dark_oak_button", + crate::Item::DarkOakDoor => "minecraft:dark_oak_door", + crate::Item::DarkOakFence => "minecraft:dark_oak_fence", + crate::Item::DarkOakFenceGate => "minecraft:dark_oak_fence_gate", + crate::Item::DarkOakLeaves => "minecraft:dark_oak_leaves", + crate::Item::DarkOakLog => "minecraft:dark_oak_log", + crate::Item::DarkOakPlanks => "minecraft:dark_oak_planks", + crate::Item::DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate", + crate::Item::DarkOakSapling => "minecraft:dark_oak_sapling", + crate::Item::DarkOakSlab => "minecraft:dark_oak_slab", + crate::Item::DarkOakStairs => "minecraft:dark_oak_stairs", + crate::Item::DarkOakTrapdoor => "minecraft:dark_oak_trapdoor", + crate::Item::DarkOakWood => "minecraft:dark_oak_wood", + crate::Item::DarkPrismarine => "minecraft:dark_prismarine", + crate::Item::DarkPrismarineSlab => "minecraft:dark_prismarine_slab", + crate::Item::DarkPrismarineStairs => "minecraft:dark_prismarine_stairs", + crate::Item::DaylightDetector => "minecraft:daylight_detector", + crate::Item::DeadBrainCoral => "minecraft:dead_brain_coral", + crate::Item::DeadBrainCoralBlock => "minecraft:dead_brain_coral_block", + crate::Item::DeadBrainCoralFan => "minecraft:dead_brain_coral_fan", + crate::Item::DeadBubbleCoral => "minecraft:dead_bubble_coral", + crate::Item::DeadBubbleCoralBlock => "minecraft:dead_bubble_coral_block", + crate::Item::DeadBubbleCoralFan => "minecraft:dead_bubble_coral_fan", + crate::Item::DeadBush => "minecraft:dead_bush", + crate::Item::DeadFireCoral => "minecraft:dead_fire_coral", + crate::Item::DeadFireCoralBlock => "minecraft:dead_fire_coral_block", + crate::Item::DeadFireCoralFan => "minecraft:dead_fire_coral_fan", + crate::Item::DeadHornCoral => "minecraft:dead_horn_coral", + crate::Item::DeadHornCoralBlock => "minecraft:dead_horn_coral_block", + crate::Item::DeadHornCoralFan => "minecraft:dead_horn_coral_fan", + crate::Item::DeadTubeCoral => "minecraft:dead_tube_coral", + crate::Item::DeadTubeCoralBlock => "minecraft:dead_tube_coral_block", + crate::Item::DeadTubeCoralFan => "minecraft:dead_tube_coral_fan", + crate::Item::DebugStick => "minecraft:debug_stick", + crate::Item::DetectorRail => "minecraft:detector_rail", + crate::Item::Diamond => "minecraft:diamond", + crate::Item::DiamondAxe => "minecraft:diamond_axe", + crate::Item::DiamondBlock => "minecraft:diamond_block", + crate::Item::DiamondBoots => "minecraft:diamond_boots", + crate::Item::DiamondChestplate => "minecraft:diamond_chestplate", + crate::Item::DiamondHelmet => "minecraft:diamond_helmet", + crate::Item::DiamondHoe => "minecraft:diamond_hoe", + crate::Item::DiamondHorseArmor => "minecraft:diamond_horse_armor", + crate::Item::DiamondLeggings => "minecraft:diamond_leggings", + crate::Item::DiamondOre => "minecraft:diamond_ore", + crate::Item::DiamondPickaxe => "minecraft:diamond_pickaxe", + crate::Item::DiamondShovel => "minecraft:diamond_shovel", + crate::Item::DiamondSword => "minecraft:diamond_sword", + crate::Item::Diorite => "minecraft:diorite", + crate::Item::Dirt => "minecraft:dirt", + crate::Item::Dispenser => "minecraft:dispenser", + crate::Item::DolphinSpawnEgg => "minecraft:dolphin_spawn_egg", + crate::Item::DonkeySpawnEgg => "minecraft:donkey_spawn_egg", + crate::Item::DragonBreath => "minecraft:dragon_breath", + crate::Item::DragonEgg => "minecraft:dragon_egg", + crate::Item::DragonHead => "minecraft:dragon_head", + crate::Item::DriedKelp => "minecraft:dried_kelp", + crate::Item::DriedKelpBlock => "minecraft:dried_kelp_block", + crate::Item::Dropper => "minecraft:dropper", + crate::Item::DrownedSpawnEgg => "minecraft:drowned_spawn_egg", + crate::Item::Egg => "minecraft:egg", + crate::Item::ElderGuardianSpawnEgg => "minecraft:elder_guardian_spawn_egg", + crate::Item::Elytra => "minecraft:elytra", + crate::Item::Emerald => "minecraft:emerald", + crate::Item::EmeraldBlock => "minecraft:emerald_block", + crate::Item::EmeraldOre => "minecraft:emerald_ore", + crate::Item::EnchantedBook => "minecraft:enchanted_book", + crate::Item::EnchantedGoldenApple => "minecraft:enchanted_golden_apple", + crate::Item::EnchantingTable => "minecraft:enchanting_table", + crate::Item::EndCrystal => "minecraft:end_crystal", + crate::Item::EndPortalFrame => "minecraft:end_portal_frame", + crate::Item::EndRod => "minecraft:end_rod", + crate::Item::EndStone => "minecraft:end_stone", + crate::Item::EndStoneBricks => "minecraft:end_stone_bricks", + crate::Item::EnderChest => "minecraft:ender_chest", + crate::Item::EnderEye => "minecraft:ender_eye", + crate::Item::EnderPearl => "minecraft:ender_pearl", + crate::Item::EndermanSpawnEgg => "minecraft:enderman_spawn_egg", + crate::Item::EndermiteSpawnEgg => "minecraft:endermite_spawn_egg", + crate::Item::EvokerSpawnEgg => "minecraft:evoker_spawn_egg", + crate::Item::ExperienceBottle => "minecraft:experience_bottle", + crate::Item::Farmland => "minecraft:farmland", + crate::Item::Feather => "minecraft:feather", + crate::Item::FermentedSpiderEye => "minecraft:fermented_spider_eye", + crate::Item::Fern => "minecraft:fern", + crate::Item::FilledMap => "minecraft:filled_map", + crate::Item::FireCharge => "minecraft:fire_charge", + crate::Item::FireCoral => "minecraft:fire_coral", + crate::Item::FireCoralBlock => "minecraft:fire_coral_block", + crate::Item::FireCoralFan => "minecraft:fire_coral_fan", + crate::Item::FireworkRocket => "minecraft:firework_rocket", + crate::Item::FireworkStar => "minecraft:firework_star", + crate::Item::FishingRod => "minecraft:fishing_rod", + crate::Item::Flint => "minecraft:flint", + crate::Item::FlintAndSteel => "minecraft:flint_and_steel", + crate::Item::FlowerPot => "minecraft:flower_pot", + crate::Item::Furnace => "minecraft:furnace", + crate::Item::FurnaceMinecart => "minecraft:furnace_minecart", + crate::Item::GhastSpawnEgg => "minecraft:ghast_spawn_egg", + crate::Item::GhastTear => "minecraft:ghast_tear", + crate::Item::Glass => "minecraft:glass", + crate::Item::GlassBottle => "minecraft:glass_bottle", + crate::Item::GlassPane => "minecraft:glass_pane", + crate::Item::GlisteringMelonSlice => "minecraft:glistering_melon_slice", + crate::Item::Glowstone => "minecraft:glowstone", + crate::Item::GlowstoneDust => "minecraft:glowstone_dust", + crate::Item::GoldBlock => "minecraft:gold_block", + crate::Item::GoldIngot => "minecraft:gold_ingot", + crate::Item::GoldNugget => "minecraft:gold_nugget", + crate::Item::GoldOre => "minecraft:gold_ore", + crate::Item::GoldenApple => "minecraft:golden_apple", + crate::Item::GoldenAxe => "minecraft:golden_axe", + crate::Item::GoldenBoots => "minecraft:golden_boots", + crate::Item::GoldenCarrot => "minecraft:golden_carrot", + crate::Item::GoldenChestplate => "minecraft:golden_chestplate", + crate::Item::GoldenHelmet => "minecraft:golden_helmet", + crate::Item::GoldenHoe => "minecraft:golden_hoe", + crate::Item::GoldenHorseArmor => "minecraft:golden_horse_armor", + crate::Item::GoldenLeggings => "minecraft:golden_leggings", + crate::Item::GoldenPickaxe => "minecraft:golden_pickaxe", + crate::Item::GoldenShovel => "minecraft:golden_shovel", + crate::Item::GoldenSword => "minecraft:golden_sword", + crate::Item::Granite => "minecraft:granite", + crate::Item::Grass => "minecraft:grass", + crate::Item::GrassBlock => "minecraft:grass_block", + crate::Item::GrassPath => "minecraft:grass_path", + crate::Item::Gravel => "minecraft:gravel", + crate::Item::GrayBanner => "minecraft:gray_banner", + crate::Item::GrayBed => "minecraft:gray_bed", + crate::Item::GrayCarpet => "minecraft:gray_carpet", + crate::Item::GrayConcrete => "minecraft:gray_concrete", + crate::Item::GrayConcretePowder => "minecraft:gray_concrete_powder", + crate::Item::GrayDye => "minecraft:gray_dye", + crate::Item::GrayGlazedTerracotta => "minecraft:gray_glazed_terracotta", + crate::Item::GrayShulkerBox => "minecraft:gray_shulker_box", + crate::Item::GrayStainedGlass => "minecraft:gray_stained_glass", + crate::Item::GrayStainedGlassPane => "minecraft:gray_stained_glass_pane", + crate::Item::GrayTerracotta => "minecraft:gray_terracotta", + crate::Item::GrayWool => "minecraft:gray_wool", + crate::Item::GreenBanner => "minecraft:green_banner", + crate::Item::GreenBed => "minecraft:green_bed", + crate::Item::GreenCarpet => "minecraft:green_carpet", + crate::Item::GreenConcrete => "minecraft:green_concrete", + crate::Item::GreenConcretePowder => "minecraft:green_concrete_powder", + crate::Item::GreenGlazedTerracotta => "minecraft:green_glazed_terracotta", + crate::Item::GreenShulkerBox => "minecraft:green_shulker_box", + crate::Item::GreenStainedGlass => "minecraft:green_stained_glass", + crate::Item::GreenStainedGlassPane => "minecraft:green_stained_glass_pane", + crate::Item::GreenTerracotta => "minecraft:green_terracotta", + crate::Item::GreenWool => "minecraft:green_wool", + crate::Item::GuardianSpawnEgg => "minecraft:guardian_spawn_egg", + crate::Item::Gunpowder => "minecraft:gunpowder", + crate::Item::HayBlock => "minecraft:hay_block", + crate::Item::HeartOfTheSea => "minecraft:heart_of_the_sea", + crate::Item::HeavyWeightedPressurePlate => "minecraft:heavy_weighted_pressure_plate", + crate::Item::Hopper => "minecraft:hopper", + crate::Item::HopperMinecart => "minecraft:hopper_minecart", + crate::Item::HornCoral => "minecraft:horn_coral", + crate::Item::HornCoralBlock => "minecraft:horn_coral_block", + crate::Item::HornCoralFan => "minecraft:horn_coral_fan", + crate::Item::HorseSpawnEgg => "minecraft:horse_spawn_egg", + crate::Item::HuskSpawnEgg => "minecraft:husk_spawn_egg", + crate::Item::Ice => "minecraft:ice", + crate::Item::InfestedChiseledStoneBricks => "minecraft:infested_chiseled_stone_bricks", + crate::Item::InfestedCobblestone => "minecraft:infested_cobblestone", + crate::Item::InfestedCrackedStoneBricks => "minecraft:infested_cracked_stone_bricks", + crate::Item::InfestedMossyStoneBricks => "minecraft:infested_mossy_stone_bricks", + crate::Item::InfestedStone => "minecraft:infested_stone", + crate::Item::InfestedStoneBricks => "minecraft:infested_stone_bricks", + crate::Item::InkSac => "minecraft:ink_sac", + crate::Item::IronAxe => "minecraft:iron_axe", + crate::Item::IronBars => "minecraft:iron_bars", + crate::Item::IronBlock => "minecraft:iron_block", + crate::Item::IronBoots => "minecraft:iron_boots", + crate::Item::IronChestplate => "minecraft:iron_chestplate", + crate::Item::IronDoor => "minecraft:iron_door", + crate::Item::IronHelmet => "minecraft:iron_helmet", + crate::Item::IronHoe => "minecraft:iron_hoe", + crate::Item::IronHorseArmor => "minecraft:iron_horse_armor", + crate::Item::IronIngot => "minecraft:iron_ingot", + crate::Item::IronLeggings => "minecraft:iron_leggings", + crate::Item::IronNugget => "minecraft:iron_nugget", + crate::Item::IronOre => "minecraft:iron_ore", + crate::Item::IronPickaxe => "minecraft:iron_pickaxe", + crate::Item::IronShovel => "minecraft:iron_shovel", + crate::Item::IronSword => "minecraft:iron_sword", + crate::Item::IronTrapdoor => "minecraft:iron_trapdoor", + crate::Item::ItemFrame => "minecraft:item_frame", + crate::Item::JackOLantern => "minecraft:jack_o_lantern", + crate::Item::Jukebox => "minecraft:jukebox", + crate::Item::JungleBoat => "minecraft:jungle_boat", + crate::Item::JungleButton => "minecraft:jungle_button", + crate::Item::JungleDoor => "minecraft:jungle_door", + crate::Item::JungleFence => "minecraft:jungle_fence", + crate::Item::JungleFenceGate => "minecraft:jungle_fence_gate", + crate::Item::JungleLeaves => "minecraft:jungle_leaves", + crate::Item::JungleLog => "minecraft:jungle_log", + crate::Item::JunglePlanks => "minecraft:jungle_planks", + crate::Item::JunglePressurePlate => "minecraft:jungle_pressure_plate", + crate::Item::JungleSapling => "minecraft:jungle_sapling", + crate::Item::JungleSlab => "minecraft:jungle_slab", + crate::Item::JungleStairs => "minecraft:jungle_stairs", + crate::Item::JungleTrapdoor => "minecraft:jungle_trapdoor", + crate::Item::JungleWood => "minecraft:jungle_wood", + crate::Item::Kelp => "minecraft:kelp", + crate::Item::KnowledgeBook => "minecraft:knowledge_book", + crate::Item::Ladder => "minecraft:ladder", + crate::Item::LapisBlock => "minecraft:lapis_block", + crate::Item::LapisLazuli => "minecraft:lapis_lazuli", + crate::Item::LapisOre => "minecraft:lapis_ore", + crate::Item::LargeFern => "minecraft:large_fern", + crate::Item::LavaBucket => "minecraft:lava_bucket", + crate::Item::Lead => "minecraft:lead", + crate::Item::Leather => "minecraft:leather", + crate::Item::LeatherBoots => "minecraft:leather_boots", + crate::Item::LeatherChestplate => "minecraft:leather_chestplate", + crate::Item::LeatherHelmet => "minecraft:leather_helmet", + crate::Item::LeatherLeggings => "minecraft:leather_leggings", + crate::Item::Lever => "minecraft:lever", + crate::Item::LightBlueBanner => "minecraft:light_blue_banner", + crate::Item::LightBlueBed => "minecraft:light_blue_bed", + crate::Item::LightBlueCarpet => "minecraft:light_blue_carpet", + crate::Item::LightBlueConcrete => "minecraft:light_blue_concrete", + crate::Item::LightBlueConcretePowder => "minecraft:light_blue_concrete_powder", + crate::Item::LightBlueDye => "minecraft:light_blue_dye", + crate::Item::LightBlueGlazedTerracotta => "minecraft:light_blue_glazed_terracotta", + crate::Item::LightBlueShulkerBox => "minecraft:light_blue_shulker_box", + crate::Item::LightBlueStainedGlass => "minecraft:light_blue_stained_glass", + crate::Item::LightBlueStainedGlassPane => "minecraft:light_blue_stained_glass_pane", + crate::Item::LightBlueTerracotta => "minecraft:light_blue_terracotta", + crate::Item::LightBlueWool => "minecraft:light_blue_wool", + crate::Item::LightGrayBanner => "minecraft:light_gray_banner", + crate::Item::LightGrayBed => "minecraft:light_gray_bed", + crate::Item::LightGrayCarpet => "minecraft:light_gray_carpet", + crate::Item::LightGrayConcrete => "minecraft:light_gray_concrete", + crate::Item::LightGrayConcretePowder => "minecraft:light_gray_concrete_powder", + crate::Item::LightGrayDye => "minecraft:light_gray_dye", + crate::Item::LightGrayGlazedTerracotta => "minecraft:light_gray_glazed_terracotta", + crate::Item::LightGrayShulkerBox => "minecraft:light_gray_shulker_box", + crate::Item::LightGrayStainedGlass => "minecraft:light_gray_stained_glass", + crate::Item::LightGrayStainedGlassPane => "minecraft:light_gray_stained_glass_pane", + crate::Item::LightGrayTerracotta => "minecraft:light_gray_terracotta", + crate::Item::LightGrayWool => "minecraft:light_gray_wool", + crate::Item::LightWeightedPressurePlate => "minecraft:light_weighted_pressure_plate", + crate::Item::Lilac => "minecraft:lilac", + crate::Item::LilyPad => "minecraft:lily_pad", + crate::Item::LimeBanner => "minecraft:lime_banner", + crate::Item::LimeBed => "minecraft:lime_bed", + crate::Item::LimeCarpet => "minecraft:lime_carpet", + crate::Item::LimeConcrete => "minecraft:lime_concrete", + crate::Item::LimeConcretePowder => "minecraft:lime_concrete_powder", + crate::Item::LimeDye => "minecraft:lime_dye", + crate::Item::LimeGlazedTerracotta => "minecraft:lime_glazed_terracotta", + crate::Item::LimeShulkerBox => "minecraft:lime_shulker_box", + crate::Item::LimeStainedGlass => "minecraft:lime_stained_glass", + crate::Item::LimeStainedGlassPane => "minecraft:lime_stained_glass_pane", + crate::Item::LimeTerracotta => "minecraft:lime_terracotta", + crate::Item::LimeWool => "minecraft:lime_wool", + crate::Item::LingeringPotion => "minecraft:lingering_potion", + crate::Item::LlamaSpawnEgg => "minecraft:llama_spawn_egg", + crate::Item::MagentaBanner => "minecraft:magenta_banner", + crate::Item::MagentaBed => "minecraft:magenta_bed", + crate::Item::MagentaCarpet => "minecraft:magenta_carpet", + crate::Item::MagentaConcrete => "minecraft:magenta_concrete", + crate::Item::MagentaConcretePowder => "minecraft:magenta_concrete_powder", + crate::Item::MagentaDye => "minecraft:magenta_dye", + crate::Item::MagentaGlazedTerracotta => "minecraft:magenta_glazed_terracotta", + crate::Item::MagentaShulkerBox => "minecraft:magenta_shulker_box", + crate::Item::MagentaStainedGlass => "minecraft:magenta_stained_glass", + crate::Item::MagentaStainedGlassPane => "minecraft:magenta_stained_glass_pane", + crate::Item::MagentaTerracotta => "minecraft:magenta_terracotta", + crate::Item::MagentaWool => "minecraft:magenta_wool", + crate::Item::MagmaBlock => "minecraft:magma_block", + crate::Item::MagmaCream => "minecraft:magma_cream", + crate::Item::MagmaCubeSpawnEgg => "minecraft:magma_cube_spawn_egg", + crate::Item::Map => "minecraft:map", + crate::Item::Melon => "minecraft:melon", + crate::Item::MelonSeeds => "minecraft:melon_seeds", + crate::Item::MelonSlice => "minecraft:melon_slice", + crate::Item::MilkBucket => "minecraft:milk_bucket", + crate::Item::Minecart => "minecraft:minecart", + crate::Item::MooshroomSpawnEgg => "minecraft:mooshroom_spawn_egg", + crate::Item::MossyCobblestone => "minecraft:mossy_cobblestone", + crate::Item::MossyCobblestoneWall => "minecraft:mossy_cobblestone_wall", + crate::Item::MossyStoneBricks => "minecraft:mossy_stone_bricks", + crate::Item::MuleSpawnEgg => "minecraft:mule_spawn_egg", + crate::Item::MushroomStem => "minecraft:mushroom_stem", + crate::Item::MushroomStew => "minecraft:mushroom_stew", + crate::Item::MusicDisc11 => "minecraft:music_disc_11", + crate::Item::MusicDisc13 => "minecraft:music_disc_13", + crate::Item::MusicDiscBlocks => "minecraft:music_disc_blocks", + crate::Item::MusicDiscCat => "minecraft:music_disc_cat", + crate::Item::MusicDiscChirp => "minecraft:music_disc_chirp", + crate::Item::MusicDiscFar => "minecraft:music_disc_far", + crate::Item::MusicDiscMall => "minecraft:music_disc_mall", + crate::Item::MusicDiscMellohi => "minecraft:music_disc_mellohi", + crate::Item::MusicDiscStal => "minecraft:music_disc_stal", + crate::Item::MusicDiscStrad => "minecraft:music_disc_strad", + crate::Item::MusicDiscWait => "minecraft:music_disc_wait", + crate::Item::MusicDiscWard => "minecraft:music_disc_ward", + crate::Item::Mutton => "minecraft:mutton", + crate::Item::Mycelium => "minecraft:mycelium", + crate::Item::NameTag => "minecraft:name_tag", + crate::Item::NautilusShell => "minecraft:nautilus_shell", + crate::Item::NetherBrick => "minecraft:nether_brick", + crate::Item::NetherBrickFence => "minecraft:nether_brick_fence", + crate::Item::NetherBrickSlab => "minecraft:nether_brick_slab", + crate::Item::NetherBrickStairs => "minecraft:nether_brick_stairs", + crate::Item::NetherBricks => "minecraft:nether_bricks", + crate::Item::NetherQuartzOre => "minecraft:nether_quartz_ore", + crate::Item::NetherStar => "minecraft:nether_star", + crate::Item::NetherWart => "minecraft:nether_wart", + crate::Item::NetherWartBlock => "minecraft:nether_wart_block", + crate::Item::Netherrack => "minecraft:netherrack", + crate::Item::NoteBlock => "minecraft:note_block", + crate::Item::OakBoat => "minecraft:oak_boat", + crate::Item::OakButton => "minecraft:oak_button", + crate::Item::OakDoor => "minecraft:oak_door", + crate::Item::OakFence => "minecraft:oak_fence", + crate::Item::OakFenceGate => "minecraft:oak_fence_gate", + crate::Item::OakLeaves => "minecraft:oak_leaves", + crate::Item::OakLog => "minecraft:oak_log", + crate::Item::OakPlanks => "minecraft:oak_planks", + crate::Item::OakPressurePlate => "minecraft:oak_pressure_plate", + crate::Item::OakSapling => "minecraft:oak_sapling", + crate::Item::OakSlab => "minecraft:oak_slab", + crate::Item::OakStairs => "minecraft:oak_stairs", + crate::Item::OakTrapdoor => "minecraft:oak_trapdoor", + crate::Item::OakWood => "minecraft:oak_wood", + crate::Item::Observer => "minecraft:observer", + crate::Item::Obsidian => "minecraft:obsidian", + crate::Item::OcelotSpawnEgg => "minecraft:ocelot_spawn_egg", + crate::Item::OrangeBanner => "minecraft:orange_banner", + crate::Item::OrangeBed => "minecraft:orange_bed", + crate::Item::OrangeCarpet => "minecraft:orange_carpet", + crate::Item::OrangeConcrete => "minecraft:orange_concrete", + crate::Item::OrangeConcretePowder => "minecraft:orange_concrete_powder", + crate::Item::OrangeDye => "minecraft:orange_dye", + crate::Item::OrangeGlazedTerracotta => "minecraft:orange_glazed_terracotta", + crate::Item::OrangeShulkerBox => "minecraft:orange_shulker_box", + crate::Item::OrangeStainedGlass => "minecraft:orange_stained_glass", + crate::Item::OrangeStainedGlassPane => "minecraft:orange_stained_glass_pane", + crate::Item::OrangeTerracotta => "minecraft:orange_terracotta", + crate::Item::OrangeTulip => "minecraft:orange_tulip", + crate::Item::OrangeWool => "minecraft:orange_wool", + crate::Item::OxeyeDaisy => "minecraft:oxeye_daisy", + crate::Item::PackedIce => "minecraft:packed_ice", + crate::Item::Painting => "minecraft:painting", + crate::Item::Paper => "minecraft:paper", + crate::Item::ParrotSpawnEgg => "minecraft:parrot_spawn_egg", + crate::Item::Peony => "minecraft:peony", + crate::Item::PetrifiedOakSlab => "minecraft:petrified_oak_slab", + crate::Item::PhantomMembrane => "minecraft:phantom_membrane", + crate::Item::PhantomSpawnEgg => "minecraft:phantom_spawn_egg", + crate::Item::PigSpawnEgg => "minecraft:pig_spawn_egg", + crate::Item::PinkBanner => "minecraft:pink_banner", + crate::Item::PinkBed => "minecraft:pink_bed", + crate::Item::PinkCarpet => "minecraft:pink_carpet", + crate::Item::PinkConcrete => "minecraft:pink_concrete", + crate::Item::PinkConcretePowder => "minecraft:pink_concrete_powder", + crate::Item::PinkDye => "minecraft:pink_dye", + crate::Item::PinkGlazedTerracotta => "minecraft:pink_glazed_terracotta", + crate::Item::PinkShulkerBox => "minecraft:pink_shulker_box", + crate::Item::PinkStainedGlass => "minecraft:pink_stained_glass", + crate::Item::PinkStainedGlassPane => "minecraft:pink_stained_glass_pane", + crate::Item::PinkTerracotta => "minecraft:pink_terracotta", + crate::Item::PinkTulip => "minecraft:pink_tulip", + crate::Item::PinkWool => "minecraft:pink_wool", + crate::Item::Piston => "minecraft:piston", + crate::Item::PlayerHead => "minecraft:player_head", + crate::Item::Podzol => "minecraft:podzol", + crate::Item::PoisonousPotato => "minecraft:poisonous_potato", + crate::Item::PolarBearSpawnEgg => "minecraft:polar_bear_spawn_egg", + crate::Item::PolishedAndesite => "minecraft:polished_andesite", + crate::Item::PolishedDiorite => "minecraft:polished_diorite", + crate::Item::PolishedGranite => "minecraft:polished_granite", + crate::Item::PoppedChorusFruit => "minecraft:popped_chorus_fruit", + crate::Item::Poppy => "minecraft:poppy", + crate::Item::Porkchop => "minecraft:porkchop", + crate::Item::Potato => "minecraft:potato", + crate::Item::Potion => "minecraft:potion", + crate::Item::PoweredRail => "minecraft:powered_rail", + crate::Item::Prismarine => "minecraft:prismarine", + crate::Item::PrismarineBrickSlab => "minecraft:prismarine_brick_slab", + crate::Item::PrismarineBrickStairs => "minecraft:prismarine_brick_stairs", + crate::Item::PrismarineBricks => "minecraft:prismarine_bricks", + crate::Item::PrismarineCrystals => "minecraft:prismarine_crystals", + crate::Item::PrismarineShard => "minecraft:prismarine_shard", + crate::Item::PrismarineSlab => "minecraft:prismarine_slab", + crate::Item::PrismarineStairs => "minecraft:prismarine_stairs", + crate::Item::Pufferfish => "minecraft:pufferfish", + crate::Item::PufferfishBucket => "minecraft:pufferfish_bucket", + crate::Item::PufferfishSpawnEgg => "minecraft:pufferfish_spawn_egg", + crate::Item::Pumpkin => "minecraft:pumpkin", + crate::Item::PumpkinPie => "minecraft:pumpkin_pie", + crate::Item::PumpkinSeeds => "minecraft:pumpkin_seeds", + crate::Item::PurpleBanner => "minecraft:purple_banner", + crate::Item::PurpleBed => "minecraft:purple_bed", + crate::Item::PurpleCarpet => "minecraft:purple_carpet", + crate::Item::PurpleConcrete => "minecraft:purple_concrete", + crate::Item::PurpleConcretePowder => "minecraft:purple_concrete_powder", + crate::Item::PurpleDye => "minecraft:purple_dye", + crate::Item::PurpleGlazedTerracotta => "minecraft:purple_glazed_terracotta", + crate::Item::PurpleShulkerBox => "minecraft:purple_shulker_box", + crate::Item::PurpleStainedGlass => "minecraft:purple_stained_glass", + crate::Item::PurpleStainedGlassPane => "minecraft:purple_stained_glass_pane", + crate::Item::PurpleTerracotta => "minecraft:purple_terracotta", + crate::Item::PurpleWool => "minecraft:purple_wool", + crate::Item::PurpurBlock => "minecraft:purpur_block", + crate::Item::PurpurPillar => "minecraft:purpur_pillar", + crate::Item::PurpurSlab => "minecraft:purpur_slab", + crate::Item::PurpurStairs => "minecraft:purpur_stairs", + crate::Item::Quartz => "minecraft:quartz", + crate::Item::QuartzBlock => "minecraft:quartz_block", + crate::Item::QuartzPillar => "minecraft:quartz_pillar", + crate::Item::QuartzSlab => "minecraft:quartz_slab", + crate::Item::QuartzStairs => "minecraft:quartz_stairs", + crate::Item::Rabbit => "minecraft:rabbit", + crate::Item::RabbitFoot => "minecraft:rabbit_foot", + crate::Item::RabbitHide => "minecraft:rabbit_hide", + crate::Item::RabbitSpawnEgg => "minecraft:rabbit_spawn_egg", + crate::Item::RabbitStew => "minecraft:rabbit_stew", + crate::Item::Rail => "minecraft:rail", + crate::Item::RedBanner => "minecraft:red_banner", + crate::Item::RedBed => "minecraft:red_bed", + crate::Item::RedCarpet => "minecraft:red_carpet", + crate::Item::RedConcrete => "minecraft:red_concrete", + crate::Item::RedConcretePowder => "minecraft:red_concrete_powder", + crate::Item::RedGlazedTerracotta => "minecraft:red_glazed_terracotta", + crate::Item::RedMushroom => "minecraft:red_mushroom", + crate::Item::RedMushroomBlock => "minecraft:red_mushroom_block", + crate::Item::RedNetherBricks => "minecraft:red_nether_bricks", + crate::Item::RedSand => "minecraft:red_sand", + crate::Item::RedSandstone => "minecraft:red_sandstone", + crate::Item::RedSandstoneSlab => "minecraft:red_sandstone_slab", + crate::Item::RedSandstoneStairs => "minecraft:red_sandstone_stairs", + crate::Item::RedShulkerBox => "minecraft:red_shulker_box", + crate::Item::RedStainedGlass => "minecraft:red_stained_glass", + crate::Item::RedStainedGlassPane => "minecraft:red_stained_glass_pane", + crate::Item::RedTerracotta => "minecraft:red_terracotta", + crate::Item::RedTulip => "minecraft:red_tulip", + crate::Item::RedWool => "minecraft:red_wool", + crate::Item::Redstone => "minecraft:redstone", + crate::Item::RedstoneBlock => "minecraft:redstone_block", + crate::Item::RedstoneLamp => "minecraft:redstone_lamp", + crate::Item::RedstoneOre => "minecraft:redstone_ore", + crate::Item::RedstoneTorch => "minecraft:redstone_torch", + crate::Item::Repeater => "minecraft:repeater", + crate::Item::RepeatingCommandBlock => "minecraft:repeating_command_block", + crate::Item::RoseBush => "minecraft:rose_bush", + crate::Item::RoseRed => "minecraft:rose_red", + crate::Item::RottenFlesh => "minecraft:rotten_flesh", + crate::Item::Saddle => "minecraft:saddle", + crate::Item::Salmon => "minecraft:salmon", + crate::Item::SalmonBucket => "minecraft:salmon_bucket", + crate::Item::SalmonSpawnEgg => "minecraft:salmon_spawn_egg", + crate::Item::Sand => "minecraft:sand", + crate::Item::Sandstone => "minecraft:sandstone", + crate::Item::SandstoneSlab => "minecraft:sandstone_slab", + crate::Item::SandstoneStairs => "minecraft:sandstone_stairs", + crate::Item::Scute => "minecraft:scute", + crate::Item::SeaLantern => "minecraft:sea_lantern", + crate::Item::SeaPickle => "minecraft:sea_pickle", + crate::Item::Seagrass => "minecraft:seagrass", + crate::Item::Shears => "minecraft:shears", + crate::Item::SheepSpawnEgg => "minecraft:sheep_spawn_egg", + crate::Item::Shield => "minecraft:shield", + crate::Item::ShulkerBox => "minecraft:shulker_box", + crate::Item::ShulkerShell => "minecraft:shulker_shell", + crate::Item::ShulkerSpawnEgg => "minecraft:shulker_spawn_egg", + crate::Item::Sign => "minecraft:sign", + crate::Item::SilverfishSpawnEgg => "minecraft:silverfish_spawn_egg", + crate::Item::SkeletonHorseSpawnEgg => "minecraft:skeleton_horse_spawn_egg", + crate::Item::SkeletonSkull => "minecraft:skeleton_skull", + crate::Item::SkeletonSpawnEgg => "minecraft:skeleton_spawn_egg", + crate::Item::SlimeBall => "minecraft:slime_ball", + crate::Item::SlimeBlock => "minecraft:slime_block", + crate::Item::SlimeSpawnEgg => "minecraft:slime_spawn_egg", + crate::Item::SmoothQuartz => "minecraft:smooth_quartz", + crate::Item::SmoothRedSandstone => "minecraft:smooth_red_sandstone", + crate::Item::SmoothSandstone => "minecraft:smooth_sandstone", + crate::Item::SmoothStone => "minecraft:smooth_stone", + crate::Item::Snow => "minecraft:snow", + crate::Item::SnowBlock => "minecraft:snow_block", + crate::Item::Snowball => "minecraft:snowball", + crate::Item::SoulSand => "minecraft:soul_sand", + crate::Item::Spawner => "minecraft:spawner", + crate::Item::SpectralArrow => "minecraft:spectral_arrow", + crate::Item::SpiderEye => "minecraft:spider_eye", + crate::Item::SpiderSpawnEgg => "minecraft:spider_spawn_egg", + crate::Item::SplashPotion => "minecraft:splash_potion", + crate::Item::Sponge => "minecraft:sponge", + crate::Item::SpruceBoat => "minecraft:spruce_boat", + crate::Item::SpruceButton => "minecraft:spruce_button", + crate::Item::SpruceDoor => "minecraft:spruce_door", + crate::Item::SpruceFence => "minecraft:spruce_fence", + crate::Item::SpruceFenceGate => "minecraft:spruce_fence_gate", + crate::Item::SpruceLeaves => "minecraft:spruce_leaves", + crate::Item::SpruceLog => "minecraft:spruce_log", + crate::Item::SprucePlanks => "minecraft:spruce_planks", + crate::Item::SprucePressurePlate => "minecraft:spruce_pressure_plate", + crate::Item::SpruceSapling => "minecraft:spruce_sapling", + crate::Item::SpruceSlab => "minecraft:spruce_slab", + crate::Item::SpruceStairs => "minecraft:spruce_stairs", + crate::Item::SpruceTrapdoor => "minecraft:spruce_trapdoor", + crate::Item::SpruceWood => "minecraft:spruce_wood", + crate::Item::SquidSpawnEgg => "minecraft:squid_spawn_egg", + crate::Item::Stick => "minecraft:stick", + crate::Item::StickyPiston => "minecraft:sticky_piston", + crate::Item::Stone => "minecraft:stone", + crate::Item::StoneAxe => "minecraft:stone_axe", + crate::Item::StoneBrickSlab => "minecraft:stone_brick_slab", + crate::Item::StoneBrickStairs => "minecraft:stone_brick_stairs", + crate::Item::StoneBricks => "minecraft:stone_bricks", + crate::Item::StoneButton => "minecraft:stone_button", + crate::Item::StoneHoe => "minecraft:stone_hoe", + crate::Item::StonePickaxe => "minecraft:stone_pickaxe", + crate::Item::StonePressurePlate => "minecraft:stone_pressure_plate", + crate::Item::StoneShovel => "minecraft:stone_shovel", + crate::Item::StoneSlab => "minecraft:stone_slab", + crate::Item::StoneSword => "minecraft:stone_sword", + crate::Item::StraySpawnEgg => "minecraft:stray_spawn_egg", + crate::Item::String => "minecraft:string", + crate::Item::StrippedAcaciaLog => "minecraft:stripped_acacia_log", + crate::Item::StrippedAcaciaWood => "minecraft:stripped_acacia_wood", + crate::Item::StrippedBirchLog => "minecraft:stripped_birch_log", + crate::Item::StrippedBirchWood => "minecraft:stripped_birch_wood", + crate::Item::StrippedDarkOakLog => "minecraft:stripped_dark_oak_log", + crate::Item::StrippedDarkOakWood => "minecraft:stripped_dark_oak_wood", + crate::Item::StrippedJungleLog => "minecraft:stripped_jungle_log", + crate::Item::StrippedJungleWood => "minecraft:stripped_jungle_wood", + crate::Item::StrippedOakLog => "minecraft:stripped_oak_log", + crate::Item::StrippedOakWood => "minecraft:stripped_oak_wood", + crate::Item::StrippedSpruceLog => "minecraft:stripped_spruce_log", + crate::Item::StrippedSpruceWood => "minecraft:stripped_spruce_wood", + crate::Item::StructureBlock => "minecraft:structure_block", + crate::Item::StructureVoid => "minecraft:structure_void", + crate::Item::Sugar => "minecraft:sugar", + crate::Item::SugarCane => "minecraft:sugar_cane", + crate::Item::Sunflower => "minecraft:sunflower", + crate::Item::TallGrass => "minecraft:tall_grass", + crate::Item::Terracotta => "minecraft:terracotta", + crate::Item::TippedArrow => "minecraft:tipped_arrow", + crate::Item::Tnt => "minecraft:tnt", + crate::Item::TntMinecart => "minecraft:tnt_minecart", + crate::Item::Torch => "minecraft:torch", + crate::Item::TotemOfUndying => "minecraft:totem_of_undying", + crate::Item::TrappedChest => "minecraft:trapped_chest", + crate::Item::Trident => "minecraft:trident", + crate::Item::TripwireHook => "minecraft:tripwire_hook", + crate::Item::TropicalFish => "minecraft:tropical_fish", + crate::Item::TropicalFishBucket => "minecraft:tropical_fish_bucket", + crate::Item::TropicalFishSpawnEgg => "minecraft:tropical_fish_spawn_egg", + crate::Item::TubeCoral => "minecraft:tube_coral", + crate::Item::TubeCoralBlock => "minecraft:tube_coral_block", + crate::Item::TubeCoralFan => "minecraft:tube_coral_fan", + crate::Item::TurtleEgg => "minecraft:turtle_egg", + crate::Item::TurtleHelmet => "minecraft:turtle_helmet", + crate::Item::TurtleSpawnEgg => "minecraft:turtle_spawn_egg", + crate::Item::VexSpawnEgg => "minecraft:vex_spawn_egg", + crate::Item::VillagerSpawnEgg => "minecraft:villager_spawn_egg", + crate::Item::VindicatorSpawnEgg => "minecraft:vindicator_spawn_egg", + crate::Item::Vine => "minecraft:vine", + crate::Item::WaterBucket => "minecraft:water_bucket", + crate::Item::WetSponge => "minecraft:wet_sponge", + crate::Item::Wheat => "minecraft:wheat", + crate::Item::WheatSeeds => "minecraft:wheat_seeds", + crate::Item::WhiteBanner => "minecraft:white_banner", + crate::Item::WhiteBed => "minecraft:white_bed", + crate::Item::WhiteCarpet => "minecraft:white_carpet", + crate::Item::WhiteConcrete => "minecraft:white_concrete", + crate::Item::WhiteConcretePowder => "minecraft:white_concrete_powder", + crate::Item::WhiteGlazedTerracotta => "minecraft:white_glazed_terracotta", + crate::Item::WhiteShulkerBox => "minecraft:white_shulker_box", + crate::Item::WhiteStainedGlass => "minecraft:white_stained_glass", + crate::Item::WhiteStainedGlassPane => "minecraft:white_stained_glass_pane", + crate::Item::WhiteTerracotta => "minecraft:white_terracotta", + crate::Item::WhiteTulip => "minecraft:white_tulip", + crate::Item::WhiteWool => "minecraft:white_wool", + crate::Item::WitchSpawnEgg => "minecraft:witch_spawn_egg", + crate::Item::WitherSkeletonSkull => "minecraft:wither_skeleton_skull", + crate::Item::WitherSkeletonSpawnEgg => "minecraft:wither_skeleton_spawn_egg", + crate::Item::WolfSpawnEgg => "minecraft:wolf_spawn_egg", + crate::Item::WoodenAxe => "minecraft:wooden_axe", + crate::Item::WoodenHoe => "minecraft:wooden_hoe", + crate::Item::WoodenPickaxe => "minecraft:wooden_pickaxe", + crate::Item::WoodenShovel => "minecraft:wooden_shovel", + crate::Item::WoodenSword => "minecraft:wooden_sword", + crate::Item::WritableBook => "minecraft:writable_book", + crate::Item::WrittenBook => "minecraft:written_book", + crate::Item::YellowBanner => "minecraft:yellow_banner", + crate::Item::YellowBed => "minecraft:yellow_bed", + crate::Item::YellowCarpet => "minecraft:yellow_carpet", + crate::Item::YellowConcrete => "minecraft:yellow_concrete", + crate::Item::YellowConcretePowder => "minecraft:yellow_concrete_powder", + crate::Item::YellowGlazedTerracotta => "minecraft:yellow_glazed_terracotta", + crate::Item::YellowShulkerBox => "minecraft:yellow_shulker_box", + crate::Item::YellowStainedGlass => "minecraft:yellow_stained_glass", + crate::Item::YellowStainedGlassPane => "minecraft:yellow_stained_glass_pane", + crate::Item::YellowTerracotta => "minecraft:yellow_terracotta", + crate::Item::YellowWool => "minecraft:yellow_wool", + crate::Item::ZombieHead => "minecraft:zombie_head", + crate::Item::ZombieHorseSpawnEgg => "minecraft:zombie_horse_spawn_egg", + crate::Item::ZombiePigmanSpawnEgg => "minecraft:zombie_pigman_spawn_egg", + crate::Item::ZombieSpawnEgg => "minecraft:zombie_spawn_egg", + crate::Item::ZombieVillagerSpawnEgg => "minecraft:zombie_villager_spawn_egg", + } + } + pub fn from_identifier(prop: &str) -> Option<Item> { + match prop { + "minecraft:acacia_boat" => Some(crate::Item::AcaciaBoat), + "minecraft:acacia_button" => Some(crate::Item::AcaciaButton), + "minecraft:acacia_door" => Some(crate::Item::AcaciaDoor), + "minecraft:acacia_fence" => Some(crate::Item::AcaciaFence), + "minecraft:acacia_fence_gate" => Some(crate::Item::AcaciaFenceGate), + "minecraft:acacia_leaves" => Some(crate::Item::AcaciaLeaves), + "minecraft:acacia_log" => Some(crate::Item::AcaciaLog), + "minecraft:acacia_planks" => Some(crate::Item::AcaciaPlanks), + "minecraft:acacia_pressure_plate" => Some(crate::Item::AcaciaPressurePlate), + "minecraft:acacia_sapling" => Some(crate::Item::AcaciaSapling), + "minecraft:acacia_slab" => Some(crate::Item::AcaciaSlab), + "minecraft:acacia_stairs" => Some(crate::Item::AcaciaStairs), + "minecraft:acacia_trapdoor" => Some(crate::Item::AcaciaTrapdoor), + "minecraft:acacia_wood" => Some(crate::Item::AcaciaWood), + "minecraft:activator_rail" => Some(crate::Item::ActivatorRail), + "minecraft:air" => Some(crate::Item::Air), + "minecraft:allium" => Some(crate::Item::Allium), + "minecraft:andesite" => Some(crate::Item::Andesite), + "minecraft:anvil" => Some(crate::Item::Anvil), + "minecraft:apple" => Some(crate::Item::Apple), + "minecraft:armor_stand" => Some(crate::Item::ArmorStand), + "minecraft:arrow" => Some(crate::Item::Arrow), + "minecraft:azure_bluet" => Some(crate::Item::AzureBluet), + "minecraft:baked_potato" => Some(crate::Item::BakedPotato), + "minecraft:barrier" => Some(crate::Item::Barrier), + "minecraft:bat_spawn_egg" => Some(crate::Item::BatSpawnEgg), + "minecraft:beacon" => Some(crate::Item::Beacon), + "minecraft:bedrock" => Some(crate::Item::Bedrock), + "minecraft:beef" => Some(crate::Item::Beef), + "minecraft:beetroot" => Some(crate::Item::Beetroot), + "minecraft:beetroot_seeds" => Some(crate::Item::BeetrootSeeds), + "minecraft:beetroot_soup" => Some(crate::Item::BeetrootSoup), + "minecraft:birch_boat" => Some(crate::Item::BirchBoat), + "minecraft:birch_button" => Some(crate::Item::BirchButton), + "minecraft:birch_door" => Some(crate::Item::BirchDoor), + "minecraft:birch_fence" => Some(crate::Item::BirchFence), + "minecraft:birch_fence_gate" => Some(crate::Item::BirchFenceGate), + "minecraft:birch_leaves" => Some(crate::Item::BirchLeaves), + "minecraft:birch_log" => Some(crate::Item::BirchLog), + "minecraft:birch_planks" => Some(crate::Item::BirchPlanks), + "minecraft:birch_pressure_plate" => Some(crate::Item::BirchPressurePlate), + "minecraft:birch_sapling" => Some(crate::Item::BirchSapling), + "minecraft:birch_slab" => Some(crate::Item::BirchSlab), + "minecraft:birch_stairs" => Some(crate::Item::BirchStairs), + "minecraft:birch_trapdoor" => Some(crate::Item::BirchTrapdoor), + "minecraft:birch_wood" => Some(crate::Item::BirchWood), + "minecraft:black_banner" => Some(crate::Item::BlackBanner), + "minecraft:black_bed" => Some(crate::Item::BlackBed), + "minecraft:black_carpet" => Some(crate::Item::BlackCarpet), + "minecraft:black_concrete" => Some(crate::Item::BlackConcrete), + "minecraft:black_concrete_powder" => Some(crate::Item::BlackConcretePowder), + "minecraft:black_glazed_terracotta" => Some(crate::Item::BlackGlazedTerracotta), + "minecraft:black_shulker_box" => Some(crate::Item::BlackShulkerBox), + "minecraft:black_stained_glass" => Some(crate::Item::BlackStainedGlass), + "minecraft:black_stained_glass_pane" => Some(crate::Item::BlackStainedGlassPane), + "minecraft:black_terracotta" => Some(crate::Item::BlackTerracotta), + "minecraft:black_wool" => Some(crate::Item::BlackWool), + "minecraft:blaze_powder" => Some(crate::Item::BlazePowder), + "minecraft:blaze_rod" => Some(crate::Item::BlazeRod), + "minecraft:blaze_spawn_egg" => Some(crate::Item::BlazeSpawnEgg), + "minecraft:blue_banner" => Some(crate::Item::BlueBanner), + "minecraft:blue_bed" => Some(crate::Item::BlueBed), + "minecraft:blue_carpet" => Some(crate::Item::BlueCarpet), + "minecraft:blue_concrete" => Some(crate::Item::BlueConcrete), + "minecraft:blue_concrete_powder" => Some(crate::Item::BlueConcretePowder), + "minecraft:blue_glazed_terracotta" => Some(crate::Item::BlueGlazedTerracotta), + "minecraft:blue_ice" => Some(crate::Item::BlueIce), + "minecraft:blue_orchid" => Some(crate::Item::BlueOrchid), + "minecraft:blue_shulker_box" => Some(crate::Item::BlueShulkerBox), + "minecraft:blue_stained_glass" => Some(crate::Item::BlueStainedGlass), + "minecraft:blue_stained_glass_pane" => Some(crate::Item::BlueStainedGlassPane), + "minecraft:blue_terracotta" => Some(crate::Item::BlueTerracotta), + "minecraft:blue_wool" => Some(crate::Item::BlueWool), + "minecraft:bone" => Some(crate::Item::Bone), + "minecraft:bone_block" => Some(crate::Item::BoneBlock), + "minecraft:bone_meal" => Some(crate::Item::BoneMeal), + "minecraft:book" => Some(crate::Item::Book), + "minecraft:bookshelf" => Some(crate::Item::Bookshelf), + "minecraft:bow" => Some(crate::Item::Bow), + "minecraft:bowl" => Some(crate::Item::Bowl), + "minecraft:brain_coral" => Some(crate::Item::BrainCoral), + "minecraft:brain_coral_block" => Some(crate::Item::BrainCoralBlock), + "minecraft:brain_coral_fan" => Some(crate::Item::BrainCoralFan), + "minecraft:bread" => Some(crate::Item::Bread), + "minecraft:brewing_stand" => Some(crate::Item::BrewingStand), + "minecraft:brick" => Some(crate::Item::Brick), + "minecraft:brick_slab" => Some(crate::Item::BrickSlab), + "minecraft:brick_stairs" => Some(crate::Item::BrickStairs), + "minecraft:bricks" => Some(crate::Item::Bricks), + "minecraft:brown_banner" => Some(crate::Item::BrownBanner), + "minecraft:brown_bed" => Some(crate::Item::BrownBed), + "minecraft:brown_carpet" => Some(crate::Item::BrownCarpet), + "minecraft:brown_concrete" => Some(crate::Item::BrownConcrete), + "minecraft:brown_concrete_powder" => Some(crate::Item::BrownConcretePowder), + "minecraft:brown_glazed_terracotta" => Some(crate::Item::BrownGlazedTerracotta), + "minecraft:brown_mushroom" => Some(crate::Item::BrownMushroom), + "minecraft:brown_mushroom_block" => Some(crate::Item::BrownMushroomBlock), + "minecraft:brown_shulker_box" => Some(crate::Item::BrownShulkerBox), + "minecraft:brown_stained_glass" => Some(crate::Item::BrownStainedGlass), + "minecraft:brown_stained_glass_pane" => Some(crate::Item::BrownStainedGlassPane), + "minecraft:brown_terracotta" => Some(crate::Item::BrownTerracotta), + "minecraft:brown_wool" => Some(crate::Item::BrownWool), + "minecraft:bubble_coral" => Some(crate::Item::BubbleCoral), + "minecraft:bubble_coral_block" => Some(crate::Item::BubbleCoralBlock), + "minecraft:bubble_coral_fan" => Some(crate::Item::BubbleCoralFan), + "minecraft:bucket" => Some(crate::Item::Bucket), + "minecraft:cactus" => Some(crate::Item::Cactus), + "minecraft:cactus_green" => Some(crate::Item::CactusGreen), + "minecraft:cake" => Some(crate::Item::Cake), + "minecraft:carrot" => Some(crate::Item::Carrot), + "minecraft:carrot_on_a_stick" => Some(crate::Item::CarrotOnAStick), + "minecraft:carved_pumpkin" => Some(crate::Item::CarvedPumpkin), + "minecraft:cauldron" => Some(crate::Item::Cauldron), + "minecraft:cave_spider_spawn_egg" => Some(crate::Item::CaveSpiderSpawnEgg), + "minecraft:chain_command_block" => Some(crate::Item::ChainCommandBlock), + "minecraft:chainmail_boots" => Some(crate::Item::ChainmailBoots), + "minecraft:chainmail_chestplate" => Some(crate::Item::ChainmailChestplate), + "minecraft:chainmail_helmet" => Some(crate::Item::ChainmailHelmet), + "minecraft:chainmail_leggings" => Some(crate::Item::ChainmailLeggings), + "minecraft:charcoal" => Some(crate::Item::Charcoal), + "minecraft:chest" => Some(crate::Item::Chest), + "minecraft:chest_minecart" => Some(crate::Item::ChestMinecart), + "minecraft:chicken" => Some(crate::Item::Chicken), + "minecraft:chicken_spawn_egg" => Some(crate::Item::ChickenSpawnEgg), + "minecraft:chipped_anvil" => Some(crate::Item::ChippedAnvil), + "minecraft:chiseled_quartz_block" => Some(crate::Item::ChiseledQuartzBlock), + "minecraft:chiseled_red_sandstone" => Some(crate::Item::ChiseledRedSandstone), + "minecraft:chiseled_sandstone" => Some(crate::Item::ChiseledSandstone), + "minecraft:chiseled_stone_bricks" => Some(crate::Item::ChiseledStoneBricks), + "minecraft:chorus_flower" => Some(crate::Item::ChorusFlower), + "minecraft:chorus_fruit" => Some(crate::Item::ChorusFruit), + "minecraft:chorus_plant" => Some(crate::Item::ChorusPlant), + "minecraft:clay" => Some(crate::Item::Clay), + "minecraft:clay_ball" => Some(crate::Item::ClayBall), + "minecraft:clock" => Some(crate::Item::Clock), + "minecraft:coal" => Some(crate::Item::Coal), + "minecraft:coal_block" => Some(crate::Item::CoalBlock), + "minecraft:coal_ore" => Some(crate::Item::CoalOre), + "minecraft:coarse_dirt" => Some(crate::Item::CoarseDirt), + "minecraft:cobblestone" => Some(crate::Item::Cobblestone), + "minecraft:cobblestone_slab" => Some(crate::Item::CobblestoneSlab), + "minecraft:cobblestone_stairs" => Some(crate::Item::CobblestoneStairs), + "minecraft:cobblestone_wall" => Some(crate::Item::CobblestoneWall), + "minecraft:cobweb" => Some(crate::Item::Cobweb), + "minecraft:cocoa_beans" => Some(crate::Item::CocoaBeans), + "minecraft:cod" => Some(crate::Item::Cod), + "minecraft:cod_bucket" => Some(crate::Item::CodBucket), + "minecraft:cod_spawn_egg" => Some(crate::Item::CodSpawnEgg), + "minecraft:command_block" => Some(crate::Item::CommandBlock), + "minecraft:command_block_minecart" => Some(crate::Item::CommandBlockMinecart), + "minecraft:comparator" => Some(crate::Item::Comparator), + "minecraft:compass" => Some(crate::Item::Compass), + "minecraft:conduit" => Some(crate::Item::Conduit), + "minecraft:cooked_beef" => Some(crate::Item::CookedBeef), + "minecraft:cooked_chicken" => Some(crate::Item::CookedChicken), + "minecraft:cooked_cod" => Some(crate::Item::CookedCod), + "minecraft:cooked_mutton" => Some(crate::Item::CookedMutton), + "minecraft:cooked_porkchop" => Some(crate::Item::CookedPorkchop), + "minecraft:cooked_rabbit" => Some(crate::Item::CookedRabbit), + "minecraft:cooked_salmon" => Some(crate::Item::CookedSalmon), + "minecraft:cookie" => Some(crate::Item::Cookie), + "minecraft:cow_spawn_egg" => Some(crate::Item::CowSpawnEgg), + "minecraft:cracked_stone_bricks" => Some(crate::Item::CrackedStoneBricks), + "minecraft:crafting_table" => Some(crate::Item::CraftingTable), + "minecraft:creeper_head" => Some(crate::Item::CreeperHead), + "minecraft:creeper_spawn_egg" => Some(crate::Item::CreeperSpawnEgg), + "minecraft:cut_red_sandstone" => Some(crate::Item::CutRedSandstone), + "minecraft:cut_sandstone" => Some(crate::Item::CutSandstone), + "minecraft:cyan_banner" => Some(crate::Item::CyanBanner), + "minecraft:cyan_bed" => Some(crate::Item::CyanBed), + "minecraft:cyan_carpet" => Some(crate::Item::CyanCarpet), + "minecraft:cyan_concrete" => Some(crate::Item::CyanConcrete), + "minecraft:cyan_concrete_powder" => Some(crate::Item::CyanConcretePowder), + "minecraft:cyan_dye" => Some(crate::Item::CyanDye), + "minecraft:cyan_glazed_terracotta" => Some(crate::Item::CyanGlazedTerracotta), + "minecraft:cyan_shulker_box" => Some(crate::Item::CyanShulkerBox), + "minecraft:cyan_stained_glass" => Some(crate::Item::CyanStainedGlass), + "minecraft:cyan_stained_glass_pane" => Some(crate::Item::CyanStainedGlassPane), + "minecraft:cyan_terracotta" => Some(crate::Item::CyanTerracotta), + "minecraft:cyan_wool" => Some(crate::Item::CyanWool), + "minecraft:damaged_anvil" => Some(crate::Item::DamagedAnvil), + "minecraft:dandelion" => Some(crate::Item::Dandelion), + "minecraft:dandelion_yellow" => Some(crate::Item::DandelionYellow), + "minecraft:dark_oak_boat" => Some(crate::Item::DarkOakBoat), + "minecraft:dark_oak_button" => Some(crate::Item::DarkOakButton), + "minecraft:dark_oak_door" => Some(crate::Item::DarkOakDoor), + "minecraft:dark_oak_fence" => Some(crate::Item::DarkOakFence), + "minecraft:dark_oak_fence_gate" => Some(crate::Item::DarkOakFenceGate), + "minecraft:dark_oak_leaves" => Some(crate::Item::DarkOakLeaves), + "minecraft:dark_oak_log" => Some(crate::Item::DarkOakLog), + "minecraft:dark_oak_planks" => Some(crate::Item::DarkOakPlanks), + "minecraft:dark_oak_pressure_plate" => Some(crate::Item::DarkOakPressurePlate), + "minecraft:dark_oak_sapling" => Some(crate::Item::DarkOakSapling), + "minecraft:dark_oak_slab" => Some(crate::Item::DarkOakSlab), + "minecraft:dark_oak_stairs" => Some(crate::Item::DarkOakStairs), + "minecraft:dark_oak_trapdoor" => Some(crate::Item::DarkOakTrapdoor), + "minecraft:dark_oak_wood" => Some(crate::Item::DarkOakWood), + "minecraft:dark_prismarine" => Some(crate::Item::DarkPrismarine), + "minecraft:dark_prismarine_slab" => Some(crate::Item::DarkPrismarineSlab), + "minecraft:dark_prismarine_stairs" => Some(crate::Item::DarkPrismarineStairs), + "minecraft:daylight_detector" => Some(crate::Item::DaylightDetector), + "minecraft:dead_brain_coral" => Some(crate::Item::DeadBrainCoral), + "minecraft:dead_brain_coral_block" => Some(crate::Item::DeadBrainCoralBlock), + "minecraft:dead_brain_coral_fan" => Some(crate::Item::DeadBrainCoralFan), + "minecraft:dead_bubble_coral" => Some(crate::Item::DeadBubbleCoral), + "minecraft:dead_bubble_coral_block" => Some(crate::Item::DeadBubbleCoralBlock), + "minecraft:dead_bubble_coral_fan" => Some(crate::Item::DeadBubbleCoralFan), + "minecraft:dead_bush" => Some(crate::Item::DeadBush), + "minecraft:dead_fire_coral" => Some(crate::Item::DeadFireCoral), + "minecraft:dead_fire_coral_block" => Some(crate::Item::DeadFireCoralBlock), + "minecraft:dead_fire_coral_fan" => Some(crate::Item::DeadFireCoralFan), + "minecraft:dead_horn_coral" => Some(crate::Item::DeadHornCoral), + "minecraft:dead_horn_coral_block" => Some(crate::Item::DeadHornCoralBlock), + "minecraft:dead_horn_coral_fan" => Some(crate::Item::DeadHornCoralFan), + "minecraft:dead_tube_coral" => Some(crate::Item::DeadTubeCoral), + "minecraft:dead_tube_coral_block" => Some(crate::Item::DeadTubeCoralBlock), + "minecraft:dead_tube_coral_fan" => Some(crate::Item::DeadTubeCoralFan), + "minecraft:debug_stick" => Some(crate::Item::DebugStick), + "minecraft:detector_rail" => Some(crate::Item::DetectorRail), + "minecraft:diamond" => Some(crate::Item::Diamond), + "minecraft:diamond_axe" => Some(crate::Item::DiamondAxe), + "minecraft:diamond_block" => Some(crate::Item::DiamondBlock), + "minecraft:diamond_boots" => Some(crate::Item::DiamondBoots), + "minecraft:diamond_chestplate" => Some(crate::Item::DiamondChestplate), + "minecraft:diamond_helmet" => Some(crate::Item::DiamondHelmet), + "minecraft:diamond_hoe" => Some(crate::Item::DiamondHoe), + "minecraft:diamond_horse_armor" => Some(crate::Item::DiamondHorseArmor), + "minecraft:diamond_leggings" => Some(crate::Item::DiamondLeggings), + "minecraft:diamond_ore" => Some(crate::Item::DiamondOre), + "minecraft:diamond_pickaxe" => Some(crate::Item::DiamondPickaxe), + "minecraft:diamond_shovel" => Some(crate::Item::DiamondShovel), + "minecraft:diamond_sword" => Some(crate::Item::DiamondSword), + "minecraft:diorite" => Some(crate::Item::Diorite), + "minecraft:dirt" => Some(crate::Item::Dirt), + "minecraft:dispenser" => Some(crate::Item::Dispenser), + "minecraft:dolphin_spawn_egg" => Some(crate::Item::DolphinSpawnEgg), + "minecraft:donkey_spawn_egg" => Some(crate::Item::DonkeySpawnEgg), + "minecraft:dragon_breath" => Some(crate::Item::DragonBreath), + "minecraft:dragon_egg" => Some(crate::Item::DragonEgg), + "minecraft:dragon_head" => Some(crate::Item::DragonHead), + "minecraft:dried_kelp" => Some(crate::Item::DriedKelp), + "minecraft:dried_kelp_block" => Some(crate::Item::DriedKelpBlock), + "minecraft:dropper" => Some(crate::Item::Dropper), + "minecraft:drowned_spawn_egg" => Some(crate::Item::DrownedSpawnEgg), + "minecraft:egg" => Some(crate::Item::Egg), + "minecraft:elder_guardian_spawn_egg" => Some(crate::Item::ElderGuardianSpawnEgg), + "minecraft:elytra" => Some(crate::Item::Elytra), + "minecraft:emerald" => Some(crate::Item::Emerald), + "minecraft:emerald_block" => Some(crate::Item::EmeraldBlock), + "minecraft:emerald_ore" => Some(crate::Item::EmeraldOre), + "minecraft:enchanted_book" => Some(crate::Item::EnchantedBook), + "minecraft:enchanted_golden_apple" => Some(crate::Item::EnchantedGoldenApple), + "minecraft:enchanting_table" => Some(crate::Item::EnchantingTable), + "minecraft:end_crystal" => Some(crate::Item::EndCrystal), + "minecraft:end_portal_frame" => Some(crate::Item::EndPortalFrame), + "minecraft:end_rod" => Some(crate::Item::EndRod), + "minecraft:end_stone" => Some(crate::Item::EndStone), + "minecraft:end_stone_bricks" => Some(crate::Item::EndStoneBricks), + "minecraft:ender_chest" => Some(crate::Item::EnderChest), + "minecraft:ender_eye" => Some(crate::Item::EnderEye), + "minecraft:ender_pearl" => Some(crate::Item::EnderPearl), + "minecraft:enderman_spawn_egg" => Some(crate::Item::EndermanSpawnEgg), + "minecraft:endermite_spawn_egg" => Some(crate::Item::EndermiteSpawnEgg), + "minecraft:evoker_spawn_egg" => Some(crate::Item::EvokerSpawnEgg), + "minecraft:experience_bottle" => Some(crate::Item::ExperienceBottle), + "minecraft:farmland" => Some(crate::Item::Farmland), + "minecraft:feather" => Some(crate::Item::Feather), + "minecraft:fermented_spider_eye" => Some(crate::Item::FermentedSpiderEye), + "minecraft:fern" => Some(crate::Item::Fern), + "minecraft:filled_map" => Some(crate::Item::FilledMap), + "minecraft:fire_charge" => Some(crate::Item::FireCharge), + "minecraft:fire_coral" => Some(crate::Item::FireCoral), + "minecraft:fire_coral_block" => Some(crate::Item::FireCoralBlock), + "minecraft:fire_coral_fan" => Some(crate::Item::FireCoralFan), + "minecraft:firework_rocket" => Some(crate::Item::FireworkRocket), + "minecraft:firework_star" => Some(crate::Item::FireworkStar), + "minecraft:fishing_rod" => Some(crate::Item::FishingRod), + "minecraft:flint" => Some(crate::Item::Flint), + "minecraft:flint_and_steel" => Some(crate::Item::FlintAndSteel), + "minecraft:flower_pot" => Some(crate::Item::FlowerPot), + "minecraft:furnace" => Some(crate::Item::Furnace), + "minecraft:furnace_minecart" => Some(crate::Item::FurnaceMinecart), + "minecraft:ghast_spawn_egg" => Some(crate::Item::GhastSpawnEgg), + "minecraft:ghast_tear" => Some(crate::Item::GhastTear), + "minecraft:glass" => Some(crate::Item::Glass), + "minecraft:glass_bottle" => Some(crate::Item::GlassBottle), + "minecraft:glass_pane" => Some(crate::Item::GlassPane), + "minecraft:glistering_melon_slice" => Some(crate::Item::GlisteringMelonSlice), + "minecraft:glowstone" => Some(crate::Item::Glowstone), + "minecraft:glowstone_dust" => Some(crate::Item::GlowstoneDust), + "minecraft:gold_block" => Some(crate::Item::GoldBlock), + "minecraft:gold_ingot" => Some(crate::Item::GoldIngot), + "minecraft:gold_nugget" => Some(crate::Item::GoldNugget), + "minecraft:gold_ore" => Some(crate::Item::GoldOre), + "minecraft:golden_apple" => Some(crate::Item::GoldenApple), + "minecraft:golden_axe" => Some(crate::Item::GoldenAxe), + "minecraft:golden_boots" => Some(crate::Item::GoldenBoots), + "minecraft:golden_carrot" => Some(crate::Item::GoldenCarrot), + "minecraft:golden_chestplate" => Some(crate::Item::GoldenChestplate), + "minecraft:golden_helmet" => Some(crate::Item::GoldenHelmet), + "minecraft:golden_hoe" => Some(crate::Item::GoldenHoe), + "minecraft:golden_horse_armor" => Some(crate::Item::GoldenHorseArmor), + "minecraft:golden_leggings" => Some(crate::Item::GoldenLeggings), + "minecraft:golden_pickaxe" => Some(crate::Item::GoldenPickaxe), + "minecraft:golden_shovel" => Some(crate::Item::GoldenShovel), + "minecraft:golden_sword" => Some(crate::Item::GoldenSword), + "minecraft:granite" => Some(crate::Item::Granite), + "minecraft:grass" => Some(crate::Item::Grass), + "minecraft:grass_block" => Some(crate::Item::GrassBlock), + "minecraft:grass_path" => Some(crate::Item::GrassPath), + "minecraft:gravel" => Some(crate::Item::Gravel), + "minecraft:gray_banner" => Some(crate::Item::GrayBanner), + "minecraft:gray_bed" => Some(crate::Item::GrayBed), + "minecraft:gray_carpet" => Some(crate::Item::GrayCarpet), + "minecraft:gray_concrete" => Some(crate::Item::GrayConcrete), + "minecraft:gray_concrete_powder" => Some(crate::Item::GrayConcretePowder), + "minecraft:gray_dye" => Some(crate::Item::GrayDye), + "minecraft:gray_glazed_terracotta" => Some(crate::Item::GrayGlazedTerracotta), + "minecraft:gray_shulker_box" => Some(crate::Item::GrayShulkerBox), + "minecraft:gray_stained_glass" => Some(crate::Item::GrayStainedGlass), + "minecraft:gray_stained_glass_pane" => Some(crate::Item::GrayStainedGlassPane), + "minecraft:gray_terracotta" => Some(crate::Item::GrayTerracotta), + "minecraft:gray_wool" => Some(crate::Item::GrayWool), + "minecraft:green_banner" => Some(crate::Item::GreenBanner), + "minecraft:green_bed" => Some(crate::Item::GreenBed), + "minecraft:green_carpet" => Some(crate::Item::GreenCarpet), + "minecraft:green_concrete" => Some(crate::Item::GreenConcrete), + "minecraft:green_concrete_powder" => Some(crate::Item::GreenConcretePowder), + "minecraft:green_glazed_terracotta" => Some(crate::Item::GreenGlazedTerracotta), + "minecraft:green_shulker_box" => Some(crate::Item::GreenShulkerBox), + "minecraft:green_stained_glass" => Some(crate::Item::GreenStainedGlass), + "minecraft:green_stained_glass_pane" => Some(crate::Item::GreenStainedGlassPane), + "minecraft:green_terracotta" => Some(crate::Item::GreenTerracotta), + "minecraft:green_wool" => Some(crate::Item::GreenWool), + "minecraft:guardian_spawn_egg" => Some(crate::Item::GuardianSpawnEgg), + "minecraft:gunpowder" => Some(crate::Item::Gunpowder), + "minecraft:hay_block" => Some(crate::Item::HayBlock), + "minecraft:heart_of_the_sea" => Some(crate::Item::HeartOfTheSea), + "minecraft:heavy_weighted_pressure_plate" => { + Some(crate::Item::HeavyWeightedPressurePlate) + } + "minecraft:hopper" => Some(crate::Item::Hopper), + "minecraft:hopper_minecart" => Some(crate::Item::HopperMinecart), + "minecraft:horn_coral" => Some(crate::Item::HornCoral), + "minecraft:horn_coral_block" => Some(crate::Item::HornCoralBlock), + "minecraft:horn_coral_fan" => Some(crate::Item::HornCoralFan), + "minecraft:horse_spawn_egg" => Some(crate::Item::HorseSpawnEgg), + "minecraft:husk_spawn_egg" => Some(crate::Item::HuskSpawnEgg), + "minecraft:ice" => Some(crate::Item::Ice), + "minecraft:infested_chiseled_stone_bricks" => { + Some(crate::Item::InfestedChiseledStoneBricks) + } + "minecraft:infested_cobblestone" => Some(crate::Item::InfestedCobblestone), + "minecraft:infested_cracked_stone_bricks" => { + Some(crate::Item::InfestedCrackedStoneBricks) + } + "minecraft:infested_mossy_stone_bricks" => Some(crate::Item::InfestedMossyStoneBricks), + "minecraft:infested_stone" => Some(crate::Item::InfestedStone), + "minecraft:infested_stone_bricks" => Some(crate::Item::InfestedStoneBricks), + "minecraft:ink_sac" => Some(crate::Item::InkSac), + "minecraft:iron_axe" => Some(crate::Item::IronAxe), + "minecraft:iron_bars" => Some(crate::Item::IronBars), + "minecraft:iron_block" => Some(crate::Item::IronBlock), + "minecraft:iron_boots" => Some(crate::Item::IronBoots), + "minecraft:iron_chestplate" => Some(crate::Item::IronChestplate), + "minecraft:iron_door" => Some(crate::Item::IronDoor), + "minecraft:iron_helmet" => Some(crate::Item::IronHelmet), + "minecraft:iron_hoe" => Some(crate::Item::IronHoe), + "minecraft:iron_horse_armor" => Some(crate::Item::IronHorseArmor), + "minecraft:iron_ingot" => Some(crate::Item::IronIngot), + "minecraft:iron_leggings" => Some(crate::Item::IronLeggings), + "minecraft:iron_nugget" => Some(crate::Item::IronNugget), + "minecraft:iron_ore" => Some(crate::Item::IronOre), + "minecraft:iron_pickaxe" => Some(crate::Item::IronPickaxe), + "minecraft:iron_shovel" => Some(crate::Item::IronShovel), + "minecraft:iron_sword" => Some(crate::Item::IronSword), + "minecraft:iron_trapdoor" => Some(crate::Item::IronTrapdoor), + "minecraft:item_frame" => Some(crate::Item::ItemFrame), + "minecraft:jack_o_lantern" => Some(crate::Item::JackOLantern), + "minecraft:jukebox" => Some(crate::Item::Jukebox), + "minecraft:jungle_boat" => Some(crate::Item::JungleBoat), + "minecraft:jungle_button" => Some(crate::Item::JungleButton), + "minecraft:jungle_door" => Some(crate::Item::JungleDoor), + "minecraft:jungle_fence" => Some(crate::Item::JungleFence), + "minecraft:jungle_fence_gate" => Some(crate::Item::JungleFenceGate), + "minecraft:jungle_leaves" => Some(crate::Item::JungleLeaves), + "minecraft:jungle_log" => Some(crate::Item::JungleLog), + "minecraft:jungle_planks" => Some(crate::Item::JunglePlanks), + "minecraft:jungle_pressure_plate" => Some(crate::Item::JunglePressurePlate), + "minecraft:jungle_sapling" => Some(crate::Item::JungleSapling), + "minecraft:jungle_slab" => Some(crate::Item::JungleSlab), + "minecraft:jungle_stairs" => Some(crate::Item::JungleStairs), + "minecraft:jungle_trapdoor" => Some(crate::Item::JungleTrapdoor), + "minecraft:jungle_wood" => Some(crate::Item::JungleWood), + "minecraft:kelp" => Some(crate::Item::Kelp), + "minecraft:knowledge_book" => Some(crate::Item::KnowledgeBook), + "minecraft:ladder" => Some(crate::Item::Ladder), + "minecraft:lapis_block" => Some(crate::Item::LapisBlock), + "minecraft:lapis_lazuli" => Some(crate::Item::LapisLazuli), + "minecraft:lapis_ore" => Some(crate::Item::LapisOre), + "minecraft:large_fern" => Some(crate::Item::LargeFern), + "minecraft:lava_bucket" => Some(crate::Item::LavaBucket), + "minecraft:lead" => Some(crate::Item::Lead), + "minecraft:leather" => Some(crate::Item::Leather), + "minecraft:leather_boots" => Some(crate::Item::LeatherBoots), + "minecraft:leather_chestplate" => Some(crate::Item::LeatherChestplate), + "minecraft:leather_helmet" => Some(crate::Item::LeatherHelmet), + "minecraft:leather_leggings" => Some(crate::Item::LeatherLeggings), + "minecraft:lever" => Some(crate::Item::Lever), + "minecraft:light_blue_banner" => Some(crate::Item::LightBlueBanner), + "minecraft:light_blue_bed" => Some(crate::Item::LightBlueBed), + "minecraft:light_blue_carpet" => Some(crate::Item::LightBlueCarpet), + "minecraft:light_blue_concrete" => Some(crate::Item::LightBlueConcrete), + "minecraft:light_blue_concrete_powder" => Some(crate::Item::LightBlueConcretePowder), + "minecraft:light_blue_dye" => Some(crate::Item::LightBlueDye), + "minecraft:light_blue_glazed_terracotta" => { + Some(crate::Item::LightBlueGlazedTerracotta) + } + "minecraft:light_blue_shulker_box" => Some(crate::Item::LightBlueShulkerBox), + "minecraft:light_blue_stained_glass" => Some(crate::Item::LightBlueStainedGlass), + "minecraft:light_blue_stained_glass_pane" => { + Some(crate::Item::LightBlueStainedGlassPane) + } + "minecraft:light_blue_terracotta" => Some(crate::Item::LightBlueTerracotta), + "minecraft:light_blue_wool" => Some(crate::Item::LightBlueWool), + "minecraft:light_gray_banner" => Some(crate::Item::LightGrayBanner), + "minecraft:light_gray_bed" => Some(crate::Item::LightGrayBed), + "minecraft:light_gray_carpet" => Some(crate::Item::LightGrayCarpet), + "minecraft:light_gray_concrete" => Some(crate::Item::LightGrayConcrete), + "minecraft:light_gray_concrete_powder" => Some(crate::Item::LightGrayConcretePowder), + "minecraft:light_gray_dye" => Some(crate::Item::LightGrayDye), + "minecraft:light_gray_glazed_terracotta" => { + Some(crate::Item::LightGrayGlazedTerracotta) + } + "minecraft:light_gray_shulker_box" => Some(crate::Item::LightGrayShulkerBox), + "minecraft:light_gray_stained_glass" => Some(crate::Item::LightGrayStainedGlass), + "minecraft:light_gray_stained_glass_pane" => { + Some(crate::Item::LightGrayStainedGlassPane) + } + "minecraft:light_gray_terracotta" => Some(crate::Item::LightGrayTerracotta), + "minecraft:light_gray_wool" => Some(crate::Item::LightGrayWool), + "minecraft:light_weighted_pressure_plate" => { + Some(crate::Item::LightWeightedPressurePlate) + } + "minecraft:lilac" => Some(crate::Item::Lilac), + "minecraft:lily_pad" => Some(crate::Item::LilyPad), + "minecraft:lime_banner" => Some(crate::Item::LimeBanner), + "minecraft:lime_bed" => Some(crate::Item::LimeBed), + "minecraft:lime_carpet" => Some(crate::Item::LimeCarpet), + "minecraft:lime_concrete" => Some(crate::Item::LimeConcrete), + "minecraft:lime_concrete_powder" => Some(crate::Item::LimeConcretePowder), + "minecraft:lime_dye" => Some(crate::Item::LimeDye), + "minecraft:lime_glazed_terracotta" => Some(crate::Item::LimeGlazedTerracotta), + "minecraft:lime_shulker_box" => Some(crate::Item::LimeShulkerBox), + "minecraft:lime_stained_glass" => Some(crate::Item::LimeStainedGlass), + "minecraft:lime_stained_glass_pane" => Some(crate::Item::LimeStainedGlassPane), + "minecraft:lime_terracotta" => Some(crate::Item::LimeTerracotta), + "minecraft:lime_wool" => Some(crate::Item::LimeWool), + "minecraft:lingering_potion" => Some(crate::Item::LingeringPotion), + "minecraft:llama_spawn_egg" => Some(crate::Item::LlamaSpawnEgg), + "minecraft:magenta_banner" => Some(crate::Item::MagentaBanner), + "minecraft:magenta_bed" => Some(crate::Item::MagentaBed), + "minecraft:magenta_carpet" => Some(crate::Item::MagentaCarpet), + "minecraft:magenta_concrete" => Some(crate::Item::MagentaConcrete), + "minecraft:magenta_concrete_powder" => Some(crate::Item::MagentaConcretePowder), + "minecraft:magenta_dye" => Some(crate::Item::MagentaDye), + "minecraft:magenta_glazed_terracotta" => Some(crate::Item::MagentaGlazedTerracotta), + "minecraft:magenta_shulker_box" => Some(crate::Item::MagentaShulkerBox), + "minecraft:magenta_stained_glass" => Some(crate::Item::MagentaStainedGlass), + "minecraft:magenta_stained_glass_pane" => Some(crate::Item::MagentaStainedGlassPane), + "minecraft:magenta_terracotta" => Some(crate::Item::MagentaTerracotta), + "minecraft:magenta_wool" => Some(crate::Item::MagentaWool), + "minecraft:magma_block" => Some(crate::Item::MagmaBlock), + "minecraft:magma_cream" => Some(crate::Item::MagmaCream), + "minecraft:magma_cube_spawn_egg" => Some(crate::Item::MagmaCubeSpawnEgg), + "minecraft:map" => Some(crate::Item::Map), + "minecraft:melon" => Some(crate::Item::Melon), + "minecraft:melon_seeds" => Some(crate::Item::MelonSeeds), + "minecraft:melon_slice" => Some(crate::Item::MelonSlice), + "minecraft:milk_bucket" => Some(crate::Item::MilkBucket), + "minecraft:minecart" => Some(crate::Item::Minecart), + "minecraft:mooshroom_spawn_egg" => Some(crate::Item::MooshroomSpawnEgg), + "minecraft:mossy_cobblestone" => Some(crate::Item::MossyCobblestone), + "minecraft:mossy_cobblestone_wall" => Some(crate::Item::MossyCobblestoneWall), + "minecraft:mossy_stone_bricks" => Some(crate::Item::MossyStoneBricks), + "minecraft:mule_spawn_egg" => Some(crate::Item::MuleSpawnEgg), + "minecraft:mushroom_stem" => Some(crate::Item::MushroomStem), + "minecraft:mushroom_stew" => Some(crate::Item::MushroomStew), + "minecraft:music_disc_11" => Some(crate::Item::MusicDisc11), + "minecraft:music_disc_13" => Some(crate::Item::MusicDisc13), + "minecraft:music_disc_blocks" => Some(crate::Item::MusicDiscBlocks), + "minecraft:music_disc_cat" => Some(crate::Item::MusicDiscCat), + "minecraft:music_disc_chirp" => Some(crate::Item::MusicDiscChirp), + "minecraft:music_disc_far" => Some(crate::Item::MusicDiscFar), + "minecraft:music_disc_mall" => Some(crate::Item::MusicDiscMall), + "minecraft:music_disc_mellohi" => Some(crate::Item::MusicDiscMellohi), + "minecraft:music_disc_stal" => Some(crate::Item::MusicDiscStal), + "minecraft:music_disc_strad" => Some(crate::Item::MusicDiscStrad), + "minecraft:music_disc_wait" => Some(crate::Item::MusicDiscWait), + "minecraft:music_disc_ward" => Some(crate::Item::MusicDiscWard), + "minecraft:mutton" => Some(crate::Item::Mutton), + "minecraft:mycelium" => Some(crate::Item::Mycelium), + "minecraft:name_tag" => Some(crate::Item::NameTag), + "minecraft:nautilus_shell" => Some(crate::Item::NautilusShell), + "minecraft:nether_brick" => Some(crate::Item::NetherBrick), + "minecraft:nether_brick_fence" => Some(crate::Item::NetherBrickFence), + "minecraft:nether_brick_slab" => Some(crate::Item::NetherBrickSlab), + "minecraft:nether_brick_stairs" => Some(crate::Item::NetherBrickStairs), + "minecraft:nether_bricks" => Some(crate::Item::NetherBricks), + "minecraft:nether_quartz_ore" => Some(crate::Item::NetherQuartzOre), + "minecraft:nether_star" => Some(crate::Item::NetherStar), + "minecraft:nether_wart" => Some(crate::Item::NetherWart), + "minecraft:nether_wart_block" => Some(crate::Item::NetherWartBlock), + "minecraft:netherrack" => Some(crate::Item::Netherrack), + "minecraft:note_block" => Some(crate::Item::NoteBlock), + "minecraft:oak_boat" => Some(crate::Item::OakBoat), + "minecraft:oak_button" => Some(crate::Item::OakButton), + "minecraft:oak_door" => Some(crate::Item::OakDoor), + "minecraft:oak_fence" => Some(crate::Item::OakFence), + "minecraft:oak_fence_gate" => Some(crate::Item::OakFenceGate), + "minecraft:oak_leaves" => Some(crate::Item::OakLeaves), + "minecraft:oak_log" => Some(crate::Item::OakLog), + "minecraft:oak_planks" => Some(crate::Item::OakPlanks), + "minecraft:oak_pressure_plate" => Some(crate::Item::OakPressurePlate), + "minecraft:oak_sapling" => Some(crate::Item::OakSapling), + "minecraft:oak_slab" => Some(crate::Item::OakSlab), + "minecraft:oak_stairs" => Some(crate::Item::OakStairs), + "minecraft:oak_trapdoor" => Some(crate::Item::OakTrapdoor), + "minecraft:oak_wood" => Some(crate::Item::OakWood), + "minecraft:observer" => Some(crate::Item::Observer), + "minecraft:obsidian" => Some(crate::Item::Obsidian), + "minecraft:ocelot_spawn_egg" => Some(crate::Item::OcelotSpawnEgg), + "minecraft:orange_banner" => Some(crate::Item::OrangeBanner), + "minecraft:orange_bed" => Some(crate::Item::OrangeBed), + "minecraft:orange_carpet" => Some(crate::Item::OrangeCarpet), + "minecraft:orange_concrete" => Some(crate::Item::OrangeConcrete), + "minecraft:orange_concrete_powder" => Some(crate::Item::OrangeConcretePowder), + "minecraft:orange_dye" => Some(crate::Item::OrangeDye), + "minecraft:orange_glazed_terracotta" => Some(crate::Item::OrangeGlazedTerracotta), + "minecraft:orange_shulker_box" => Some(crate::Item::OrangeShulkerBox), + "minecraft:orange_stained_glass" => Some(crate::Item::OrangeStainedGlass), + "minecraft:orange_stained_glass_pane" => Some(crate::Item::OrangeStainedGlassPane), + "minecraft:orange_terracotta" => Some(crate::Item::OrangeTerracotta), + "minecraft:orange_tulip" => Some(crate::Item::OrangeTulip), + "minecraft:orange_wool" => Some(crate::Item::OrangeWool), + "minecraft:oxeye_daisy" => Some(crate::Item::OxeyeDaisy), + "minecraft:packed_ice" => Some(crate::Item::PackedIce), + "minecraft:painting" => Some(crate::Item::Painting), + "minecraft:paper" => Some(crate::Item::Paper), + "minecraft:parrot_spawn_egg" => Some(crate::Item::ParrotSpawnEgg), + "minecraft:peony" => Some(crate::Item::Peony), + "minecraft:petrified_oak_slab" => Some(crate::Item::PetrifiedOakSlab), + "minecraft:phantom_membrane" => Some(crate::Item::PhantomMembrane), + "minecraft:phantom_spawn_egg" => Some(crate::Item::PhantomSpawnEgg), + "minecraft:pig_spawn_egg" => Some(crate::Item::PigSpawnEgg), + "minecraft:pink_banner" => Some(crate::Item::PinkBanner), + "minecraft:pink_bed" => Some(crate::Item::PinkBed), + "minecraft:pink_carpet" => Some(crate::Item::PinkCarpet), + "minecraft:pink_concrete" => Some(crate::Item::PinkConcrete), + "minecraft:pink_concrete_powder" => Some(crate::Item::PinkConcretePowder), + "minecraft:pink_dye" => Some(crate::Item::PinkDye), + "minecraft:pink_glazed_terracotta" => Some(crate::Item::PinkGlazedTerracotta), + "minecraft:pink_shulker_box" => Some(crate::Item::PinkShulkerBox), + "minecraft:pink_stained_glass" => Some(crate::Item::PinkStainedGlass), + "minecraft:pink_stained_glass_pane" => Some(crate::Item::PinkStainedGlassPane), + "minecraft:pink_terracotta" => Some(crate::Item::PinkTerracotta), + "minecraft:pink_tulip" => Some(crate::Item::PinkTulip), + "minecraft:pink_wool" => Some(crate::Item::PinkWool), + "minecraft:piston" => Some(crate::Item::Piston), + "minecraft:player_head" => Some(crate::Item::PlayerHead), + "minecraft:podzol" => Some(crate::Item::Podzol), + "minecraft:poisonous_potato" => Some(crate::Item::PoisonousPotato), + "minecraft:polar_bear_spawn_egg" => Some(crate::Item::PolarBearSpawnEgg), + "minecraft:polished_andesite" => Some(crate::Item::PolishedAndesite), + "minecraft:polished_diorite" => Some(crate::Item::PolishedDiorite), + "minecraft:polished_granite" => Some(crate::Item::PolishedGranite), + "minecraft:popped_chorus_fruit" => Some(crate::Item::PoppedChorusFruit), + "minecraft:poppy" => Some(crate::Item::Poppy), + "minecraft:porkchop" => Some(crate::Item::Porkchop), + "minecraft:potato" => Some(crate::Item::Potato), + "minecraft:potion" => Some(crate::Item::Potion), + "minecraft:powered_rail" => Some(crate::Item::PoweredRail), + "minecraft:prismarine" => Some(crate::Item::Prismarine), + "minecraft:prismarine_brick_slab" => Some(crate::Item::PrismarineBrickSlab), + "minecraft:prismarine_brick_stairs" => Some(crate::Item::PrismarineBrickStairs), + "minecraft:prismarine_bricks" => Some(crate::Item::PrismarineBricks), + "minecraft:prismarine_crystals" => Some(crate::Item::PrismarineCrystals), + "minecraft:prismarine_shard" => Some(crate::Item::PrismarineShard), + "minecraft:prismarine_slab" => Some(crate::Item::PrismarineSlab), + "minecraft:prismarine_stairs" => Some(crate::Item::PrismarineStairs), + "minecraft:pufferfish" => Some(crate::Item::Pufferfish), + "minecraft:pufferfish_bucket" => Some(crate::Item::PufferfishBucket), + "minecraft:pufferfish_spawn_egg" => Some(crate::Item::PufferfishSpawnEgg), + "minecraft:pumpkin" => Some(crate::Item::Pumpkin), + "minecraft:pumpkin_pie" => Some(crate::Item::PumpkinPie), + "minecraft:pumpkin_seeds" => Some(crate::Item::PumpkinSeeds), + "minecraft:purple_banner" => Some(crate::Item::PurpleBanner), + "minecraft:purple_bed" => Some(crate::Item::PurpleBed), + "minecraft:purple_carpet" => Some(crate::Item::PurpleCarpet), + "minecraft:purple_concrete" => Some(crate::Item::PurpleConcrete), + "minecraft:purple_concrete_powder" => Some(crate::Item::PurpleConcretePowder), + "minecraft:purple_dye" => Some(crate::Item::PurpleDye), + "minecraft:purple_glazed_terracotta" => Some(crate::Item::PurpleGlazedTerracotta), + "minecraft:purple_shulker_box" => Some(crate::Item::PurpleShulkerBox), + "minecraft:purple_stained_glass" => Some(crate::Item::PurpleStainedGlass), + "minecraft:purple_stained_glass_pane" => Some(crate::Item::PurpleStainedGlassPane), + "minecraft:purple_terracotta" => Some(crate::Item::PurpleTerracotta), + "minecraft:purple_wool" => Some(crate::Item::PurpleWool), + "minecraft:purpur_block" => Some(crate::Item::PurpurBlock), + "minecraft:purpur_pillar" => Some(crate::Item::PurpurPillar), + "minecraft:purpur_slab" => Some(crate::Item::PurpurSlab), + "minecraft:purpur_stairs" => Some(crate::Item::PurpurStairs), + "minecraft:quartz" => Some(crate::Item::Quartz), + "minecraft:quartz_block" => Some(crate::Item::QuartzBlock), + "minecraft:quartz_pillar" => Some(crate::Item::QuartzPillar), + "minecraft:quartz_slab" => Some(crate::Item::QuartzSlab), + "minecraft:quartz_stairs" => Some(crate::Item::QuartzStairs), + "minecraft:rabbit" => Some(crate::Item::Rabbit), + "minecraft:rabbit_foot" => Some(crate::Item::RabbitFoot), + "minecraft:rabbit_hide" => Some(crate::Item::RabbitHide), + "minecraft:rabbit_spawn_egg" => Some(crate::Item::RabbitSpawnEgg), + "minecraft:rabbit_stew" => Some(crate::Item::RabbitStew), + "minecraft:rail" => Some(crate::Item::Rail), + "minecraft:red_banner" => Some(crate::Item::RedBanner), + "minecraft:red_bed" => Some(crate::Item::RedBed), + "minecraft:red_carpet" => Some(crate::Item::RedCarpet), + "minecraft:red_concrete" => Some(crate::Item::RedConcrete), + "minecraft:red_concrete_powder" => Some(crate::Item::RedConcretePowder), + "minecraft:red_glazed_terracotta" => Some(crate::Item::RedGlazedTerracotta), + "minecraft:red_mushroom" => Some(crate::Item::RedMushroom), + "minecraft:red_mushroom_block" => Some(crate::Item::RedMushroomBlock), + "minecraft:red_nether_bricks" => Some(crate::Item::RedNetherBricks), + "minecraft:red_sand" => Some(crate::Item::RedSand), + "minecraft:red_sandstone" => Some(crate::Item::RedSandstone), + "minecraft:red_sandstone_slab" => Some(crate::Item::RedSandstoneSlab), + "minecraft:red_sandstone_stairs" => Some(crate::Item::RedSandstoneStairs), + "minecraft:red_shulker_box" => Some(crate::Item::RedShulkerBox), + "minecraft:red_stained_glass" => Some(crate::Item::RedStainedGlass), + "minecraft:red_stained_glass_pane" => Some(crate::Item::RedStainedGlassPane), + "minecraft:red_terracotta" => Some(crate::Item::RedTerracotta), + "minecraft:red_tulip" => Some(crate::Item::RedTulip), + "minecraft:red_wool" => Some(crate::Item::RedWool), + "minecraft:redstone" => Some(crate::Item::Redstone), + "minecraft:redstone_block" => Some(crate::Item::RedstoneBlock), + "minecraft:redstone_lamp" => Some(crate::Item::RedstoneLamp), + "minecraft:redstone_ore" => Some(crate::Item::RedstoneOre), + "minecraft:redstone_torch" => Some(crate::Item::RedstoneTorch), + "minecraft:repeater" => Some(crate::Item::Repeater), + "minecraft:repeating_command_block" => Some(crate::Item::RepeatingCommandBlock), + "minecraft:rose_bush" => Some(crate::Item::RoseBush), + "minecraft:rose_red" => Some(crate::Item::RoseRed), + "minecraft:rotten_flesh" => Some(crate::Item::RottenFlesh), + "minecraft:saddle" => Some(crate::Item::Saddle), + "minecraft:salmon" => Some(crate::Item::Salmon), + "minecraft:salmon_bucket" => Some(crate::Item::SalmonBucket), + "minecraft:salmon_spawn_egg" => Some(crate::Item::SalmonSpawnEgg), + "minecraft:sand" => Some(crate::Item::Sand), + "minecraft:sandstone" => Some(crate::Item::Sandstone), + "minecraft:sandstone_slab" => Some(crate::Item::SandstoneSlab), + "minecraft:sandstone_stairs" => Some(crate::Item::SandstoneStairs), + "minecraft:scute" => Some(crate::Item::Scute), + "minecraft:sea_lantern" => Some(crate::Item::SeaLantern), + "minecraft:sea_pickle" => Some(crate::Item::SeaPickle), + "minecraft:seagrass" => Some(crate::Item::Seagrass), + "minecraft:shears" => Some(crate::Item::Shears), + "minecraft:sheep_spawn_egg" => Some(crate::Item::SheepSpawnEgg), + "minecraft:shield" => Some(crate::Item::Shield), + "minecraft:shulker_box" => Some(crate::Item::ShulkerBox), + "minecraft:shulker_shell" => Some(crate::Item::ShulkerShell), + "minecraft:shulker_spawn_egg" => Some(crate::Item::ShulkerSpawnEgg), + "minecraft:sign" => Some(crate::Item::Sign), + "minecraft:silverfish_spawn_egg" => Some(crate::Item::SilverfishSpawnEgg), + "minecraft:skeleton_horse_spawn_egg" => Some(crate::Item::SkeletonHorseSpawnEgg), + "minecraft:skeleton_skull" => Some(crate::Item::SkeletonSkull), + "minecraft:skeleton_spawn_egg" => Some(crate::Item::SkeletonSpawnEgg), + "minecraft:slime_ball" => Some(crate::Item::SlimeBall), + "minecraft:slime_block" => Some(crate::Item::SlimeBlock), + "minecraft:slime_spawn_egg" => Some(crate::Item::SlimeSpawnEgg), + "minecraft:smooth_quartz" => Some(crate::Item::SmoothQuartz), + "minecraft:smooth_red_sandstone" => Some(crate::Item::SmoothRedSandstone), + "minecraft:smooth_sandstone" => Some(crate::Item::SmoothSandstone), + "minecraft:smooth_stone" => Some(crate::Item::SmoothStone), + "minecraft:snow" => Some(crate::Item::Snow), + "minecraft:snow_block" => Some(crate::Item::SnowBlock), + "minecraft:snowball" => Some(crate::Item::Snowball), + "minecraft:soul_sand" => Some(crate::Item::SoulSand), + "minecraft:spawner" => Some(crate::Item::Spawner), + "minecraft:spectral_arrow" => Some(crate::Item::SpectralArrow), + "minecraft:spider_eye" => Some(crate::Item::SpiderEye), + "minecraft:spider_spawn_egg" => Some(crate::Item::SpiderSpawnEgg), + "minecraft:splash_potion" => Some(crate::Item::SplashPotion), + "minecraft:sponge" => Some(crate::Item::Sponge), + "minecraft:spruce_boat" => Some(crate::Item::SpruceBoat), + "minecraft:spruce_button" => Some(crate::Item::SpruceButton), + "minecraft:spruce_door" => Some(crate::Item::SpruceDoor), + "minecraft:spruce_fence" => Some(crate::Item::SpruceFence), + "minecraft:spruce_fence_gate" => Some(crate::Item::SpruceFenceGate), + "minecraft:spruce_leaves" => Some(crate::Item::SpruceLeaves), + "minecraft:spruce_log" => Some(crate::Item::SpruceLog), + "minecraft:spruce_planks" => Some(crate::Item::SprucePlanks), + "minecraft:spruce_pressure_plate" => Some(crate::Item::SprucePressurePlate), + "minecraft:spruce_sapling" => Some(crate::Item::SpruceSapling), + "minecraft:spruce_slab" => Some(crate::Item::SpruceSlab), + "minecraft:spruce_stairs" => Some(crate::Item::SpruceStairs), + "minecraft:spruce_trapdoor" => Some(crate::Item::SpruceTrapdoor), + "minecraft:spruce_wood" => Some(crate::Item::SpruceWood), + "minecraft:squid_spawn_egg" => Some(crate::Item::SquidSpawnEgg), + "minecraft:stick" => Some(crate::Item::Stick), + "minecraft:sticky_piston" => Some(crate::Item::StickyPiston), + "minecraft:stone" => Some(crate::Item::Stone), + "minecraft:stone_axe" => Some(crate::Item::StoneAxe), + "minecraft:stone_brick_slab" => Some(crate::Item::StoneBrickSlab), + "minecraft:stone_brick_stairs" => Some(crate::Item::StoneBrickStairs), + "minecraft:stone_bricks" => Some(crate::Item::StoneBricks), + "minecraft:stone_button" => Some(crate::Item::StoneButton), + "minecraft:stone_hoe" => Some(crate::Item::StoneHoe), + "minecraft:stone_pickaxe" => Some(crate::Item::StonePickaxe), + "minecraft:stone_pressure_plate" => Some(crate::Item::StonePressurePlate), + "minecraft:stone_shovel" => Some(crate::Item::StoneShovel), + "minecraft:stone_slab" => Some(crate::Item::StoneSlab), + "minecraft:stone_sword" => Some(crate::Item::StoneSword), + "minecraft:stray_spawn_egg" => Some(crate::Item::StraySpawnEgg), + "minecraft:string" => Some(crate::Item::String), + "minecraft:stripped_acacia_log" => Some(crate::Item::StrippedAcaciaLog), + "minecraft:stripped_acacia_wood" => Some(crate::Item::StrippedAcaciaWood), + "minecraft:stripped_birch_log" => Some(crate::Item::StrippedBirchLog), + "minecraft:stripped_birch_wood" => Some(crate::Item::StrippedBirchWood), + "minecraft:stripped_dark_oak_log" => Some(crate::Item::StrippedDarkOakLog), + "minecraft:stripped_dark_oak_wood" => Some(crate::Item::StrippedDarkOakWood), + "minecraft:stripped_jungle_log" => Some(crate::Item::StrippedJungleLog), + "minecraft:stripped_jungle_wood" => Some(crate::Item::StrippedJungleWood), + "minecraft:stripped_oak_log" => Some(crate::Item::StrippedOakLog), + "minecraft:stripped_oak_wood" => Some(crate::Item::StrippedOakWood), + "minecraft:stripped_spruce_log" => Some(crate::Item::StrippedSpruceLog), + "minecraft:stripped_spruce_wood" => Some(crate::Item::StrippedSpruceWood), + "minecraft:structure_block" => Some(crate::Item::StructureBlock), + "minecraft:structure_void" => Some(crate::Item::StructureVoid), + "minecraft:sugar" => Some(crate::Item::Sugar), + "minecraft:sugar_cane" => Some(crate::Item::SugarCane), + "minecraft:sunflower" => Some(crate::Item::Sunflower), + "minecraft:tall_grass" => Some(crate::Item::TallGrass), + "minecraft:terracotta" => Some(crate::Item::Terracotta), + "minecraft:tipped_arrow" => Some(crate::Item::TippedArrow), + "minecraft:tnt" => Some(crate::Item::Tnt), + "minecraft:tnt_minecart" => Some(crate::Item::TntMinecart), + "minecraft:torch" => Some(crate::Item::Torch), + "minecraft:totem_of_undying" => Some(crate::Item::TotemOfUndying), + "minecraft:trapped_chest" => Some(crate::Item::TrappedChest), + "minecraft:trident" => Some(crate::Item::Trident), + "minecraft:tripwire_hook" => Some(crate::Item::TripwireHook), + "minecraft:tropical_fish" => Some(crate::Item::TropicalFish), + "minecraft:tropical_fish_bucket" => Some(crate::Item::TropicalFishBucket), + "minecraft:tropical_fish_spawn_egg" => Some(crate::Item::TropicalFishSpawnEgg), + "minecraft:tube_coral" => Some(crate::Item::TubeCoral), + "minecraft:tube_coral_block" => Some(crate::Item::TubeCoralBlock), + "minecraft:tube_coral_fan" => Some(crate::Item::TubeCoralFan), + "minecraft:turtle_egg" => Some(crate::Item::TurtleEgg), + "minecraft:turtle_helmet" => Some(crate::Item::TurtleHelmet), + "minecraft:turtle_spawn_egg" => Some(crate::Item::TurtleSpawnEgg), + "minecraft:vex_spawn_egg" => Some(crate::Item::VexSpawnEgg), + "minecraft:villager_spawn_egg" => Some(crate::Item::VillagerSpawnEgg), + "minecraft:vindicator_spawn_egg" => Some(crate::Item::VindicatorSpawnEgg), + "minecraft:vine" => Some(crate::Item::Vine), + "minecraft:water_bucket" => Some(crate::Item::WaterBucket), + "minecraft:wet_sponge" => Some(crate::Item::WetSponge), + "minecraft:wheat" => Some(crate::Item::Wheat), + "minecraft:wheat_seeds" => Some(crate::Item::WheatSeeds), + "minecraft:white_banner" => Some(crate::Item::WhiteBanner), + "minecraft:white_bed" => Some(crate::Item::WhiteBed), + "minecraft:white_carpet" => Some(crate::Item::WhiteCarpet), + "minecraft:white_concrete" => Some(crate::Item::WhiteConcrete), + "minecraft:white_concrete_powder" => Some(crate::Item::WhiteConcretePowder), + "minecraft:white_glazed_terracotta" => Some(crate::Item::WhiteGlazedTerracotta), + "minecraft:white_shulker_box" => Some(crate::Item::WhiteShulkerBox), + "minecraft:white_stained_glass" => Some(crate::Item::WhiteStainedGlass), + "minecraft:white_stained_glass_pane" => Some(crate::Item::WhiteStainedGlassPane), + "minecraft:white_terracotta" => Some(crate::Item::WhiteTerracotta), + "minecraft:white_tulip" => Some(crate::Item::WhiteTulip), + "minecraft:white_wool" => Some(crate::Item::WhiteWool), + "minecraft:witch_spawn_egg" => Some(crate::Item::WitchSpawnEgg), + "minecraft:wither_skeleton_skull" => Some(crate::Item::WitherSkeletonSkull), + "minecraft:wither_skeleton_spawn_egg" => Some(crate::Item::WitherSkeletonSpawnEgg), + "minecraft:wolf_spawn_egg" => Some(crate::Item::WolfSpawnEgg), + "minecraft:wooden_axe" => Some(crate::Item::WoodenAxe), + "minecraft:wooden_hoe" => Some(crate::Item::WoodenHoe), + "minecraft:wooden_pickaxe" => Some(crate::Item::WoodenPickaxe), + "minecraft:wooden_shovel" => Some(crate::Item::WoodenShovel), + "minecraft:wooden_sword" => Some(crate::Item::WoodenSword), + "minecraft:writable_book" => Some(crate::Item::WritableBook), + "minecraft:written_book" => Some(crate::Item::WrittenBook), + "minecraft:yellow_banner" => Some(crate::Item::YellowBanner), + "minecraft:yellow_bed" => Some(crate::Item::YellowBed), + "minecraft:yellow_carpet" => Some(crate::Item::YellowCarpet), + "minecraft:yellow_concrete" => Some(crate::Item::YellowConcrete), + "minecraft:yellow_concrete_powder" => Some(crate::Item::YellowConcretePowder), + "minecraft:yellow_glazed_terracotta" => Some(crate::Item::YellowGlazedTerracotta), + "minecraft:yellow_shulker_box" => Some(crate::Item::YellowShulkerBox), + "minecraft:yellow_stained_glass" => Some(crate::Item::YellowStainedGlass), + "minecraft:yellow_stained_glass_pane" => Some(crate::Item::YellowStainedGlassPane), + "minecraft:yellow_terracotta" => Some(crate::Item::YellowTerracotta), + "minecraft:yellow_wool" => Some(crate::Item::YellowWool), + "minecraft:zombie_head" => Some(crate::Item::ZombieHead), + "minecraft:zombie_horse_spawn_egg" => Some(crate::Item::ZombieHorseSpawnEgg), + "minecraft:zombie_pigman_spawn_egg" => Some(crate::Item::ZombiePigmanSpawnEgg), + "minecraft:zombie_spawn_egg" => Some(crate::Item::ZombieSpawnEgg), + "minecraft:zombie_villager_spawn_egg" => Some(crate::Item::ZombieVillagerSpawnEgg), + _ => None, + } + } +} diff --git a/feather/old/definitions/src/generated/mod.rs b/feather/old/definitions/src/generated/mod.rs new file mode 100644 index 000000000..c31a04cd9 --- /dev/null +++ b/feather/old/definitions/src/generated/mod.rs @@ -0,0 +1,7 @@ +// This file is @generated +mod block; +pub use block::*; +mod item; +pub use item::*; +mod tool; +pub use tool::*; diff --git a/feather/old/definitions/src/generated/tool.rs b/feather/old/definitions/src/generated/tool.rs new file mode 100644 index 000000000..b7c28d5d3 --- /dev/null +++ b/feather/old/definitions/src/generated/tool.rs @@ -0,0 +1,178 @@ +// This file is @generated +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ToPrimitive, FromPrimitive)] +pub enum Tool { + Axe, + Pickaxe, + Shovel, + Hoe, + Sword, + Shears, +} +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ToPrimitive, FromPrimitive)] +pub enum ToolMaterial { + Wooden, + Stone, + Iron, + Diamond, + Golden, +} +impl crate::Item { + pub fn tool(self) -> Option<crate::Tool> { + match self { + crate::Item::DiamondAxe => Some(crate::Tool::Axe), + crate::Item::DiamondHoe => Some(crate::Tool::Hoe), + crate::Item::DiamondPickaxe => Some(crate::Tool::Pickaxe), + crate::Item::DiamondShovel => Some(crate::Tool::Shovel), + crate::Item::DiamondSword => Some(crate::Tool::Sword), + crate::Item::GoldenAxe => Some(crate::Tool::Axe), + crate::Item::GoldenHoe => Some(crate::Tool::Hoe), + crate::Item::GoldenPickaxe => Some(crate::Tool::Pickaxe), + crate::Item::GoldenShovel => Some(crate::Tool::Shovel), + crate::Item::GoldenSword => Some(crate::Tool::Sword), + crate::Item::IronAxe => Some(crate::Tool::Axe), + crate::Item::IronHoe => Some(crate::Tool::Hoe), + crate::Item::IronPickaxe => Some(crate::Tool::Pickaxe), + crate::Item::IronShovel => Some(crate::Tool::Shovel), + crate::Item::IronSword => Some(crate::Tool::Sword), + crate::Item::Shears => Some(crate::Tool::Shears), + crate::Item::StoneAxe => Some(crate::Tool::Axe), + crate::Item::StoneHoe => Some(crate::Tool::Hoe), + crate::Item::StonePickaxe => Some(crate::Tool::Pickaxe), + crate::Item::StoneShovel => Some(crate::Tool::Shovel), + crate::Item::StoneSword => Some(crate::Tool::Sword), + crate::Item::WoodenAxe => Some(crate::Tool::Axe), + crate::Item::WoodenHoe => Some(crate::Tool::Hoe), + crate::Item::WoodenPickaxe => Some(crate::Tool::Pickaxe), + crate::Item::WoodenShovel => Some(crate::Tool::Shovel), + crate::Item::WoodenSword => Some(crate::Tool::Sword), + _ => None, + } + } +} +impl crate::Item { + pub fn tool_material(self) -> Option<crate::ToolMaterial> { + match self { + crate::Item::DiamondAxe => Some(crate::ToolMaterial::Diamond), + crate::Item::DiamondHoe => Some(crate::ToolMaterial::Diamond), + crate::Item::DiamondPickaxe => Some(crate::ToolMaterial::Diamond), + crate::Item::DiamondShovel => Some(crate::ToolMaterial::Diamond), + crate::Item::DiamondSword => Some(crate::ToolMaterial::Diamond), + crate::Item::GoldenAxe => Some(crate::ToolMaterial::Golden), + crate::Item::GoldenHoe => Some(crate::ToolMaterial::Golden), + crate::Item::GoldenPickaxe => Some(crate::ToolMaterial::Golden), + crate::Item::GoldenShovel => Some(crate::ToolMaterial::Golden), + crate::Item::GoldenSword => Some(crate::ToolMaterial::Golden), + crate::Item::IronAxe => Some(crate::ToolMaterial::Iron), + crate::Item::IronHoe => Some(crate::ToolMaterial::Iron), + crate::Item::IronPickaxe => Some(crate::ToolMaterial::Iron), + crate::Item::IronShovel => Some(crate::ToolMaterial::Iron), + crate::Item::IronSword => Some(crate::ToolMaterial::Iron), + crate::Item::StoneAxe => Some(crate::ToolMaterial::Stone), + crate::Item::StoneHoe => Some(crate::ToolMaterial::Stone), + crate::Item::StonePickaxe => Some(crate::ToolMaterial::Stone), + crate::Item::StoneShovel => Some(crate::ToolMaterial::Stone), + crate::Item::StoneSword => Some(crate::ToolMaterial::Stone), + crate::Item::WoodenAxe => Some(crate::ToolMaterial::Wooden), + crate::Item::WoodenHoe => Some(crate::ToolMaterial::Wooden), + crate::Item::WoodenPickaxe => Some(crate::ToolMaterial::Wooden), + crate::Item::WoodenShovel => Some(crate::ToolMaterial::Wooden), + crate::Item::WoodenSword => Some(crate::ToolMaterial::Wooden), + _ => None, + } + } +} +impl crate::ToolMaterial { + pub fn dig_multiplier(self) -> f64 { + match self { + crate::ToolMaterial::Diamond => 8f64, + crate::ToolMaterial::Golden => 12f64, + crate::ToolMaterial::Iron => 6f64, + crate::ToolMaterial::Stone => 4f64, + crate::ToolMaterial::Wooden => 2f64, + } + } +} +impl crate::Item { + pub fn durability(self) -> Option<u32> { + match self { + crate::Item::Bow => Some(384u32), + crate::Item::CarrotOnAStick => Some(25u32), + crate::Item::ChainmailBoots => Some(195u32), + crate::Item::ChainmailChestplate => Some(240u32), + crate::Item::ChainmailHelmet => Some(165u32), + crate::Item::ChainmailLeggings => Some(225u32), + crate::Item::DiamondAxe => Some(1561u32), + crate::Item::DiamondBoots => Some(429u32), + crate::Item::DiamondChestplate => Some(528u32), + crate::Item::DiamondHelmet => Some(363u32), + crate::Item::DiamondHoe => Some(1561u32), + crate::Item::DiamondLeggings => Some(495u32), + crate::Item::DiamondPickaxe => Some(1561u32), + crate::Item::DiamondShovel => Some(1561u32), + crate::Item::DiamondSword => Some(1561u32), + crate::Item::Elytra => Some(432u32), + crate::Item::FishingRod => Some(64u32), + crate::Item::FlintAndSteel => Some(64u32), + crate::Item::GoldenAxe => Some(32u32), + crate::Item::GoldenBoots => Some(91u32), + crate::Item::GoldenChestplate => Some(112u32), + crate::Item::GoldenHelmet => Some(77u32), + crate::Item::GoldenHoe => Some(32u32), + crate::Item::GoldenLeggings => Some(105u32), + crate::Item::GoldenPickaxe => Some(32u32), + crate::Item::GoldenShovel => Some(32u32), + crate::Item::GoldenSword => Some(32u32), + crate::Item::IronAxe => Some(250u32), + crate::Item::IronBoots => Some(195u32), + crate::Item::IronChestplate => Some(240u32), + crate::Item::IronHelmet => Some(165u32), + crate::Item::IronHoe => Some(250u32), + crate::Item::IronLeggings => Some(225u32), + crate::Item::IronPickaxe => Some(250u32), + crate::Item::IronShovel => Some(250u32), + crate::Item::IronSword => Some(250u32), + crate::Item::LeatherBoots => Some(65u32), + crate::Item::LeatherChestplate => Some(80u32), + crate::Item::LeatherHelmet => Some(55u32), + crate::Item::LeatherLeggings => Some(75u32), + crate::Item::Shears => Some(238u32), + crate::Item::Shield => Some(336u32), + crate::Item::StoneAxe => Some(131u32), + crate::Item::StoneHoe => Some(131u32), + crate::Item::StonePickaxe => Some(131u32), + crate::Item::StoneShovel => Some(131u32), + crate::Item::StoneSword => Some(131u32), + crate::Item::Trident => Some(250u32), + crate::Item::WoodenAxe => Some(59u32), + crate::Item::WoodenHoe => Some(59u32), + crate::Item::WoodenPickaxe => Some(59u32), + crate::Item::WoodenShovel => Some(59u32), + crate::Item::WoodenSword => Some(59u32), + _ => None, + } + } +} +impl crate::BlockKind { + pub fn best_tool(self) -> Option<crate::Tool> { + match self { + crate::BlockKind::Cobblestone => Some(crate::Tool::Pickaxe), + crate::BlockKind::Dirt => Some(crate::Tool::Shovel), + crate::BlockKind::GrassBlock => Some(crate::Tool::Shovel), + crate::BlockKind::RedSand => Some(crate::Tool::Shovel), + crate::BlockKind::Sand => Some(crate::Tool::Shovel), + crate::BlockKind::Sandstone => Some(crate::Tool::Pickaxe), + crate::BlockKind::Stone => Some(crate::Tool::Pickaxe), + _ => None, + } + } +} +impl crate::BlockKind { + pub fn best_tool_required(self) -> bool { + match self { + crate::BlockKind::Cobblestone => true, + crate::BlockKind::Sandstone => true, + crate::BlockKind::Stone => true, + _ => false, + } + } +} diff --git a/feather/old/definitions/src/lib.rs b/feather/old/definitions/src/lib.rs new file mode 100644 index 000000000..6ec7c0e69 --- /dev/null +++ b/feather/old/definitions/src/lib.rs @@ -0,0 +1,13 @@ +#[macro_use] +extern crate num_derive; + +#[allow(warnings)] +mod generated; + +pub use generated::*; + +impl Default for BlockKind { + fn default() -> Self { + BlockKind::Air + } +} diff --git a/feather/old/server/Cargo.toml b/feather/old/server/Cargo.toml new file mode 100644 index 000000000..0c33e1e1e --- /dev/null +++ b/feather/old/server/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "feather-server" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" +default-run = "feather-server" + +[lib] +name = "feather_server" +path = "src/lib.rs" + +[[bin]] +name = "feather-server" +path = "src/main.rs" + +[dependencies] +# Feather crates +feather-core = { path = "../core" } +feather-server-block = { path = "block" } +feather-server-chat = { path = "chat" } +feather-server-chunk = { path = "chunk" } +feather-server-config = { path = "config" } +feather-server-entity = { path = "entity" } +feather-server-lighting = { path = "lighting" } +feather-server-network = { path = "network" } +feather-server-packet-buffer = { path = "packet_buffer" } +feather-server-physics = { path = "physics" } +feather-server-player = { path = "player" } +feather-server-types = { path = "types" } +feather-server-util = { path = "util" } +feather-server-weather = { path = "weather" } +feather-server-worldgen = { path = "worldgen" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +tokio = { version = "0.2", features = ["full"] } +simple_logger = "1.6" +log = "0.4" +anyhow = "1.0" +rand = "0.7" +fxhash = "0.2" +base64 = "0.12" +spin_sleep = "1.0" +crossbeam = "0.7" +ctrlc = "3.1" diff --git a/feather/old/server/README.md b/feather/old/server/README.md new file mode 100644 index 000000000..953038251 --- /dev/null +++ b/feather/old/server/README.md @@ -0,0 +1,30 @@ +`feather-server` and its subcrates, implementing a server on top of `feather-core`. + +### Subcrates + +Please see [the book](https://feather-rs.github.io/book) to find out in which crate new features belong. If you're +not sure where to put something, feel free to ask on our Discord. + +The philosophy here is to have many small crates to enforce modularity. If a crate starts getting +too large, it will be split into subcrates. + +To create a new crate, please copy the `template` directory and update the package name +for the new crate. + +Note that all crates should have `#![forbid(unsafe_code)]` at the crate root unless it is made +explicit here that a crate contains unsafe code. + +* `types`: all components and resources which subcrates would like to make available to other subcrates. +Acts somewhat like a more elegant C/C++ header file. +* `util`: small utility functions as well as trivial game logic which doesn't need to be in its own crate (e.g. world time) +* `entity`: entity implementations (items, arrows, falling blocks, mobs, ...). UNSAFE: used for item collection in `object::item::item_collect:system`. +* `block`: block entity implementations (chests, furnaces, command blocks, ...) +* `player`: logic pertaining directly to players, e.g. chunk sending, chat, the view system. Also contains all packet handlers. +* `network`: the TCP listener and IO worker implementation for communication with clients +* `config`: the configuration file and struct, plus loading/saving logic +* `chunk`: the chunk worker and chunk loading/saving logic +* `physics`: physics systems, including entity and (soon) fluid mechanics +* `lighting`: block and sky lighting +* `packet_buffer`: various data structures to buffer packets between the IO worker and the server threads +* `weather`: weather handling, scheduling + diff --git a/feather/old/server/block/Cargo.toml b/feather/old/server/block/Cargo.toml new file mode 100644 index 000000000..358789bd1 --- /dev/null +++ b/feather/old/server/block/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "feather-server-block" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } +feather-server-entity = { path = "../entity" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +once_cell = "1.4" +ahash = "0.3" +num-traits = "0.2" +inventory = "0.1" +log = "0.4" +anyhow = "1.0" +arrayvec = "0.5" + +[dev-dependencies] +feather-test-framework = { path = "../test" } diff --git a/feather/old/server/block/src/chest.rs b/feather/old/server/block/src/chest.rs new file mode 100644 index 000000000..fb2afa5d0 --- /dev/null +++ b/feather/old/server/block/src/chest.rs @@ -0,0 +1,565 @@ +use crate::ShouldReplace; +use anyhow::bail; +use arrayvec::ArrayVec; +use feather_core::util::{BlockPosition, Position}; +use feather_core::{ + anvil::{ + block_entity::{BlockEntityData, BlockEntityKind, BlockEntityVariant}, + player::InventorySlot, + }, + blocks::{BlockId, BlockKind, ChestKind, FacingCardinal}, + inventory::{Area, Window}, + items::{Item, ItemStack}, + network::{ + packets::{BlockAction, OpenWindow, WindowItems}, + Packet, + }, + text::TextRoot, +}; +use feather_server_entity::drops::drop_item; +use feather_server_types::{ + BlockEntityLoaderRegistration, BlockSerializer, BlockUpdateCause, BlockUpdateEvent, BumpVec, + EntityDespawnEvent, Game, InteractionHandler, Inventory, Network, SpawnPacketCreator, + WindowCloseEvent, WindowOpenEvent, +}; +use fecs::{Entity, EntityBuilder, EntityRef, World}; +use num_traits::ToPrimitive; + +pub const SLOTS: usize = 27; + +inventory::submit!(BlockEntityLoaderRegistration { + f: &load, + kind: BlockEntityVariant::Chest, +}); + +/// Marker component for chests. +pub struct Chest; + +/// Stores number of players currently viewing a chest. +/// ("Viewing" seems to mean "has chest open," though the documentation is somewhat vague.) +/// This value is used on the client to render lid animations. +pub struct ChestViewers(u32); + +/// Creates a chest. +pub fn create(pos: BlockPosition) -> EntityBuilder { + create_with_inventory(pos, Inventory::chest()) +} + +/// Creates a chest with the given inventory. +pub fn create_with_inventory(pos: BlockPosition, inventory: Inventory) -> EntityBuilder { + crate::base(pos) + .with(Chest) + .with(ChestViewers(0)) + .with(inventory) + .with(SpawnPacketCreator(&create_spawn_packet)) + .with(BlockSerializer(&serialize)) + .with(ShouldReplace(should_replace)) +} + +fn should_replace(_old: BlockId, new: BlockId) -> bool { + new.kind() != BlockKind::Chest +} + +/// When a chest is despawned, drops its contents. +#[fecs::event_handler] +pub fn on_chest_break_drop_contents( + event: &EntityDespawnEvent, + game: &mut Game, + world: &mut World, +) { + let entity = event.entity; + if !world.has::<Chest>(entity) { + return; + } + + let items = BumpVec::from_iter_in( + world + .get::<Inventory>(entity) + .iter_mut() + .filter_map(|mut guard| guard.take()), + game.bump(), + ); + let pos = *world.get::<Position>(entity); + for item in items { + drop_item(game, world, item, pos); + } +} + +#[fecs::event_handler] +pub fn on_chest_create_try_connect(event: &BlockUpdateEvent, game: &mut Game, world: &mut World) { + if event.new.kind() != BlockKind::Chest { + return; + } + + if event.new.chest_kind() != Some(ChestKind::Single) { + return; + } + + try_connect_chests(game, world, event.pos); +} + +/// When a chest is broken and it is connected with another chest, +/// set the other chest as ChestKind::Single. +#[fecs::event_handler] +pub fn on_chest_break_try_disconnect(event: &BlockUpdateEvent, game: &mut Game, world: &mut World) { + if event.old.kind() != BlockKind::Chest || event.new.kind() == BlockKind::Chest { + return; + } + + let kind = event.old.chest_kind().expect("chest has kind"); + + if let Some((left, right)) = connected_chest(event.pos, event.old) { + // Unintuitively, ChestKind::Left means that the chest it is connected to is + // to the left, so it is actually the _right_ hand chest. + // This is a Mojang naming issue. + + // Find which chest is not at event.pos. + let to_update = match kind { + ChestKind::Left => left, + ChestKind::Right => right, + ChestKind::Single => unreachable!(), + }; + debug_assert!(to_update != event.pos); + + let old_block = game.block_at(to_update); + if let Some(old_block) = old_block { + let new_block = old_block.with_chest_kind(ChestKind::Single); + + game.set_block_at(world, to_update, new_block, BlockUpdateCause::Unknown); + } + } +} + +fn create_spawn_packet(accessor: &EntityRef) -> Box<dyn Packet> { + Box::new(viewers_packet(accessor)) +} + +#[fecs::event_handler] +pub fn on_chest_open_increment_viewers(event: &WindowOpenEvent, game: &Game, world: &mut World) { + let should_resend = if let Some(mut viewers) = world.try_get_mut::<ChestViewers>(event.opened) { + viewers.0 += 1; + true + } else { + false + }; + + if should_resend { + resend_viewers(game, world, event.opened); + } +} + +#[fecs::event_handler] +pub fn on_chest_close_decrement_viewers(event: &WindowCloseEvent, game: &Game, world: &mut World) { + let should_resend = if let Some(mut viewers) = world.try_get_mut::<ChestViewers>(event.closed) { + viewers.0 = viewers.0.checked_sub(1).unwrap_or_default(); + true + } else { + false + }; + + if should_resend { + resend_viewers(game, world, event.closed); + } +} + +fn resend_viewers(game: &Game, world: &World, chest: Entity) { + let packet = viewers_packet(&world.entity(chest).unwrap()); + game.broadcast_entity_update(world, packet, chest, None); +} + +fn viewers_packet(chest: &EntityRef) -> impl Packet { + BlockAction { + location: *chest.get::<BlockPosition>(), + action_id: 1, + action_param: chest.get::<ChestViewers>().0 as u8, + block_type: BlockKind::Chest.to_i32().unwrap(), + } +} + +fn serialize(_game: &Game, accessor: &EntityRef) -> BlockEntityData { + let base = crate::serialize_base(accessor); + + let items = serialize_items(&*accessor.get::<Inventory>()); + + BlockEntityData { + base, + kind: BlockEntityKind::Chest { + items, + loot_table: None, + loot_table_seed: None, + }, + } +} + +fn serialize_items(inventory: &Inventory) -> Vec<InventorySlot> { + let mut slots = Vec::new(); + for i in 0..27 { + let item = inventory.item_at(Area::Chest, i).unwrap(); + + if let Some(item) = item { + slots.push(InventorySlot::from_inventory_index(i as i8, item)); + } + } + slots +} + +fn load(data: BlockEntityData) -> anyhow::Result<EntityBuilder> { + let pos = crate::load_base(&data.base); + let slots = match data.kind { + BlockEntityKind::Chest { items, .. } => items, + _ => bail!("not a chest"), + }; + + let inventory = load_inventory(&slots); + + Ok(create_with_inventory(pos, inventory)) +} + +fn load_inventory(slots: &[InventorySlot]) -> Inventory { + let inv = Inventory::chest(); + + for slot in slots { + if Item::from_identifier(&slot.item).is_some() { + if let Err(e) = inv.set_item_at(Area::Chest, slot.slot as usize, slot.into()) { + log::warn!("Invalid chest slot: {}", e); + } + } + } + + inv +} + +/// If the block at the given position is a chest, and it is connected +/// to another chest to form a large chest, returns a tuple (left, right) +// where `left` is the left chest and `right` is the right chest position. +pub fn connected_chest( + pos: BlockPosition, + block: BlockId, +) -> Option<(BlockPosition, BlockPosition)> { + if block.kind() != BlockKind::Chest { + return None; + } + + let kind = block + .chest_kind() + .expect("chest block always has chest_kind property"); + let facing = block + .facing_cardinal() + .expect("chest blcok always has facing_cardinal property"); + + // facing_offset is offset along (x, z) axes + // from the left chest to the right. + let facing_offset = connected_offset(facing); + + match kind { + ChestKind::Single => None, + ChestKind::Left => Some(( + BlockPosition::new(pos.x - facing_offset[0], pos.y, pos.z - facing_offset[1]), + pos, + )), + ChestKind::Right => Some(( + pos, + BlockPosition::new(pos.x + facing_offset[0], pos.y, pos.z + facing_offset[1]), + )), + } +} + +/// Attempts to connect the chest at `pos` to an adjacent chest +/// facing the same direction. +/// Returns the position of the adjacent chest, or `None` if +/// no chest was found. +pub fn try_connect_chests( + game: &mut Game, + world: &mut World, + pos: BlockPosition, +) -> Option<BlockPosition> { + let block = game.block_at(pos).unwrap_or_default(); + if block.kind() != BlockKind::Chest { + return None; + } + let facing = block.facing_cardinal().expect("chest has facing_cardinal"); + + let offsets = [(0, 1), (0, -1), (1, 0), (-1, 0)]; + for (x_offset, z_offset) in offsets.iter().copied() { + let pos2 = BlockPosition::new(pos.x + x_offset, pos.y, pos.z + z_offset); + + let block2 = game.block_at(pos2).unwrap_or_default(); + if block2.kind() != BlockKind::Chest { + continue; + } + + let kind2 = block2.chest_kind().expect("chest has chest_kind"); + if kind2 != ChestKind::Single { + // Other chest is already connected. + continue; + } + + let facing2 = block2.facing_cardinal().expect("chest has facing_cardinal"); + if facing == facing2 { + // Both chests face same direction. Connect them. + let (mut left_pos, mut left_block, mut right_pos, mut right_block) = + if x_offset < 0 || z_offset < 0 { + (pos2, block2, pos, block) + } else { + (pos, block, pos2, block2) + }; + + if !matches!(facing, FacingCardinal::South | FacingCardinal::West) { + // backwards, so swap + std::mem::swap(&mut left_pos, &mut right_pos); + std::mem::swap(&mut left_block, &mut right_block); + } + + left_block = left_block.with_chest_kind(ChestKind::Right); + right_block = right_block.with_chest_kind(ChestKind::Left); + + game.set_block_at(world, left_pos, left_block, BlockUpdateCause::Unknown); + game.set_block_at(world, right_pos, right_block, BlockUpdateCause::Unknown); + + return Some(pos2); + } + } + None +} + +/// Giving a chest's facing direction, returns the offset +/// along (x, z) axes to a potential connected chest to the right. +fn connected_offset(facing: FacingCardinal) -> [i32; 2] { + match facing { + FacingCardinal::North => [-1, 0], + FacingCardinal::South => [1, 0], + FacingCardinal::East => [0, -1], + FacingCardinal::West => [0, 1], + } +} + +/// Handler for player right clicking on chests. +pub struct ChestInteraction; +inventory::submit!(Box::new(ChestInteraction) as Box<dyn InteractionHandler>); + +impl InteractionHandler for ChestInteraction { + fn handle_interaction( + &self, + game: &mut Game, + world: &mut World, + pos: BlockPosition, + player: Entity, + window_id: u8, + ) { + // Open chest window and set the player's window. + // For large chests, the top row is the left + // chest (ChestKind::Right, oddly enough) and the + // bottom row is the right chest (ChestKind::Left). + + let chests: ArrayVec<[Option<Entity>; 2]> = opened_chests(game, pos); + let slots = slots(world, &chests); + + send_open_window(world, player, slots.len(), window_id); + send_window_items(world, player, slots, window_id); + + set_player_window(game, world, player, &chests); + } + + fn block_kind(&self) -> BlockKind { + BlockKind::Chest + } +} + +fn opened_chests(game: &Game, pos: BlockPosition) -> ArrayVec<[Option<Entity>; 2]> { + if let Some((left, right)) = connected_chest(pos, game.block_at(pos).unwrap_or_default()) { + ArrayVec::from([ + game.block_entities.get(&left).copied(), + game.block_entities.get(&right).copied(), + ]) + } else { + std::iter::once(game.block_entities.get(&pos).copied()).collect() + } +} + +/// Creates slot vector for the Window Items packet. +fn slots(world: &World, chests: &[Option<Entity>]) -> Vec<Option<ItemStack>> { + let num_slots = SLOTS * chests.len(); + let mut slots = Vec::with_capacity(num_slots); + + for chest in chests.iter().copied().filter_map(|entity| entity) { + let inventory = world.get::<Inventory>(chest); + + for i in 0..SLOTS { + let stack = inventory + .item_at(Area::Chest, i) + .expect("chest has at least SLOTS slots"); + slots.push(stack); + } + } + + slots +} + +fn send_open_window(world: &World, player: Entity, num_slots: usize, window_id: u8) { + const SINGLE: usize = SLOTS; + const LARGE: usize = SLOTS * 2; + let window_type = match num_slots { + SINGLE => "minecraft:generic_9x3", + LARGE => "minecraft:generic_9x6", + _ => "minecraft:generic_9x1", + }; + let window_title = match num_slots { + SINGLE => "Chest", + LARGE => "Large Chest", + _ => "Chest", + }; + let packet = OpenWindow { + window_id, + window_type: String::from(window_type), + window_title: TextRoot::from(window_title).into(), + number_of_slots: num_slots as u8, + entity_id: None, + }; + world.get::<Network>(player).send(packet); +} + +fn send_window_items(world: &World, player: Entity, slots: Vec<Option<ItemStack>>, window_id: u8) { + let packet = WindowItems { window_id, slots }; + world.get::<Network>(player).send(packet); +} + +/// Sets a player's `Window` to a chest window. +fn set_player_window( + game: &mut Game, + world: &mut World, + player: Entity, + chests: &[Option<Entity>], +) { + let chests = chests + .iter() + .copied() + .filter_map(|chest| chest) + .collect::<ArrayVec<[Entity; 2]>>(); + + let window = if chests.len() >= 2 { + Window::large_chest(player, chests[0], chests[1]) + } else if chests.len() == 1 { + Window::chest(player, chests[0]) + } else { + Window::player(player) + }; + + *world.get_mut::<Window>(player) = window; + + for opened in chests { + game.handle(world, WindowOpenEvent { player, opened }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use feather_core::blocks::BlockId; + use feather_server_types::BlockUpdateCause; + use feather_test_framework::Test; + + #[test] + fn test_connected_chest() { + let mut test = Test::new(); + + let pairs = vec![ + ( + BlockPosition::new(0, 0, 0), + BlockPosition::new(1, 0, 0), + BlockId::chest() + .with_chest_kind(ChestKind::Right) + .with_facing_cardinal(FacingCardinal::South), + BlockId::chest() + .with_chest_kind(ChestKind::Left) + .with_facing_cardinal(FacingCardinal::South), + ), + ( + BlockPosition::new(0, 0, 0), + BlockPosition::new(0, 0, -1), + BlockId::chest() + .with_chest_kind(ChestKind::Right) + .with_facing_cardinal(FacingCardinal::East), + BlockId::chest() + .with_chest_kind(ChestKind::Left) + .with_facing_cardinal(FacingCardinal::East), + ), + ]; + + for (pos_left, pos_right, block_left, block_right) in pairs { + assert!(test.game.set_block_at( + &mut test.world, + pos_left, + block_left, + BlockUpdateCause::Unknown, + )); + assert!(test.game.set_block_at( + &mut test.world, + pos_right, + block_right, + BlockUpdateCause::Unknown, + )); + + assert_eq!( + connected_chest(pos_left, block_left), + Some((pos_left, pos_right)) + ); + } + } + + #[test] + fn test_connected_chest_single() { + let mut test = Test::new(); + test.game.set_block_at( + &mut test.world, + BlockPosition::new(0, 0, 0), + BlockId::chest().with_chest_kind(ChestKind::Single), + BlockUpdateCause::Unknown, + ); + + assert_eq!( + connected_chest( + BlockPosition::new(0, 0, 0), + BlockId::chest().with_chest_kind(ChestKind::Single) + ), + None + ); + } + + #[test] + fn test_try_connect_chests() { + let mut test = Test::new(); + test.game.set_block_at( + &mut test.world, + BlockPosition::new(0, 0, 0), + BlockId::chest() + .with_chest_kind(ChestKind::Single) + .with_facing_cardinal(FacingCardinal::East), + BlockUpdateCause::Unknown, + ); + assert_eq!( + try_connect_chests(&mut test.game, &mut test.world, BlockPosition::new(0, 0, 0)), + None + ); + + test.game.set_block_at( + &mut test.world, + BlockPosition::new(0, 0, 1), + BlockId::chest() + .with_chest_kind(ChestKind::Single) + .with_facing_cardinal(FacingCardinal::East), + BlockUpdateCause::Unknown, + ); + assert_eq!( + try_connect_chests(&mut test.game, &mut test.world, BlockPosition::new(0, 0, 0)), + Some(BlockPosition::new(0, 0, 1)) + ); + + let left = test.game.block_at(BlockPosition::new(0, 0, 0)).unwrap(); + let right = test.game.block_at(BlockPosition::new(0, 0, 1)).unwrap(); + + assert_eq!(left.chest_kind(), Some(ChestKind::Left)); + assert_eq!(right.chest_kind(), Some(ChestKind::Right)); + assert_eq!(left.facing_cardinal(), Some(FacingCardinal::East)); + assert_eq!(right.facing_cardinal(), Some(FacingCardinal::East)); + } +} diff --git a/feather/old/server/block/src/init.rs b/feather/old/server/block/src/init.rs new file mode 100644 index 000000000..8c3a4c65c --- /dev/null +++ b/feather/old/server/block/src/init.rs @@ -0,0 +1,60 @@ +use crate::{chest, ShouldReplace}; +use ahash::AHashMap; +use feather_core::blocks::BlockKind; +use feather_core::util::BlockPosition; +use feather_server_types::{BlockEntity, BlockUpdateEvent, EntitySpawnEvent, Game}; +use fecs::{EntityBuilder, World}; +use once_cell::sync::Lazy; + +type BlockEntityCreator = fn(BlockPosition) -> EntityBuilder; + +/// Global mapping of blocks which require block entities. +static BLOCK_ENTITY_MAP: Lazy<AHashMap<BlockKind, BlockEntityCreator>> = Lazy::new(|| { + let mut map: AHashMap<_, fn(BlockPosition) -> EntityBuilder> = AHashMap::new(); + + map.insert(BlockKind::Chest, chest::create); + + map +}); + +/// When a block is created, and there is a block entity kind +/// associated with it, creates the block entity. Additionally, +/// removes any old block entity, if it existed. +#[fecs::event_handler] +pub fn on_block_update_create_block_entity( + event: &BlockUpdateEvent, + game: &mut Game, + world: &mut World, +) { + if let Some(entity) = game.block_entities.get(&event.pos).copied() { + // Determine whether we should replace the entity + // or keep the existing block entity. + if let Some(should_replace) = world.try_get::<ShouldReplace>(entity).map(|x| x.0) { + if !should_replace(event.old, event.new) { + return; // should keep existing block entity; block entities remain unchanged + } + } + game.block_entities.remove(&event.pos); + game.despawn(entity, world); + } + + if let Some(init) = BLOCK_ENTITY_MAP.get(&event.new.kind()) { + // Spawn block entity + let entity = init(event.pos).build().spawn_in(world); + + game.handle(world, EntitySpawnEvent { entity }); + } +} + +#[fecs::event_handler] +pub fn on_block_entity_create_insert_to_map( + event: &EntitySpawnEvent, + game: &mut Game, + world: &mut World, +) { + if let Some(pos) = world.try_get::<BlockPosition>(event.entity) { + if world.has::<BlockEntity>(event.entity) { + game.block_entities.insert(*pos, event.entity); + } + } +} diff --git a/feather/old/server/block/src/lib.rs b/feather/old/server/block/src/lib.rs new file mode 100644 index 000000000..d17915acd --- /dev/null +++ b/feather/old/server/block/src/lib.rs @@ -0,0 +1,46 @@ +#![forbid(unsafe_code)] + +pub mod chest; +mod init; + +pub use chest::{ + on_chest_break_drop_contents, on_chest_break_try_disconnect, on_chest_close_decrement_viewers, + on_chest_create_try_connect, on_chest_open_increment_viewers, +}; +use feather_core::{ + anvil::block_entity::BlockEntityBase, + blocks::BlockId, + util::{BlockPosition, Position}, +}; +use feather_server_types::BlockEntity; +use fecs::{EntityBuilder, EntityRef}; +pub use init::{on_block_entity_create_insert_to_map, on_block_update_create_block_entity}; + +/// A function which determines whether a given change between +/// block states should cause a block entity to be destroyed/recreated. +/// +/// First parameter is the old block; second is the new block. Return value +/// is `false` if the block entity should remain unchanged and `true` +/// if it should be replaced with a block entity for the new block. +pub struct ShouldReplace(pub fn(BlockId, BlockId) -> bool); + +/// Returns the base components all block entities have. +fn base(pos: BlockPosition) -> EntityBuilder { + EntityBuilder::new() + .with(pos) + .with(Position::from(pos)) + .with(BlockEntity) +} + +fn serialize_base(accessor: &EntityRef) -> BlockEntityBase { + let pos = *accessor.get::<BlockPosition>(); + BlockEntityBase { + x: pos.x, + y: pos.y, + z: pos.z, + } +} + +fn load_base(data: &BlockEntityBase) -> BlockPosition { + BlockPosition::new(data.x, data.y, data.z) +} diff --git a/feather/old/server/chat/Cargo.toml b/feather/old/server/chat/Cargo.toml new file mode 100644 index 000000000..6de189e30 --- /dev/null +++ b/feather/old/server/chat/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "feather-server-chat" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] diff --git a/feather/old/server/chat/src/lib.rs b/feather/old/server/chat/src/lib.rs new file mode 100644 index 000000000..45278f224 --- /dev/null +++ b/feather/old/server/chat/src/lib.rs @@ -0,0 +1 @@ +#![forbid(unsafe_code)] diff --git a/feather/old/server/chunk/Cargo.toml b/feather/old/server/chunk/Cargo.toml new file mode 100644 index 000000000..09f77af0c --- /dev/null +++ b/feather/old/server/chunk/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "feather-server-chunk" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } +feather-server-worldgen = { path = "../worldgen" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +parking_lot = "0.10" +ahash = "0.3" +rayon = "1.3" +crossbeam = "0.7" +log = "0.4" +smallvec = "1.4" +anyhow = "1.0" diff --git a/feather/old/server/chunk/src/chunk_manager.rs b/feather/old/server/chunk/src/chunk_manager.rs new file mode 100644 index 000000000..9964996eb --- /dev/null +++ b/feather/old/server/chunk/src/chunk_manager.rs @@ -0,0 +1,350 @@ +//! Module for interacting with the chunk worker thread +//! from the server threads. +//! +//! Also handles unloading chunks when unused. +use crossbeam::channel::{Receiver, Sender}; +use std::sync::atomic::{AtomicU32, Ordering}; + +use crate::chunk_worker; +use ahash::AHashSet; +use chunk_worker::ChunkSave; +use feather_core::anvil::{block_entity::BlockEntityData, entity::EntityData}; +use feather_core::chunk::Chunk; +use feather_core::util::ChunkPosition; +use feather_server_types::{ + ChunkHolder, ChunkHolderReleaseEvent, ChunkLoadEvent, ChunkLoadFailEvent, ChunkUnloadEvent, + EntityDespawnEvent, EntitySpawnEvent, Game, HoldChunkRequest, LoadChunkRequest, + ReleaseChunkRequest, TPS, +}; +use feather_server_util::current_time_in_millis; +use fecs::{Entity, World}; +use parking_lot::RwLock; +use rayon::prelude::*; +use smallvec::SmallVec; +use std::collections::VecDeque; +use std::sync::Arc; + +/// Set of chunks which are currently being loaded. +#[derive(Debug, Clone, Default)] +pub struct LoadingChunks(pub AHashSet<ChunkPosition>); + +/// A handle for interacting with the chunk +/// worker thread. +#[derive(Debug, Clone)] +pub struct ChunkWorkerHandle { + pub sender: Sender<chunk_worker::Request>, + pub receiver: Receiver<chunk_worker::Reply>, +} + +/// System for handling replies from the chunk worker thread. +#[fecs::system] +pub fn handle_chunk_worker_replies( + game: &mut Game, + world: &mut World, + chunk_worker_handle: &ChunkWorkerHandle, + #[default] loading_chunks: &mut LoadingChunks, +) { + while let Ok(reply) = chunk_worker_handle.receiver.try_recv() { + match reply { + chunk_worker::Reply::LoadedChunk(pos, result) => { + loading_chunks.0.remove(&pos); + match result { + Ok(loaded) => { + game.chunk_map.insert(loaded.chunk); + + loaded.entities.into_iter().for_each(|builder| { + let entity = builder.build().spawn_in(world); + game.handle(world, EntitySpawnEvent { entity }); + }); + + game.handle(world, ChunkLoadEvent { chunk: pos }); + + log::trace!("Loaded chunk at {:?}", pos); + } + Err(error) => { + log::warn!("Failed to load chunk at {:?}: {}", pos, error); + game.handle(world, ChunkLoadFailEvent { pos, error }); + } + } + } + chunk_worker::Reply::SavedChunk(pos, result) => match result { + Ok(()) => log::trace!("Saved chunk at {:?}", pos), + Err(error) => log::warn!("Failed to save chunk at {:?}: {}", pos, error), + }, + } + } +} + +pub fn remove_chunk_holder( + game: &mut Game, + world: &mut World, + chunk: ChunkPosition, + holder: Entity, +) { + if let Some(vec) = game.chunk_holders.inner.get_mut(&chunk) { + let index = vec.iter().position(|e| *e == holder); + if let Some(index) = index { + vec.remove(index); + + game.handle( + world, + ChunkHolderReleaseEvent { + chunk, + entity: holder, + }, + ); + } + } +} + +/// The queue of chunks to be unloaded. +/// See `chunk_unload` for details. +#[derive(Clone, Debug, Default)] +pub struct ChunkUnloadQueue { + /// The internal queue. + queue: VecDeque<ChunkUnload>, +} + +/// A chunk to be unloaded. +#[derive(Clone, Copy, Debug, Default)] +struct ChunkUnload { + /// The position of this chunk. + chunk: ChunkPosition, + /// The tick count at which to unload the chunk. + time: u64, +} + +/// The amount of time, in ticks, between the time +/// a chunk is queued for unloading and when it is unloaded. +const CHUNK_UNLOAD_TIME: u64 = TPS * 5; // 5 seconds - TODO make this configurable + +/// System for unloading chunks when they have no holders. +/// This system through chunks which are currently +/// queued to be loaded and unloads them if the +/// period of time has elapsed. +/// +/// Chunks are not unloaded immediately after having +/// no holders because doing so could open up +/// opportunities for exploits. For example, a player +/// could quickly move between chunk boundaries, causing +/// chunks at the edge of their view distance +/// to be loaded and unloaded at an alarming rate. +#[fecs::system] +pub fn chunk_unload( + game: &mut Game, + world: &mut World, + #[default] chunk_unload_queue: &mut ChunkUnloadQueue, +) { + // Unload chunks which are finished in the queue. + + // Since chunks are queued in the back and taken out + // from the front, the chunks in the front of the vector + // were queued the longest time ago. Because of this, + // we go through the unloads in the front of the queue + // to find which chunks to unload. + while let Some(unload) = chunk_unload_queue.queue.front().copied() { + if game.tick_count >= unload.time { + // Don't unload if new chunk holders have appeared. + if game.chunk_holders.chunk_has_holders(unload.chunk) { + chunk_unload_queue.queue.pop_front(); + continue; + } + + // Unload chunk and pop from queue. + if game.chunk_map.chunk_at(unload.chunk).is_some() { + game.handle( + world, + ChunkUnloadEvent { + chunk: unload.chunk, + }, + ); + game.chunk_map.remove(unload.chunk); + log::trace!("Unloaded chunk at {}", unload.chunk); + } + chunk_unload_queue.queue.pop_front(); + } else { + // We're done - all chunks farther up in + // the queue were queued before this one, + // so it isn't time to unload any of those. + break; + } + } +} + +/// Event handler which handles holder release events. If +/// a chunk has no more holders, then a chunk unload is queued. +#[fecs::event_handler] +pub fn on_chunk_holder_release_unload_chunk( + event: &ChunkHolderReleaseEvent, + game: &mut Game, + chunk_unload_queue: &mut ChunkUnloadQueue, +) { + // Handle holder release events. + // If the chunk now has zero holders, queue it for unloading. + if !game.chunk_holders.chunk_has_holders(event.chunk) { + let unload = ChunkUnload { + chunk: event.chunk, + time: game.tick_count + CHUNK_UNLOAD_TIME, + }; + chunk_unload_queue.queue.push_back(unload); + } +} + +/// System for removing an entity's chunk holds +/// once it is destroyed. +#[fecs::event_handler] +pub fn on_entity_despawn_remove_chunk_holder( + event: &EntityDespawnEvent, + game: &mut Game, + world: &mut World, +) { + // If entity had chunk holds, remove them all + let holds = if let Some(holds) = world.try_get::<ChunkHolder>(event.entity) { + log::debug!("Removing chunk holds for entity {:?}", event.entity); + holds.holds.iter().copied().collect::<Vec<_>>() // todo: remove allocation + } else { + Vec::new() + }; + + for hold in holds { + remove_chunk_holder(game, world, hold, event.entity); + } +} + +/// The interval, in ticks, at which +/// chunks will be optimized. +const CHUNK_OPTIMIZE_INTERVAL: u64 = TPS * 60 * 5; // 5 minutes + +/// System which optimizes chunks periodically. +/// This allows for more efficient memory use +/// at the cost of the occasional CPU spike +/// when optimization happens. +/// +/// For optimal performance, this system is fully +/// concurrent - each chunk optimization is split +/// into a separate job and fed into `rayon`. +#[fecs::system] +pub fn chunk_optimize(game: &mut Game) { + // Only run every CHUNK_OPTIMIZE_INTERVAL ticks + if game.tick_count % CHUNK_OPTIMIZE_INTERVAL != 0 { + return; + } + + log::debug!("Optimizing chunks"); + + let start_time = current_time_in_millis(); + let count = AtomicU32::new(0); + + game.chunk_map.0.par_values().for_each(|chunk| { + count.fetch_add(chunk.write().optimize(), Ordering::Relaxed); + }); + + let end_time = current_time_in_millis(); + let elapsed = end_time - start_time; + + let num_sections = count.load(Ordering::Relaxed); + log::debug!( + "Optimized {} chunk sections (took {}ms{})", + num_sections, + elapsed, + if num_sections == 0 { + String::new() + } else { + format!(" - {:.2}ms/section", elapsed as f64 / num_sections as f64) + } + ); +} + +/// Adds a hold for a chunk for the given entity. +pub fn hold_chunk(game: &mut Game, holder: &mut ChunkHolder, chunk: ChunkPosition, entity: Entity) { + holder.holds.insert(chunk); + game.chunk_holders + .inner + .entry(chunk) + .or_default() + .push(entity); + log::trace!("Obtained chunk hold on {} for player {:?}", chunk, entity); +} + +/// Releases a hold for a chunk for the given entity. +pub fn release_chunk(game: &mut Game, world: &mut World, chunk: ChunkPosition, entity: Entity) { + let mut holder = world.get_mut::<ChunkHolder>(entity); + holder.holds.remove(&chunk); + if let Some(vec) = game.chunk_holders.inner.get_mut(&chunk) { + let mut index = None; + for (i, e) in vec.iter().enumerate() { + if *e == entity { + index = Some(i); + } + } + + if let Some(index) = index { + vec.swap_remove(index); + } + } + log::trace!("Released chunk hold on {} for player {:?}", chunk, entity); + drop(holder); + game.handle(world, ChunkHolderReleaseEvent { chunk, entity }); +} + +/// Asynchronously loads the chunk at the given position. +/// At some point in time after this function is called, +/// the chunk will appear in the chunk map. +/// +/// In the event that the requested chunk does not exist +/// in the world save, it will be generated asynchronously. +pub fn load_chunk(handle: &ChunkWorkerHandle, pos: ChunkPosition) { + // Send request to chunk worker thread + handle + .sender + .send(chunk_worker::Request::LoadChunk(pos)) + .unwrap(); +} + +/// Asynchronously saves the chunk at the given position. +pub fn save_chunk( + handle: &ChunkWorkerHandle, + chunk: Arc<RwLock<Chunk>>, + entities: SmallVec<[EntityData; 4]>, + block_entities: SmallVec<[BlockEntityData; 4]>, +) { + let save = ChunkSave { + chunk, + entities, + block_entities, + }; + handle + .sender + .send(chunk_worker::Request::SaveChunk(save)) + .unwrap(); +} + +#[fecs::event_handler] +pub fn release_chunk_request(event: &ReleaseChunkRequest, game: &mut Game, world: &mut World) { + release_chunk(game, world, event.chunk, event.player); +} + +#[fecs::event_handler] +pub fn hold_chunk_request(event: &HoldChunkRequest, game: &mut Game, world: &mut World) { + hold_chunk( + game, + &mut *world.get_mut::<ChunkHolder>(event.player), + event.chunk, + event.player, + ); +} + +#[fecs::event_handler] +pub fn load_chunk_request( + event: &LoadChunkRequest, + handle: &ChunkWorkerHandle, + loading_chunks: &mut LoadingChunks, + game: &mut Game, +) { + // Don't load chunk if it's already loading or already loaded. + if !loading_chunks.0.insert(event.chunk) || game.chunk_map.0.contains_key(&event.chunk) { + return; + } + + load_chunk(handle, event.chunk); +} diff --git a/feather/old/server/chunk/src/chunk_worker.rs b/feather/old/server/chunk/src/chunk_worker.rs new file mode 100644 index 000000000..e2f678996 --- /dev/null +++ b/feather/old/server/chunk/src/chunk_worker.rs @@ -0,0 +1,25 @@ +//! This module handles the asynchronous loading and saving +//! of chunks. It receives load and save requests from the server +//! (over a channel) and executes them. +//! +//! If a chunk cannot be loaded, it is generated on the Rayon thread pool +//! instead. +use ahash::AHashMap; +use crossbeam::channel::{Receiver, Sender}; +use feather_core::anvil::entity::EntityData; +use feather_core::anvil::region; +use feather_core::anvil::{ + block_entity::BlockEntityData, + region::{RegionHandle, RegionPosition}, +}; +use feather_core::chunk::Chunk; +use feather_core::util::ChunkPosition; +use feather_server_util::EntityLoader; +use feather_server_worldgen::WorldGenerator; +use fecs::EntityBuilder; +use parking_lot::RwLock; +use smallvec::SmallVec; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + diff --git a/feather/old/server/chunk/src/lib.rs b/feather/old/server/chunk/src/lib.rs new file mode 100644 index 000000000..8fe64b1b0 --- /dev/null +++ b/feather/old/server/chunk/src/lib.rs @@ -0,0 +1,8 @@ +#![forbid(unsafe_code)] + +mod chunk_manager; +pub mod chunk_worker; +mod save; + +pub use chunk_manager::*; +pub use save::*; diff --git a/feather/old/server/chunk/src/save.rs b/feather/old/server/chunk/src/save.rs new file mode 100644 index 000000000..5e5b270e8 --- /dev/null +++ b/feather/old/server/chunk/src/save.rs @@ -0,0 +1,224 @@ +//! Handles saving of chunks and entities + +use crate::{chunk_manager, ChunkWorkerHandle}; +use feather_core::anvil::entity::{AnimalData, BaseEntityData, EntityData}; +use feather_core::anvil::{ + block_entity::BlockEntityData, + player::{InventorySlot, PlayerData}, +}; +use feather_core::inventory::{Inventory, Window}; +use feather_core::util::{ChunkPosition, Gamemode, Position, Vec3d}; +use feather_server_types::{ + tasks, BlockSerializer, ChunkLoadEvent, ChunkUnloadEvent, ComponentSerializer, Game, Health, + HeldItem, PlayerLeaveEvent, Uuid, TICK_LENGTH, TPS, +}; +use fecs::{Entity, World}; +use std::collections::VecDeque; +use std::path::Path; +use std::sync::Arc; + +/// A chunk to save + the tick count at which to do so. +#[derive(Clone, Copy, Debug)] +struct SaveTask { + /// Chunk position to save. + chunk: ChunkPosition, + /// Tick count at which to save this chunk. + at: u64, +} + +/// Queue of chunks to save. +#[derive(Debug, Default)] +struct SaveQueue(VecDeque<SaveTask>); + +/// On a chunk load, adds the chunk to the save queue. +#[fecs::event_handler] +pub fn on_chunk_load_queue_for_saving( + event: &ChunkLoadEvent, + game: &mut Game, + #[default] save_queue: &mut SaveQueue, +) { + queue_for_saving(game, save_queue, event.chunk); +} + +/// On a chunk unload, saves the chunk first. +#[fecs::event_handler] +pub fn on_chunk_unload_save_chunk( + event: &ChunkUnloadEvent, + game: &mut Game, + world: &mut World, + chunk_worker_handle: &ChunkWorkerHandle, +) { + save_chunk_at(game, world, event.chunk, chunk_worker_handle); +} + +fn queue_for_saving(game: &mut Game, save_queue: &mut SaveQueue, chunk: ChunkPosition) { + let tick_to_save_at = + game.tick_count + (game.config.world.save_interval.as_millis() as u64) / TICK_LENGTH; + + let task = SaveTask { + chunk, + at: tick_to_save_at, + }; + + save_queue.0.push_back(task); +} + +/// System which checks for chunks which have been queued for saving +/// and, if it is time, saves them. +#[fecs::system] +pub fn chunk_save( + game: &mut Game, + world: &mut World, + save_queue: &mut SaveQueue, + chunk_worker_handle: &ChunkWorkerHandle, +) { + // no need to run this system every tick + if game.tick_count % TPS != 0 { + return; + } + + loop { + let task = match save_queue.0.front().copied() { + Some(task) => task, + None => return, // no save tasks to run + }; + + if game.chunk_map.chunk_at(task.chunk).is_none() { + save_queue + .0 + .pop_front() + .expect("we just verified the front task exists"); + continue; + } + + if task.at <= game.tick_count { + // Save the chunk, then pop the task from the queue. + save_chunk_at(game, world, task.chunk, chunk_worker_handle); + + save_queue + .0 + .pop_front() + .expect("we just verified the front task exists"); + + // Requeue the chunk for saving again. + queue_for_saving(game, save_queue, task.chunk); + } else { + return; + } + } +} + +pub fn save_chunk_at( + game: &Game, + world: &World, + pos: ChunkPosition, + chunk_worker_handle: &ChunkWorkerHandle, +) { + let chunk = game + .chunk_map + .chunk_handle_at(pos) + .expect("chunk does not exist"); + + if !chunk.write().check_modified() && game.chunk_entities.entities_in_chunk(pos).is_empty() { + return; + } + + // Serialize the entities in the chunk. + let (entities, block_entities) = serialize_entities(game, world, pos); + + log::trace!("Queuing chunk at {} for saving", pos); + chunk_manager::save_chunk( + chunk_worker_handle, + game.chunk_map.chunk_handle_at(pos).unwrap(), + entities.collect(), + block_entities.collect(), + ); +} + +fn serialize_entities<'a>( + game: &'a Game, + world: &'a World, + pos: ChunkPosition, +) -> ( + impl Iterator<Item = EntityData> + 'a, + impl Iterator<Item = BlockEntityData> + 'a, +) { + let entities = game + .chunk_entities + .entities_in_chunk(pos) + .iter() + .filter_map(move |entity| { + if let Some(serializer) = world.try_get::<ComponentSerializer>(*entity) { + let accessor = world.entity(*entity).expect("entity does not exist"); + + Some(serializer.serialize(game, &accessor)) + } else { + None + } + }); + + let block_entities = game + .chunk_entities + .entities_in_chunk(pos) + .iter() + .filter_map(move |entity| { + if let Some(serializer) = world.try_get::<BlockSerializer>(*entity) { + let accessor = world.entity(*entity).expect("entity does not exist"); + + Some(serializer.serialize(game, &accessor)) + } else { + None + } + }); + + (entities, block_entities) +} + +#[fecs::event_handler] +pub fn on_player_leave_save_data(event: &PlayerLeaveEvent, game: &Game, world: &mut World) { + save_player_data(game, world, event.player); +} + +pub fn save_player_data(game: &Game, world: &World, player: Entity) { + let inventory = world + .get::<Inventory>(player) + .enumerate() + .filter_map(|(index, slot)| slot.map(move |slot| (index, slot))) + .filter_map(|(index, slot)| { + InventorySlot::from_network_index( + Window::player(player).convert_slot(index, player).unwrap(), + slot, + ) + }) + .collect(); + + let health = world + .try_get::<Health>(player) + .map(|health| health.0 as f32) + .unwrap_or(1.0); + let data = PlayerData { + animal: AnimalData::new( + BaseEntityData::new(*world.get::<Position>(player), Vec3d::broadcast(0.0)), + health, + ), + gamemode: world.get::<Gamemode>(player).id() as i32, + inventory, + held_item: world.get::<HeldItem>(player).0 as i32, + }; + + let uuid = *world.get::<Uuid>(player); + let config = Arc::clone(&game.config); + + tasks().spawn(async move { + match feather_core::anvil::player::save_player_data( + &Path::new(&config.world.name), + uuid, + &data, + ) + .await + { + Ok(_) => (), + Err(e) => log::error!("Failed to save player data for UUID {}: {}", uuid, e), + } + }); +} diff --git a/feather/old/server/commands/Cargo.toml b/feather/old/server/commands/Cargo.toml new file mode 100644 index 000000000..d3aa5ad11 --- /dev/null +++ b/feather/old/server/commands/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "feather-server-commands" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } +feather-definitions = { path = "../../definitions" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +lieutenant = { git = "https://github.com/feather-rs/lieutenant", branch = "master" } +smallvec = "1.4" +anyhow = "1.0" +thiserror = "1.0" +rand = "0.7" +vek = "0.10" +uuid = { version = "0.8", features = ["v3"] } +tokio = { version = "0.2", features = ["full"] } diff --git a/feather/old/server/commands/src/arguments.rs b/feather/old/server/commands/src/arguments.rs new file mode 100644 index 000000000..e5fccca87 --- /dev/null +++ b/feather/old/server/commands/src/arguments.rs @@ -0,0 +1,542 @@ +use crate::CommandCtx; +use feather_core::position; +use feather_core::util::{Gamemode, Position}; +use feather_definitions::Item; +use feather_server_types::{Game, Name, NetworkId, Player}; +use fecs::{component, Entity, IntoQuery, Read, World}; +use lieutenant::{ArgumentKind, Input}; +use rand::Rng; +use smallvec::SmallVec; +use std::convert::Infallible; +use std::num::ParseFloatError; +use std::str::FromStr; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum SelectorParseError { + #[error("no player with name {0}")] + PlayerNotFound(String), +} + +/// Argument kind which supports entity selectors. +pub struct EntitySelector { + /// Entities selected by the parameter. + pub entities: SmallVec<[Entity; 1]>, +} + +impl ArgumentKind<CommandCtx> for EntitySelector { + type ParseError = SelectorParseError; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + input.advance_until(" "); + + true + } + + fn parse<'a>(ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let head = input.advance_until(" "); + + // See https://minecraft.gamepedia.com/Commands#Target_selectors + let entities = find_selected_entities(ctx, head)?; + + Ok(EntitySelector { entities }) + } +} + +impl EntitySelector { + /// Parses the returned entities for use in reporting success messages + /// Either the name of the entity for one entity, or how many were affected for many entities. + pub fn entities_to_string(&self, ctx: &CommandCtx, add_player: bool) -> String { + if self.entities.is_empty() { + "no entities".to_string() + } else if self.entities.len() == 1 { + if let Some(name) = ctx.world.try_get::<Name>(*self.entities.first().unwrap()) { + if add_player { + if ctx + .world + .try_get::<Player>(*self.entities.first().unwrap()) + .is_some() + { + format!("player {}", name.0) + } else { + format!("entity {}", name.0) + } + } else { + name.0.to_string() + } + } else { + "Server".to_string() + } + } else { + // TODO: confirm this is correct behaviour for success messages involving many players + let mut players = true; + for entity in &self.entities { + players &= ctx.world.try_get::<Player>(*entity).is_some(); + } + if players { + format!("{} players", self.entities.len()) + } else { + format!("{} entities", self.entities.len()) + } + } + } +} + +fn find_selected_entities( + ctx: &CommandCtx, + input: &str, +) -> Result<SmallVec<[Entity; 1]>, SelectorParseError> { + use smallvec::smallvec; + Ok(match input { + "@p" => { + // Nearest player + let pos = ctx + .world + .try_get::<Position>(ctx.sender) + .map(|r| *r) + .unwrap_or(position!(0.0, 0.0, 0.0)); + + nearest_player_to(&ctx.world, pos).into_iter().collect() + } + "@r" => { + // Random player + random_player(&ctx.game, &ctx.world).into_iter().collect() + } + "@a" => { + // Every player + <Read<Player>>::query() + .iter_entities(ctx.world.inner()) + .map(|(e, _)| e) + .collect() + } + "@e" => { + // Every entity + <Read<NetworkId>>::query() + .iter_entities(ctx.world.inner()) + .map(|(e, _)| e) + .collect() + } + "@s" => { + // Command sender, if it was a player + if ctx.world.has::<Player>(ctx.sender) { + smallvec![ctx.sender] + } else { + SmallVec::new() + } + } + player_name => smallvec![find_player_by_name(&ctx.world, player_name) + .ok_or_else(|| SelectorParseError::PlayerNotFound(player_name.to_owned()))?], + }) +} + +// TODO: eliminate linear searches. +// These search functions are incredibly naive. +fn find_player_by_name(world: &World, name: &str) -> Option<Entity> { + <Read<Name>>::query() + .iter_entities(world.inner()) + .find(|(_, n)| n.0 == name) + .map(|(entity, _name)| entity) +} + +fn nearest_player_to(world: &World, pos: Position) -> Option<Entity> { + <Read<Position>>::query() + .filter(component::<Player>()) + .iter_entities(world.inner()) + .min_by_key(|(_, p)| pos.distance_squared_to(**p).floor() as u64) + .map(|(entity, _)| entity) +} + +fn random_player(game: &Game, world: &World) -> Option<Entity> { + let query = <Read<Player>>::query(); + + let count = query.iter(world.inner()).count(); + + let index = game.rng().gen_range(0, count); + + query + .iter_entities(world.inner()) + .nth(index) + .map(|(e, _)| e) +} + +#[derive(Debug, Error)] +pub enum CoordinatesParseError { + #[error("missing coordinate")] + MissingCoordinate, + #[error("failed to parse float: {0}")] + ParseFloat(#[from] ParseFloatError), +} + +/// Parses a position (<x> <y> <z>, but also with support for relative +/// positions as per https://minecraft.gamepedia.com/Commands#Tilde_and_caret_notation). +#[derive(Copy, Clone, Debug)] +pub struct Coordinates { + pub x: Coordinate, + pub y: Coordinate, + pub z: Coordinate, +} + +impl Coordinates { + /// Converts these coordinates into a `Position`. + /// + /// The input `relative_to` is the position to interpret + /// as the origin of relative coordinates. For example, + /// this is the position of the target entity for the `/tp` + /// command. + pub fn into_position(self, relative_to: Position) -> Position { + let direction = relative_to.direction(); + position!( + Self::coordinate_into_absolute(self.x, relative_to.x, direction.x), + Self::coordinate_into_absolute(self.y, relative_to.y, direction.y), + Self::coordinate_into_absolute(self.z, relative_to.z, direction.z), + relative_to.pitch, + relative_to.yaw, + ) + } + + fn coordinate_into_absolute(coord: Coordinate, relative_to: f64, facing_magnitude: f64) -> f64 { + match coord { + Coordinate::Absolute(coord) => coord, + Coordinate::Relative(rel) => relative_to + rel, + Coordinate::RelativeLook(rel) => relative_to + rel * facing_magnitude, + } + } +} + +impl From<Position> for Coordinates { + fn from(pos: Position) -> Self { + Coordinates { + x: Coordinate::Absolute(pos.x), + y: Coordinate::Absolute(pos.y), + z: Coordinate::Absolute(pos.z), + } + } +} + +#[derive(Copy, Clone, Debug)] +pub enum Coordinate { + /// Coordinates relative to some position. The origin + /// is interpreted differently by different commands. + /// + /// For example, `/tp` interprets this as the coordinates + /// relative to the initial position of the target entity. + /// On the other hand, another command may use + /// this as the coordinates relative to the sender's + /// position. + Relative(f64), + /// Relative coordinates in the direction the player is looking. + /// This is similar to `Relative`, but the axes are rotated + /// to align with the entity's view direction. + RelativeLook(f64), + /// Absolute coordinates, in world space. + Absolute(f64), +} + +impl FromStr for Coordinate { + type Err = CoordinatesParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + if let Some(first) = s.chars().next() { + Ok(match first { + '~' => { + let offset = if s.len() > 1 { + f64::from_str(&s[1..])? + } else { + 0.0 + }; + Coordinate::Relative(offset) + } + '^' => { + let offset = if s.len() > 1 { + f64::from_str(&s[1..])? + } else { + 0.0 + }; + Coordinate::RelativeLook(offset) + } + _ => Coordinate::Absolute(f64::from_str(s)?), + }) + } else { + Err(CoordinatesParseError::MissingCoordinate) + } + } +} + +impl ArgumentKind<CommandCtx> for Coordinates { + type ParseError = CoordinatesParseError; + + fn satisfies<'a>(ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + Self::parse(ctx, input).is_ok() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let x = input.advance_until(" "); + let y = input.advance_until(" "); + let z = input.advance_until(" "); + + let x = Coordinate::from_str(x)?; + let y = Coordinate::from_str(y)?; + let z = Coordinate::from_str(z)?; + + Ok(Coordinates { x, y, z }) + } +} + +#[derive(Debug, Error)] +pub enum GamemodeParseError { + #[error("invalid gamemode string {0}")] + InvalidGamemode(String), +} + +/// A parsed gamemode string ("survival", "creative", ...) +#[derive(Copy, Clone, Debug)] +pub struct ParsedGamemode(pub Gamemode); + +impl ArgumentKind<CommandCtx> for ParsedGamemode { + type ParseError = GamemodeParseError; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + !input.advance_until(" ").is_empty() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let s = input.advance_until(" "); + + let gamemode = match s { + "survival" => Gamemode::Survival, + "creative" => Gamemode::Creative, + "spectator" => Gamemode::Spectator, + "adventure" => Gamemode::Adventure, + s => return Err(GamemodeParseError::InvalidGamemode(s.to_owned())), + }; + + Ok(ParsedGamemode(gamemode)) + } +} + +#[derive(Debug, Error)] +pub enum TextParseError {} + +/// A multi-word argument (parses until the end of the command) +#[derive(Clone, Debug)] +pub struct TextArgument(pub String); + +impl ArgumentKind<CommandCtx> for TextArgument { + type ParseError = Infallible; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + !input.advance_to_end().is_empty() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let text = input.advance_to_end(); + + Ok(TextArgument(text.to_owned())) + } +} + +impl AsRef<str> for TextArgument { + fn as_ref(&self) -> &str { + self.0.as_str() + } +} + +#[derive(Debug, Error)] +pub enum ItemParseError { + #[error("Unknown item {0}")] + ItemDoesNotExist(String), +} + +#[derive(Clone, Debug)] +pub struct ItemArgument(pub Item); + +impl ArgumentKind<CommandCtx> for ItemArgument { + type ParseError = ItemParseError; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + !input.advance_until(" ").is_empty() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let text = input.advance_until(" "); + let item = Item::from_identifier(text); + match item { + Some(s) => Ok(ItemArgument(s)), + None => Err(ItemParseError::ItemDoesNotExist(text.to_owned())), + } + } +} + +#[derive(Debug, Error)] +pub enum I32ParseError { + #[error("Invalid integer {0}")] + Invalid(String), +} + +#[derive(Clone, Debug)] +pub struct I32Argument(pub i32); + +impl ArgumentKind<CommandCtx> for I32Argument { + type ParseError = I32ParseError; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + !input.advance_until(" ").is_empty() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let text = input.advance_until(" "); + let number = text.parse::<i32>(); + match number { + Ok(s) => Ok(I32Argument(s)), + Err(_) => Err(I32ParseError::Invalid(text.to_owned())), + } + } +} + +#[derive(Debug, Error)] +pub enum PositiveI32ParseError { + #[error("Invalid integer {0}")] + Invalid(String), + #[error("Integer must not be less than 0, found {0}")] + Negative(i32), +} + +#[derive(Clone, Debug)] +pub struct PositiveI32Argument(pub i32); + +impl ArgumentKind<CommandCtx> for PositiveI32Argument { + type ParseError = PositiveI32ParseError; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + !input.advance_until(" ").is_empty() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let text = input.advance_until(" "); + let number = text.parse::<i32>(); + match number { + Ok(integer) => { + if integer >= 0 { + Ok(PositiveI32Argument(integer)) + } else { + Err(PositiveI32ParseError::Negative(integer)) + } + } + Err(_) => Err(PositiveI32ParseError::Invalid(text.to_owned())), + } + } +} + +#[derive(Debug, Error)] +pub enum TimeQueryInformationError { + #[error("Unknown Argument {0}")] + UnknownArgument(String), +} + +#[derive(Clone, Debug)] +pub enum TimeQueryInformation { + DayTime, + GameTime, + Day, +} + +impl ArgumentKind<CommandCtx> for TimeQueryInformation { + type ParseError = TimeQueryInformationError; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input) -> bool { + !input.advance_until(" ").is_empty() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let text = input.advance_until(" "); + match text { + "daytime" => Ok(TimeQueryInformation::DayTime), + "gametime" => Ok(TimeQueryInformation::GameTime), + "day" => Ok(TimeQueryInformation::Day), + s => Err(TimeQueryInformationError::UnknownArgument(s.to_owned())), + } + } +} + +#[derive(Debug, Error)] +pub enum TimeArgumentError { + #[error("Invalid integer {0}")] + Invalid(String), + #[error("Invalid unit, found {0}")] + InvalidUnit(char), +} + +#[derive(Clone, Debug)] +pub struct TimeArgument(pub u64); + +impl ArgumentKind<CommandCtx> for TimeArgument { + type ParseError = TimeArgumentError; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + Self::parse(_ctx, input).is_ok() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let text = input.advance_until(" "); + let (value, unit) = { + let it = text.chars(); + // Get and parse the number part up to the unit character + let val = it + .clone() + // allow . to be able to type decimal + .take_while(|&c| c == '.' || char::is_numeric(c)) + .collect::<String>() + .parse::<f32>(); + // Skips the number part and gets the unit character or default to 't' + let unit = it + .clone() + .find(|&c| c != '.' && !char::is_numeric(c)) + .unwrap_or('t'); + (val, unit) + }; + match value { + Ok(num) => match unit { + 'd' => Ok(TimeArgument((num * 24_000.0) as u64)), + 's' => Ok(TimeArgument((num * 20.0) as u64)), + 't' => Ok(TimeArgument(num as u64)), + _ => Err(TimeArgumentError::InvalidUnit(unit)), + }, + Err(_) => Err(TimeArgumentError::Invalid(text.to_owned())), + } + } +} + +#[derive(Debug, Error)] +pub enum TimeSpecParseError { + #[error("invalid time string {0}")] + InvalidTimeSpec(String), +} + +/// A parsed TimeSpec +#[derive(Copy, Clone, Debug)] +pub enum TimeSpec { + Day, + Night, + Noon, + Midnight, +} + +impl ArgumentKind<CommandCtx> for TimeSpec { + type ParseError = TimeSpecParseError; + + fn satisfies<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> bool { + !input.advance_until(" ").is_empty() + } + + fn parse<'a>(_ctx: &CommandCtx, input: &mut Input<'a>) -> Result<Self, Self::ParseError> { + let s = input.advance_until(" "); + + Ok(match s { + "day" => TimeSpec::Day, + "night" => TimeSpec::Night, + "noon" => TimeSpec::Noon, + "midnight" => TimeSpec::Midnight, + s => return Err(TimeSpecParseError::InvalidTimeSpec(s.to_owned())), + }) + } +} diff --git a/feather/old/server/commands/src/impls.rs b/feather/old/server/commands/src/impls.rs new file mode 100644 index 000000000..00283bea4 --- /dev/null +++ b/feather/old/server/commands/src/impls.rs @@ -0,0 +1,879 @@ +//! The implementations of various commands. + +use crate::{ + arguments::{ + Coordinates, EntitySelector, ItemArgument, ParsedGamemode, PositiveI32Argument, + TextArgument, TimeArgument, TimeQueryInformation, TimeSpec, + }, + CommandCtx, +}; +use feather_core::inventory::{Inventory, SlotIndex}; +use feather_core::text::{Text, TextComponentBuilder, TextValue}; +use feather_core::util::{Gamemode, Position}; +use feather_definitions::Item; +use feather_server_types::{ + Ban, ChatEvent, ChatPosition, GamemodeUpdateEvent, InventoryUpdateEvent, MessageReceiver, Name, + Player, ShutdownChannels, Teleported, TimeUpdateEvent, WrappedBanInfo, +}; +use feather_server_util::{name_to_uuid_offline, name_to_uuid_online}; +use fecs::{Entity, IntoQuery, Read, ResourcesProvider, World}; +use lieutenant::command; +use smallvec::SmallVec; +use std::net::{IpAddr, SocketAddr}; +use std::str::FromStr; +use thiserror::Error; +use tokio::runtime::Runtime; +use uuid::Uuid; + +#[derive(Debug, Error)] +pub enum TpError { + #[error("No entity was found")] + NoMatchingEntities, + #[error("Only one entity is allowed, but the provided selector allows for more than one")] + TooManyEntities, +} + +#[command(usage = "tp|teleport <destination>")] +pub fn tp_1(ctx: &mut CommandCtx, destination: EntitySelector) -> anyhow::Result<()> { + if let Some(first) = destination.entities.first() { + if let Some(pos) = ctx.world.try_get::<Position>(*first).map(|r| *r) { + teleport_entity_to_pos(&mut ctx.world, ctx.sender, pos); + } + + Ok(Some(format!( + "Teleported {0} to {1}", + ctx.world.get::<Name>(ctx.sender).0.to_string(), + ctx.world.get::<Name>(*first).0.to_string() + ))) + } else { + Err(TpError::NoMatchingEntities.into()) + } +} + +#[command(usage = "tp|teleport <location>")] +pub fn tp_2(ctx: &mut CommandCtx, location: Coordinates) -> anyhow::Result<()> { + teleport_entity(&mut ctx.world, ctx.sender, location); + + let position = ctx.world.get::<Position>(ctx.sender); + Ok(Some(format!( + "Teleported {0} to {1}, {2}, {3}", + ctx.world.get::<Name>(ctx.sender).0, + position.x, + position.y, + position.z + ))) +} + +#[command(usage = "tp|teleport <targets> <location>")] +pub fn tp_3( + ctx: &mut CommandCtx, + targets: EntitySelector, + location: Coordinates, +) -> anyhow::Result<()> { + if targets.entities.is_empty() { + Err(TpError::NoMatchingEntities.into()) + } else { + for entity in &targets.entities { + teleport_entity(&mut ctx.world, *entity, location); + } + + let position = ctx + .world + .get::<Position>(*targets.entities.first().unwrap()); + Ok(Some(format!( + "Teleported {0} to {1}, {2}, {3}", + targets.entities_to_string(ctx, false), + position.x, + position.y, + position.z + ))) + } +} + +#[command(usage = "tp|teleport <targets> <destination>")] +pub fn tp_4( + ctx: &mut CommandCtx, + targets: EntitySelector, + destination: EntitySelector, +) -> anyhow::Result<()> { + if destination.entities.len() > 1 { + Err(TpError::TooManyEntities.into()) + } else if let Some(location) = destination + .entities + .first() + .map(|e| ctx.world.try_get::<Position>(*e).map(|r| *r)) + .flatten() + { + if targets.entities.is_empty() { + Err(TpError::NoMatchingEntities.into()) + } else { + for entity in &targets.entities { + teleport_entity_to_pos(&mut ctx.world, *entity, location); + } + Ok(Some(format!( + "Teleported {0} to {1}", + targets.entities_to_string(ctx, false), + destination.entities_to_string(ctx, false) + ))) + } + } else { + Err(TpError::NoMatchingEntities.into()) + } +} + +fn teleport_entity(world: &mut World, entity: Entity, location: Coordinates) { + let new_pos = world + .try_get::<Position>(entity) + .map(|r| *r) + .map(|relative_to| location.into_position(relative_to)); + + if let Some(new_pos) = new_pos { + teleport_entity_to_pos(world, entity, new_pos); + } +} + +fn teleport_entity_to_pos(world: &mut World, entity: Entity, pos: Position) { + if let Some(mut old_pos) = world.try_get_mut::<Position>(entity) { + *old_pos = pos; + } + let _ = world.add(entity, Teleported); +} + +#[command(usage = "gamemode <gamemode>")] +pub fn gamemode_1(ctx: &mut CommandCtx, gamemode: ParsedGamemode) -> anyhow::Result<()> { + update_gamemode(ctx, gamemode.0, ctx.sender); + Ok(Some(format!( + "Set own gamemode to {} Mode", + gamemode.0.to_string() + ))) +} + +#[command(usage = "gamemode <gamemode> <target>")] +pub fn gamemode_2( + ctx: &mut CommandCtx, + gamemode: ParsedGamemode, + target: EntitySelector, +) -> anyhow::Result<()> { + for entity in &target.entities { + update_gamemode(ctx, gamemode.0, *entity) + } + + if target.entities.len() == 1 && *target.entities.first().unwrap() == ctx.sender { + return Ok(Some(format!( + "Set own gamemode to {} Mode", + gamemode.0.to_string() + ))); + } + Ok(Some(format!( + "Changed gamemode of {} to {} Mode", + target.entities_to_string(ctx, false), + gamemode.0.to_string() + ))) +} + +fn update_gamemode(ctx: &mut CommandCtx, gamemode: Gamemode, entity: Entity) { + let event = if let Some(mut old) = ctx.world.try_get_mut::<Gamemode>(ctx.sender) { + let old_val = *old; + *old = gamemode; + + let event = GamemodeUpdateEvent { + player: entity, + old: old_val, + new: gamemode, + }; + Some(event) + } else { + None + }; + + if let Some(event) = event { + ctx.game.handle(&mut *ctx.world, event); + } +} + +#[command(usage = "tell|msg|w <target> <message>")] +pub fn whisper( + ctx: &mut CommandCtx, + target: EntitySelector, + message: TextArgument, +) -> anyhow::Result<()> { + let sender_name = if let Some(sender_name) = ctx.world.try_get::<Name>(ctx.sender) { + sender_name.0.clone() + } else { + // Use a default value if the executor has no Name component + String::from("Server") + }; + + // The message that is returned to the whisperer + // You whisper to [player] (and [player]): [message] + let mut response_message = String::from("You whisper to"); + + // Tracks if there needs to be "and" before the next player added to the response message + let mut needs_and = false; + + for entity in target.entities { + if let Some(mut message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) { + message_receiver.send( + Text::from(format!( + "{} whispers to you: {}", + sender_name, + message.0.clone() + )) + .gray() + .italic(), + ); + } else { + // If the entity doesn't have a message receiver it is not a player and there is no need to continue + continue; + }; + + if let Some(player_name) = ctx.world.try_get::<Name>(entity) { + if needs_and { + response_message += format!(" and {}", player_name.0).as_str(); + } else { + needs_and = true; + + response_message += format!(" {}", player_name.0).as_str(); + } + } + } + + // Send the whisperer a confirmation message + if let Some(mut sender_message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + response_message += format!(": {}", message.0).as_str(); + let return_text = Text::from(response_message).gray().italic(); + + sender_message_receiver.send(return_text); + } + + Ok(None) +} + +#[command(usage = "say <message>")] +pub fn say(ctx: &mut CommandCtx, message: TextArgument) -> anyhow::Result<()> { + let name = ctx.world.try_get::<Name>(ctx.sender); + + let sender_name = if let Some(name) = &name { + &name.0 + } else { + "Server" + }; + + let command_output = Text::from(format!("[{}] {}", sender_name, message.0)); + + drop(name); + + ctx.game.handle( + &mut ctx.world, + ChatEvent { + message: command_output.into(), + position: ChatPosition::Chat, + }, + ); + + Ok(None) +} + +#[command(usage = "me <action>")] +pub fn me(ctx: &mut CommandCtx, action: TextArgument) -> anyhow::Result<()> { + let command_output = { + let name = ctx.world.try_get::<Name>(ctx.sender); + let sender_name = name.as_deref().map_or("@", |Name(n)| n); + Text::from(format!("* {} {}", sender_name, action.as_ref())) + }; + + ctx.game.handle( + &mut ctx.world, + ChatEvent { + message: command_output.into(), + position: ChatPosition::Chat, + }, + ); + + Ok(None) +} + +#[derive(Debug, Error)] +pub enum KickError { + #[error( + "Only players may be affected by this command, but the provided selector includes entities" + )] + NoEntities, +} + +#[command(usage = "kick <targets>")] +pub fn kick_1(ctx: &mut CommandCtx, targets: EntitySelector) -> anyhow::Result<()> { + kick_players( + ctx, + &targets, + TextValue::translate("multiplayer.disconnect.kicked").into(), + ) +} + +#[command(usage = "kick <targets> <reason>")] +pub fn kick_2( + ctx: &mut CommandCtx, + targets: EntitySelector, + reason: TextArgument, +) -> anyhow::Result<()> { + kick_players(ctx, &targets, reason.0.into()) +} + +fn kick_players( + ctx: &mut CommandCtx, + targets: &EntitySelector, + reason: Text, +) -> anyhow::Result<Option<String>> { + for entity in &targets.entities { + if ctx.world.try_get::<Player>(*entity).is_none() { + return Err(KickError::NoEntities.into()); + } + } + + for entity in &targets.entities { + let name = ctx.world.get::<Name>(*entity).0.clone(); + ctx.game + .disconnect_and_log(*entity, &mut ctx.world, &reason, "player kicked"); + + // Send confirmation message + // TODO Server ops should also see the message + if let Some(mut sender_message_receiver) = + ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + let kick_confirm = Text::from(TextValue::translate_with( + "commands.kick.success", + vec![Text::from(name), reason.clone()], + )); + sender_message_receiver.send(kick_confirm); + } + } + Ok(None) +} + +#[command(usage = "stop")] +pub fn stop(ctx: &mut CommandCtx) -> anyhow::Result<()> { + // Confirmation message + // TODO Server ops should also see the message + if let Some(mut sender_message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + let text = Text::from(TextValue::translate("commands.stop.stopping")); + sender_message_receiver.send(text); + } + + ctx.game + .resources + .get::<ShutdownChannels>() + .tx + .try_send(())?; + + Ok(None) +} + +#[derive(Debug, Error)] +pub enum ClearError { + #[error("command has to be run from a player")] + NotPlayer, + #[error("No items were found on player {0}")] + NoItems(String), + #[error("No items were found on {0}")] + NoItemsMultiplayer(String), + #[error( + "Only players may be affected by this command, but the provided selector includes entities" + )] + NoEntities, +} + +#[command(usage = "clear")] +pub fn clear_1(ctx: &mut CommandCtx) -> anyhow::Result<()> { + if ctx.world.try_get::<Player>(ctx.sender).is_some() { + // Go through the player's inventory and set all the slots to no items. + // Also, keep track of how many items we delete. + let mut count = 0; + clear_items(ctx, ctx.sender, None, i32::MAX, &mut count); + // If count is zero, the player's inventory was empty and the command fails + // "No items were found on player {0}." + if count == 0 { + let name = ctx.world.get::<Name>(ctx.sender); + return Err(ClearError::NoItems(name.0.clone()).into()); + } + // If the count is not zero, we return the count of items we deleted. Command succeeds. + // "Removed {1} items from player {0}" + Ok(Some(format!( + "Removed {1} items from player {0}", + ctx.world.get::<Name>(ctx.sender).0, + count + ))) + } else { + Err(ClearError::NotPlayer.into()) + } +} + +#[command(usage = "clear <targets>")] +pub fn clear_2(ctx: &mut CommandCtx, targets: EntitySelector) -> anyhow::Result<()> { + let mut players = true; + for entity in &targets.entities { + players &= ctx.world.try_get::<Player>(*entity).is_some(); + } + if players { + let mut count = 0; + for entity in &targets.entities { + clear_items(ctx, *entity, None, i32::MAX, &mut count); + } + // If count is zero, the everybody's inventory was empty and the command fails + // "No items were found on {0} players." + if count == 0 { + return Err( + ClearError::NoItemsMultiplayer(targets.entities_to_string(ctx, true)).into(), + ); + } + // If the count is not zero, we return the count of items we deleted. Command succeeds. + // "Removed {1} items from {0} players" + Ok(Some(format!( + "Removed {1} items from {0}", + targets.entities_to_string(ctx, true), + count + ))) + } else { + Err(ClearError::NoEntities.into()) + } +} + +#[command(usage = "clear <targets> <item>")] +pub fn clear_3( + ctx: &mut CommandCtx, + targets: EntitySelector, + item: ItemArgument, +) -> anyhow::Result<()> { + let mut players = true; + for entity in &targets.entities { + players &= ctx.world.try_get::<Player>(*entity).is_some(); + } + if players { + let mut count = 0; + for entity in &targets.entities { + clear_items(ctx, *entity, Some(item.0), i32::MAX, &mut count); + } + // If count is zero, the everybody's inventory was empty and the command fails + // "No items were found on {0} players." + if count == 0 { + return Err( + ClearError::NoItemsMultiplayer(targets.entities_to_string(ctx, true)).into(), + ); + } + // If the count is not zero, we return the count of items we deleted. Command succeeds. + // "Removed {1} items from {0} players" + Ok(Some(format!( + "Removed {1} items from {0}", + targets.entities_to_string(ctx, true), + count + ))) + } else { + Err(ClearError::NoEntities.into()) + } +} + +#[command(usage = "clear <targets> <item> <maxcount>")] +pub fn clear_4( + ctx: &mut CommandCtx, + targets: EntitySelector, + item: ItemArgument, + maxcount: PositiveI32Argument, +) -> anyhow::Result<()> { + let mut players = true; + for entity in &targets.entities { + players &= ctx.world.try_get::<Player>(*entity).is_some(); + } + if players { + let mut count = 0; + for entity in &targets.entities { + clear_items(ctx, *entity, Some(item.0), maxcount.0, &mut count); + } + // If count is zero, the everybody's inventory was empty and the command fails + // "No items were found on {0} players." + if count == 0 { + return Err( + ClearError::NoItemsMultiplayer(targets.entities_to_string(ctx, true)).into(), + ); + } + // If maxcount is 0, we report not that we removed items, only that we found them. + if maxcount.0 == 0 { + Ok(Some(format!( + "Found {1} matching items on {0}", + targets.entities_to_string(ctx, true), + count + ))) + } else { + // If the count is not zero, we return the count of items we deleted. Command succeeds. + // "Removed {1} items from {0} players" + Ok(Some(format!( + "Removed {1} items from {0}", + targets.entities_to_string(ctx, true), + count + ))) + } + } else { + Err(ClearError::NoEntities.into()) + } +} + +/// Go through a player's inventory and set all the slots that match "item" to empty, up to maxcount items removed. +/// Also, keep track of how many items we delete total in the variable count. +/// Will panic if entity does not have an inventory +fn clear_items( + ctx: &mut CommandCtx, + player: Entity, + item: Option<Item>, + maxcount: i32, + count: &mut i32, +) { + let inventory = ctx.world.get_mut::<Inventory>(player); + let mut changed_items: SmallVec<[SlotIndex; 2]> = SmallVec::new(); + for (index, slot) in inventory.enumerate() { + if let Some(mut stack) = slot { + if let Some(item_inner) = item { + if stack.ty != item_inner { + continue; + } + } + if maxcount == 0 { + *count += stack.amount as i32; + } else if (stack.amount as i32) <= maxcount - *count { + *count += stack.amount as i32; + inventory.remove_item_at(index.area, index.slot).unwrap(); + changed_items.push(index); + } else { + stack.amount -= (maxcount - *count) as u8; + inventory + .set_item_at(index.area, index.slot, stack) + .unwrap(); + *count = maxcount; + changed_items.push(index); + break; + } + } + } + + drop(inventory); + + if !changed_items.is_empty() { + ctx.game.handle( + &mut *ctx.world, + InventoryUpdateEvent { + entity: player, + slots: changed_items, + }, + ); + } +} + +#[command(usage = "seed")] +pub fn seed(ctx: &mut CommandCtx) -> anyhow::Result<()> { + if let Some(mut message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) { + message_receiver.send( + Text::from("Seed: [") + + Text::from(ctx.game.level.seed.to_string()) + .green() + .insertion(ctx.game.level.seed.to_string()) + + Text::from("]"), + ); + } + Ok(None) +} + +#[derive(Debug, Error)] +pub enum BanError { + #[error( + "Only players may be affected by this command, but the provided selector includes entities" + )] + NotPlayer, + #[error("Already banned")] + NoTargets, +} + +#[command(usage = "ban <targets> <reason>")] +pub fn ban_withreason( + ctx: &mut CommandCtx, + targets: EntitySelector, + reason: TextArgument, +) -> anyhow::Result<()> { + ban_players(ctx, targets, reason.0, false) +} + +#[command(usage = "ban <targets>")] +pub fn ban_noreason(ctx: &mut CommandCtx, targets: EntitySelector) -> anyhow::Result<()> { + ban_players(ctx, targets, "Banned by an operator.".to_owned(), false) +} + +#[command(usage = "ban-ip <targets> <reason>")] +pub fn banip_withreason( + ctx: &mut CommandCtx, + targets: EntitySelector, + reason: TextArgument, +) -> anyhow::Result<()> { + ban_players(ctx, targets, reason.0, true) +} + +#[command(usage = "ban-ip <targets>")] +pub fn banip_noreason(ctx: &mut CommandCtx, targets: EntitySelector) -> anyhow::Result<()> { + ban_players(ctx, targets, "Banned by an operator.".to_owned(), true) +} + +#[derive(Debug, Error)] +pub enum BanIpError { + #[error("Not a valid IP Address.")] + InvalidIp, +} + +#[command(usage = "ban-ip <ip> <reason>")] +pub fn banip_withreason_ip( + ctx: &mut CommandCtx, + ip: String, + reason: TextArgument, +) -> anyhow::Result<()> { + ban_ip(ctx, ip, reason.0) +} + +#[command(usage = "ban-ip <ip>")] +pub fn banip_noreason_ip(ctx: &mut CommandCtx, ip: String) -> anyhow::Result<()> { + ban_ip(ctx, ip, "IP Banned by an operator.".to_string()) +} + +pub fn ban_ip(ctx: &mut CommandCtx, ip: String, reason: String) -> anyhow::Result<Option<String>> { + let ip = IpAddr::from_str(&ip).map_err(|_| BanIpError::InvalidIp)?; + + { + let bi_lock = ctx.game.resources.get::<WrappedBanInfo>(); + let mut ban_info = bi_lock.write().unwrap(); + + ban_info.ip_bans.insert( + ip, + Ban { + reason: reason.clone(), + expires_after: None, + }, + ); + } + + if let Some(mut sender_message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + let ban_confirm = Text::from(TextValue::translate_with( + "commands.ban.success", + vec![Text::from(ip.to_string()), Text::from(reason.clone())], + )); + sender_message_receiver.send(ban_confirm); + } + + let ent = Read::<(SocketAddr, Entity)>::query() + .iter(ctx.world.inner()) + .find(|x| x.0.ip() == ip) + .map(|x| (*x).1); + + if let Some(ent) = ent { + ctx.game.disconnect_and_log( + ent, + &mut ctx.world, + &Text::from(reason), + "Banned by an operator.", + ); + } + + Ok(None) +} + +pub fn ban_players( + ctx: &mut CommandCtx, + targets: EntitySelector, + reason: String, + by_ip: bool, +) -> anyhow::Result<Option<String>> { + if targets.entities.is_empty() { + return Err(BanError::NoTargets.into()); + } + + for entity in &targets.entities { + if ctx.world.try_get::<Player>(*entity).is_none() { + return Err(BanError::NotPlayer.into()); + } + } + + for entity in &targets.entities { + { + let bi_lock = ctx.game.resources.get::<WrappedBanInfo>(); + let mut ban_info = bi_lock.write().unwrap(); + + if by_ip { + let ip = ctx.world.try_get::<SocketAddr>(*entity).unwrap(); + + ban_info.ip_bans.insert( + ip.ip(), + Ban { + reason: reason.clone(), + expires_after: None, + }, + ); + } else { + let uuid = ctx.world.try_get::<Uuid>(*entity).unwrap(); + + ban_info.uuid_bans.insert( + uuid.to_hyphenated_ref().to_string(), + Ban { + reason: reason.clone(), + expires_after: None, + }, + ); + } + } + + let name = ctx.world.try_get::<Name>(*entity).unwrap().0.clone(); + if let Some(mut sender_message_receiver) = + ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + let ban_confirm = Text::from(TextValue::translate_with( + "commands.ban.success", + vec![Text::from(name), Text::from(reason.clone())], + )); + sender_message_receiver.send(ban_confirm); + } + + ctx.game.disconnect_and_log( + *entity, + &mut ctx.world, + &Text::from(reason.clone()), + "Banned by an operator.", + ); + } + + Ok(None) +} + +#[derive(Debug, Error)] +pub enum PardonError { + #[error("Couldn't find that players UUID, Have they changed name?")] + NotPlayer, +} + +#[command(usage = "pardon <name>")] +pub fn pardon(ctx: &mut CommandCtx, name: TextArgument) -> anyhow::Result<()> { + // Get UUID from name + let online_mode = ctx.game.shared.config.server.online_mode; + let uuid = if online_mode { + Runtime::new() + .unwrap() + .block_on(name_to_uuid_online(&name.0)) + } else { + Some(name_to_uuid_offline(&name.0)) + }; + + let uuid = match uuid { + Some(uuid) => uuid, + None => return Err(PardonError::NotPlayer.into()), + }; + + { + let bi_lock = ctx.game.resources.get::<WrappedBanInfo>(); + let mut ban_info = bi_lock.write().unwrap(); + ban_info + .uuid_bans + .remove(&uuid.to_hyphenated_ref().to_string()); + } + + if let Some(mut sender_message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + let kick_confirm = Text::from(TextValue::translate_with( + "commands.pardon.success", + vec![Text::from(name.0)], + )); + sender_message_receiver.send(kick_confirm); + } + + Ok(None) +} + +#[derive(Debug, Error)] +pub enum PardonIpError { + #[error("Invalid IP Address")] + NotIp, +} + +#[command(usage = "pardon-ip <ip>")] +pub fn pardonip(ctx: &mut CommandCtx, ip: String) -> anyhow::Result<()> { + // Try to parse ip + let addr = IpAddr::from_str(&ip).map_err(|_| PardonIpError::NotIp)?; + + { + let bi_lock = ctx.game.resources.get::<WrappedBanInfo>(); + let mut ban_info = bi_lock.write().unwrap(); + ban_info.ip_bans.remove(&addr); + } + + if let Some(mut sender_message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + let kick_confirm = Text::from(TextValue::translate_with( + "commands.pardon.success", + vec![Text::from(ip)], + )); + sender_message_receiver.send(kick_confirm); + } + + Ok(None) +} + +#[command(usage = "time query <info>")] +pub fn time_query(ctx: &mut CommandCtx, info: TimeQueryInformation) -> anyhow::Result<()> { + let time = match info { + TimeQueryInformation::DayTime => ctx.game.time.time_of_day(), + TimeQueryInformation::GameTime => ctx.game.time.world_age(), + TimeQueryInformation::Day => ctx.game.time.days(), + }; + + if let Some(mut sender_message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + let message = Text::from(TextValue::translate_with( + "commands.time.query", + vec![Text::from(time.to_string())], + )); + sender_message_receiver.send(message); + } + + Ok(None) +} + +#[command(usage = "time add <time>")] +pub fn time_add(ctx: &mut CommandCtx, time: TimeArgument) -> anyhow::Result<()> { + time_set(ctx, ctx.game.time.time_of_day() + time.0) +} + +#[command(usage = "time set <time>")] +pub fn time_set_0(ctx: &mut CommandCtx, time: TimeArgument) -> anyhow::Result<()> { + time_set(ctx, time.0) +} + +#[command(usage = "time set <time_spec>")] +pub fn time_set_1(ctx: &mut CommandCtx, time_spec: TimeSpec) -> anyhow::Result<()> { + time_set( + ctx, + match time_spec { + TimeSpec::Day => 1_000, + TimeSpec::Noon => 6_000, + TimeSpec::Night => 13_000, + TimeSpec::Midnight => 18_000, + }, + ) +} + +pub fn time_set(ctx: &mut CommandCtx, time: u64) -> anyhow::Result<Option<String>> { + ctx.game + .handle(&mut ctx.world, TimeUpdateEvent { new_time: time }); + + if let Some(mut sender_message_receiver) = ctx.world.try_get_mut::<MessageReceiver>(ctx.sender) + { + let message = Text::from(TextValue::translate_with( + "commands.time.set", + vec![Text::from(ctx.game.time.time_of_day().to_string())], + )); + sender_message_receiver.send(message); + } + + Ok(None) +} diff --git a/feather/old/server/commands/src/lib.rs b/feather/old/server/commands/src/lib.rs new file mode 100644 index 000000000..b070bddbe --- /dev/null +++ b/feather/old/server/commands/src/lib.rs @@ -0,0 +1,175 @@ +//! Implements the Feather command dispatching framework, +//! based on our `lieutenant` library (a Rust fork +//! of Mojang's [brigadier](https://github.com/Mojang/brigadier). +//! +//! Also implements vanilla commands not defined by plugins. + +mod arguments; +mod impls; + +use feather_core::text::{Text, TextComponentBuilder}; +use feather_server_types::{Game, MessageReceiver}; +use fecs::{Entity, World}; +use impls::*; +use lieutenant::CommandDispatcher; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + +/// Dumb workaround for a certain lifetime issue. +/// +/// `CommandCtx` stores references to `Game`, and it +/// is used as the `C` parameter for `CommandDispatcher`, +/// This combination of lifetimes and storage in structs +/// prevents a lifetime-based `CommandCtx` from being stored +/// in `CommandState` without adding a lifetime parameter to `CommandState`. +/// +/// Since `CommandCtx` is never actually _stored_ in `CommandState` (it's +/// only passed into a function), we can (hopefully) soundly erase +/// the lifetime parameters. FIXME: if someone has a better solution, +/// a PR is welcome :) +pub struct LifetimelessMut<T>(*mut T); + +impl<T> Deref for LifetimelessMut<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &mut *self.0 } + } +} + +impl<T> DerefMut for LifetimelessMut<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.0 } + } +} + +unsafe impl<T> Send for LifetimelessMut<T> where T: Send {} +unsafe impl<T> Sync for LifetimelessMut<T> where T: Sync {} + +/// Context passed into a command. This value can be used +/// for access to game and entity data, such as components. +pub struct CommandCtx { + /// The entity which triggered the command. + /// + /// _Not necessarily a player_. If the command was executed + /// from the server console, then this will be the "server entity" + /// associated with the console. You may check if an entity is a player + /// by checking if it has the `Player` component. Similarly, you + /// may check if an entity is the server console through the `Console` component. + /// + /// Note that players and the console are not the only possible command senders, + /// and command implementations should account for this. + pub sender: Entity, + /// The game state. + pub game: LifetimelessMut<Game>, + /// The `World`, for access to components. + pub world: LifetimelessMut<World>, +} + +impl lieutenant::Context for CommandCtx { + type Error = anyhow::Error; + type Ok = Option<String>; +} + +macro_rules! commands { + ($dispatcher:ident : $($command:expr,)*) => { + $( + $dispatcher.register($command).unwrap(); + )* + } +} + +/// State storing all registered commands. +pub struct CommandState { + dispatcher: Arc<CommandDispatcher<CommandCtx>>, +} + +impl Default for CommandState { + fn default() -> Self { + Self::new() + } +} + +impl CommandState { + /// Initializes the command state. + pub fn new() -> Self { + let mut dispatcher = CommandDispatcher::<CommandCtx>::new(); + + commands! { + dispatcher: + tp_1, + tp_2, + tp_3, + tp_4, + + gamemode_1, + gamemode_2, + + whisper, + say, + me, + + kick_1, + kick_2, + + stop, + + clear_1, + clear_2, + clear_3, + clear_4, + + seed, + + ban_withreason, + ban_noreason, + banip_withreason, + banip_noreason, + banip_withreason_ip, + banip_noreason_ip, + + pardon, + pardonip, + + time_query, + time_add, + time_set_0, + time_set_1, + } + + Self { + dispatcher: Arc::new(dispatcher), + } + } + + /// Dispatches a command. + pub fn dispatch(&self, game: &mut Game, world: &mut World, sender: Entity, command: &str) { + let mut ctx = CommandCtx { + game: LifetimelessMut(game), + world: LifetimelessMut(world), + sender, + }; + + match self.dispatcher.dispatch(&mut ctx, command) { + Ok(ok) => { + if let Some(msg) = ok { + if let Some(mut receiver) = world.try_get_mut::<MessageReceiver>(sender) { + receiver.send(Text::from(msg)); + } + } + } + + Err(errs) => { + let msg = if let Some(last) = errs.last() { + Text::from(last.to_string()).red() + } else { + Text::from("Unknown command.") + }; + + if let Some(mut receiver) = world.try_get_mut::<MessageReceiver>(sender) { + receiver.send(msg); + } + } + } + } +} diff --git a/feather/old/server/config/Cargo.toml b/feather/old/server/config/Cargo.toml new file mode 100644 index 000000000..693d52d9d --- /dev/null +++ b/feather/old/server/config/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "feather-server-config" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-util = { path = "../../core/util" } + +tokio = { version = "0.2", features = ["full"] } +anyhow = "1.0" +serde = { version = "1.0", features = ["derive"] } +humantime-serde = "1.0" +toml = "0.5" diff --git a/feather/old/server/config/src/lib.rs b/feather/old/server/config/src/lib.rs new file mode 100644 index 000000000..d3fc734b2 --- /dev/null +++ b/feather/old/server/config/src/lib.rs @@ -0,0 +1,207 @@ +#![forbid(unsafe_code)] + +//! Defines the server configuration file, feather.toml. + +use std::collections::HashMap; +use std::net::IpAddr; +use std::time::SystemTime; + +use feather_util::Gamemode; +use serde::{Deserialize, Serialize}; +use std::time::Duration; +use tokio::fs::File; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Config { + pub io: IO, + pub proxy: Proxy, + pub server: Server, + pub gameplay: Gameplay, + pub log: Log, + pub resource_pack: ResourcePack, + pub world: World, +} + +impl Config { + /// Loads a config from the given string. + pub fn load(s: &str) -> anyhow::Result<Config> { + toml::from_str(s).map_err(Into::into) + } + + /// Loads a config from the given file. + pub async fn load_from_file(f: &mut File) -> anyhow::Result<Config> { + let mut s = String::new(); + f.read_to_string(&mut s).await?; + Self::load(&s) + } + + /// Saves the configuration, writing its contents to the given string. + pub fn save(&self) -> String { + toml::to_string_pretty(self).expect("failed to serialize config") + } + + /// Saves the configuration to the given file. + pub async fn save_to_file(&self, f: &mut File) -> anyhow::Result<()> { + let string = self.save(); + + f.write_all(string.as_bytes()).await.map_err(Into::into) + } +} + +pub const DEFAULT_CONFIG_STR: &str = include_str!("../feather.toml"); + +impl Default for Config { + fn default() -> Self { + toml::from_str(DEFAULT_CONFIG_STR).unwrap() + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct IO { + pub compression_threshold: i32, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Proxy { + pub proxy_mode: ProxyMode, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Server { + pub online_mode: bool, + pub motd: String, + pub max_players: i32, + pub view_distance: u8, + pub address: String, + pub port: u16, + pub default_gamemode: Gamemode, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Gameplay { + pub monster_spawning: bool, + pub animal_spawning: bool, + pub pvp: bool, + pub nerf_spawner_mobs: bool, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Log { + pub level: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ResourcePack { + pub url: String, + pub hash: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct World { + pub name: String, + pub generator: String, + pub seed: String, + #[serde(with = "humantime_serde")] + pub save_interval: Duration, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub enum ProxyMode { + #[serde(alias = "none")] + None, + #[serde(alias = "bungeecord")] + BungeeCord, + #[serde(alias = "velocity")] + Velocity, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct BanInfo { + pub ip_bans: HashMap<IpAddr, Ban>, + pub uuid_bans: HashMap<String, Ban>, +} + +impl BanInfo { + /// An empty list of bans + pub fn default() -> BanInfo { + BanInfo { + ip_bans: HashMap::new(), + uuid_bans: HashMap::new(), + } + } + + /// Loads the bans from the given string. + pub fn load(s: &str) -> anyhow::Result<BanInfo> { + toml::from_str(s).map_err(Into::into) + } + + /// Loads the bans from the given file. + pub async fn load_from_file(f: &mut File) -> anyhow::Result<BanInfo> { + let mut s = String::new(); + f.read_to_string(&mut s).await?; + Self::load(&s) + } + + /// Saves the ban info, writing its contents to the given string. + pub fn save(&self) -> String { + toml::to_string_pretty(self).expect("failed to serialize config") + } + + /// Saves the ban info to the given file. + pub async fn save_to_file(&self, f: &mut File) -> anyhow::Result<()> { + let string = self.save(); + + f.write_all(string.as_bytes()).await.map_err(Into::into) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Ban { + pub expires_after: Option<SystemTime>, + pub reason: String, +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_load_config() { + let input = include_str!("../feather.toml"); + + let config = Config::load(input).expect("invalid default configuration"); + let io = &config.io; + assert_eq!(io.compression_threshold, 256); + + let server = &config.server; + assert_eq!(server.online_mode, true); + assert_eq!(server.motd, "A Feather server"); + assert_eq!(server.max_players, 16); + assert_eq!(server.default_gamemode, Gamemode::Creative); + assert_eq!(server.view_distance, 6); + assert_eq!(server.address, "0.0.0.0"); + assert_eq!(server.port, 25565); + + let gameplay = &config.gameplay; + assert_eq!(gameplay.animal_spawning, true); + assert_eq!(gameplay.monster_spawning, true); + assert_eq!(gameplay.pvp, true); + assert_eq!(gameplay.nerf_spawner_mobs, false); + + let log = &config.log; + assert_eq!(log.level, "debug"); + + let resource_pack = &config.resource_pack; + assert_eq!(resource_pack.url, ""); + assert_eq!(resource_pack.hash, ""); + + let world = &config.world; + assert_eq!(world.name, "world"); + assert_eq!(world.generator, "default"); + assert_eq!(world.seed, ""); + assert_eq!(world.save_interval.as_millis(), 1000 * 60); + + let proxy = &config.proxy; + assert_eq!(proxy.proxy_mode, ProxyMode::None); + } +} diff --git a/feather/old/server/entity/Cargo.toml b/feather/old/server/entity/Cargo.toml new file mode 100644 index 000000000..fec0f8f4b --- /dev/null +++ b/feather/old/server/entity/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "feather-server-entity" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +nalgebra-glm = "0.6" +inventory = "0.1" +parking_lot = "0.10" +rand = "0.7" +anyhow = "1.0" +num-traits = "0.2" +num-derive = "0.3" +log = "0.4" +smallvec = "1.4" + +[dev-dependencies] +feather-test-framework = { path = "../test" } diff --git a/feather/old/server/entity/src/broadcasters.rs b/feather/old/server/entity/src/broadcasters.rs new file mode 100644 index 000000000..f46414674 --- /dev/null +++ b/feather/old/server/entity/src/broadcasters.rs @@ -0,0 +1,13 @@ +mod entity_creation; +mod entity_deletion; +mod inventory; +mod item_collect; +mod metadata; +mod movement; + +pub use self::inventory::*; +pub use entity_creation::*; +pub use entity_deletion::*; +pub use item_collect::*; +pub use metadata::*; +pub use movement::*; diff --git a/feather/old/server/entity/src/broadcasters/entity_creation.rs b/feather/old/server/entity/src/broadcasters/entity_creation.rs new file mode 100644 index 000000000..400649351 --- /dev/null +++ b/feather/old/server/entity/src/broadcasters/entity_creation.rs @@ -0,0 +1,136 @@ +use feather_core::entitymeta::EntityMetadata; +use feather_core::network::packets::PacketEntityMetadata; +use feather_core::util::Position; +use feather_server_types::{ + CreationPacketCreator, EntitySendEvent, EntitySpawnEvent, Game, Network, NetworkId, + PlayerJoinEvent, SpawnPacketCreator, +}; +use fecs::{IntoQuery, Read, World}; + +/// When an entity is created and has a `CreationPacketCreator` and/or `SpawnPacketCreator`, +/// broadcasts the packets to all online clients. +#[fecs::event_handler] +pub fn on_entity_spawn_send_to_clients( + event: &EntitySpawnEvent, + game: &mut Game, + world: &mut World, +) { + let accessor = world.entity(event.entity).expect("entity does not exist"); + + if let Some(creator) = world.try_get::<CreationPacketCreator>(event.entity) { + let packet = creator.get(&accessor); + game.broadcast_global_boxed(world, packet, None); + } + let mut to_trigger = vec![]; + + if let Some(creator) = world.try_get::<SpawnPacketCreator>(event.entity) { + // Send metadata before spawn packet. Not sure why this works, + // but if we don't do this, then the client just despawns + // the entity immediately after sending. + if let Some(meta) = world.try_get::<EntityMetadata>(event.entity) { + let packet = PacketEntityMetadata { + entity_id: world.get::<NetworkId>(event.entity).0, + metadata: (&*meta).clone(), + }; + game.broadcast_entity_update(world, packet, event.entity, Some(event.entity)); + } + + // Now send spawn packet: Spawn Object / Spawn Player / Spawn Mob / whatever. + let packet = creator.get(&accessor); + game.broadcast_entity_update_boxed(world, packet, event.entity, Some(event.entity)); + + let chunk = world.get::<Position>(event.entity).chunk(); + + drop(creator); + + // trigger on_entity_send + for player in game.chunk_holders.holders_for(chunk) { + if world.try_get::<Network>(*player).is_some() { + to_trigger.push(*player); + } + } + } + + for client in to_trigger { + game.handle( + world, + EntitySendEvent { + entity: event.entity, + client, + }, + ); + } +} + +/// Wehn a player joins, sends existing entities to the player. +/// +/// This only handles init packets (PlayerInfo, etc.)—spawn packets +/// are handled by the view update mechanism in `crate::view`. +#[fecs::event_handler] +pub fn on_player_join_send_existing_entities(event: &PlayerJoinEvent, world: &mut World) { + let network = world.get::<Network>(event.player); + for (entity, creator) in <Read<CreationPacketCreator>>::query().iter_entities(world.inner()) { + let accessor = world + .entity(entity) + .expect("query yielded entity which does not exist"); + let packet = creator.get(&accessor); + network.send_boxed(packet); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::item; + use feather_core::items::{Item, ItemStack}; + use feather_core::network::packets::{PlayerInfo, SpawnObject}; + use feather_core::position; + use feather_test_framework::Test; + use std::collections::HashSet; + + #[test] + fn send_on_spawn() { + let stack = ItemStack::new(Item::Sand, 47); + let mut test = Test::new(); + + let item1 = + test.entity(item::create(stack, Default::default()).with(position!(0.0, 100.0, 0.0))); + let player1 = test.player("player1", Position::default()); + let player2 = test.player("player2", position!(234_234.0, 342.0, 23.0)); + + test.handle( + EntitySpawnEvent { entity: item1 }, + on_entity_spawn_send_to_clients, + ); + + let sent = test.sent::<SpawnObject>(player1).unwrap(); + assert_eq!(sent.entity_id, test.id(item1)); + + assert!(test.sent::<SpawnObject>(player2).is_none()); + } + + #[test] + fn send_existing_entities() { + let mut test = Test::new(); + + let player1 = test.player("player1", position!(1000.0, -5.0, 0.0)); + let player2 = test.player("player2", position!(2000.0, 2_138_901.0, 0.0)); + let player3 = test.player("player3", position!(950.0, 255.0, 0.0)); + + test.handle( + PlayerJoinEvent { player: player3 }, + on_player_join_send_existing_entities, + ); + + let mut players_sent = HashSet::new(); + for _ in 0..3 { + let packet = test.sent::<PlayerInfo>(player3).unwrap(); + + players_sent.insert(packet.uuid); + } + + for expected in &[player1, player2, player3] { + assert!(players_sent.contains(&test.uuid(*expected))); + } + } +} diff --git a/feather/old/server/entity/src/broadcasters/entity_deletion.rs b/feather/old/server/entity/src/broadcasters/entity_deletion.rs new file mode 100644 index 000000000..f8d61cddf --- /dev/null +++ b/feather/old/server/entity/src/broadcasters/entity_deletion.rs @@ -0,0 +1,102 @@ +use feather_core::{ + network::{ + packets::{DestroyEntities, PlayerInfo, PlayerInfoAction, UpdateBlockEntity}, + Packet, + }, + util::BlockPosition, +}; +use feather_server_types::{BlockEntity, EntityDespawnEvent, Game, NetworkId, Player, Uuid}; +use fecs::{Entity, World}; + +/// Broadcasts when an entity is deleted. +#[fecs::event_handler] +pub fn on_entity_despawn_broadcast_despawn( + event: &EntityDespawnEvent, + game: &mut Game, + world: &mut World, +) { + let packet = packet_to_despawn(event.entity, world); + + game.broadcast_entity_update_boxed(world, packet, event.entity, Some(event.entity)); + + // If the entity was a player, send Player Info to + // remove them from the tablist. + if world.has::<Player>(event.entity) { + let uuid = *world.get::<Uuid>(event.entity); + let packet = PlayerInfo { + action: PlayerInfoAction::RemovePlayer, + uuid, + }; + + game.broadcast_global(world, packet, None); + } +} + +fn packet_to_despawn(entity: Entity, world: &World) -> Box<dyn Packet> { + // For normal entities, use Destroy Entities. + // For block entities, send Update Block Entity + // with a single TAG_END to remove the block entity + // at the position. + + if world.has::<BlockEntity>(entity) { + Box::new(UpdateBlockEntity { + location: *world.get::<BlockPosition>(entity), + ..Default::default() + }) + } else { + Box::new(DestroyEntities { + entity_ids: vec![world.get::<NetworkId>(entity).0], + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::item; + use feather_core::items::ItemStack; + use feather_core::util::Position; + use feather_test_framework::Test; + + #[test] + fn broadcast_despawn() { + let mut test = Test::new(); + + let player = test.player("", Position::default()); + let player_far_away = test.player("faraway", position!(0.0, 0.0, 10000.0)); + let item = + test.entity(item::create(ItemStack::default(), 0).with(position!(10.0, 64.0, 0.0))); + + test.handle( + EntityDespawnEvent { entity: item }, + on_entity_despawn_broadcast_despawn, + ); + + let packet = test.sent::<DestroyEntities>(player).unwrap(); + assert_eq!(packet.entity_ids, vec![test.id(item)]); + assert!(test.sent::<PlayerInfo>(player).is_none()); + + assert!(test.sent::<DestroyEntities>(player_far_away).is_none()); + assert!(test.sent::<PlayerInfo>(player_far_away).is_none()); + + let player2 = test.player("", position!(45.0, -324.0, 16.8)); + test.handle( + EntityDespawnEvent { entity: player2 }, + on_entity_despawn_broadcast_despawn, + ); + + let packet = test.sent::<DestroyEntities>(player).unwrap(); + assert_eq!(packet.entity_ids, vec![test.id(player2)]); + + // player_far_away should receive because PlayerInfo is broadcasted globally + let packets = [ + test.sent::<PlayerInfo>(player).unwrap(), + test.sent::<PlayerInfo>(player_far_away).unwrap(), + ]; + + for packet in &packets { + assert_eq!(packet.uuid, test.uuid(player2)); + assert_eq!(packet.action, PlayerInfoAction::RemovePlayer); + } + } +} diff --git a/feather/old/server/entity/src/broadcasters/inventory.rs b/feather/old/server/entity/src/broadcasters/inventory.rs new file mode 100644 index 000000000..c69436cdb --- /dev/null +++ b/feather/old/server/entity/src/broadcasters/inventory.rs @@ -0,0 +1,327 @@ +//! Broadcasting of inventory-related events. + +use crate::inventory::Equipment; +use feather_core::inventory::{slot, Area, Inventory, SlotIndex, Window}; +use feather_core::network::packets::{EntityEquipment, NamedSoundEffect, SetSlot, SoundCategory}; +use feather_core::util::Position; +use feather_server_types::{ + EntitySendEvent, Game, HeldItem, InventoryUpdateEvent, ItemDamageEvent, Network, NetworkId, + Player, +}; +use fecs::{Entity, World}; +use num_traits::ToPrimitive; +use rand::Rng; +use smallvec::smallvec; + +/// System for broadcasting equipment updates. +#[fecs::event_handler] +pub fn on_inventory_update_broadcast_equipment_update( + event: &InventoryUpdateEvent, + game: &mut Game, + world: &mut World, +) { + let inv = world.get::<Inventory>(event.entity); + let held_item = match world.try_get::<HeldItem>(event.entity) { + Some(item) => item, + None => return, // entity has no equipment (e.g. chest) + }; + + for slot in &event.slots { + // Skip this slot if it is not an equipment update. + if let Ok(equipment) = is_equipment_update(held_item.0, *slot) { + let slot = equipment.slot_index(held_item.0); + let item = inv + .item_at(slot.area, slot.slot) + .expect("invalid InventoryUpdateEvent"); + + let packet = EntityEquipment { + entity_id: world.get::<NetworkId>(event.entity).0, + slot: equipment.to_i32().unwrap(), + item, + }; + + game.broadcast_entity_update(world, packet, event.entity, Some(event.entity)); + } + } +} + +/// System to send an entity's equipment when the +/// entity is sent to a client. +#[fecs::event_handler] +pub fn on_entity_send_send_equipment(event: &EntitySendEvent, world: &mut World) { + let client = event.client; + let entity = event.entity; + if !world.is_alive(client) || !world.is_alive(entity) { + return; + } + + let network = world.get::<Network>(client); + let inventory = match world.try_get::<Inventory>(entity) { + Some(inv) => inv, + None => return, // no equipment to send + }; + let held_item = match world.try_get::<HeldItem>(entity) { + Some(item) => item, + None => return, + }; + + let equipments = [ + Equipment::MainHand, + Equipment::Boots, + Equipment::Leggings, + Equipment::Chestplate, + Equipment::Helmet, + Equipment::OffHand, + ]; + + for equipment in equipments.iter() { + let item = { + let slot = equipment.slot_index(held_item.0); + match inventory.item_at(slot.area, slot.slot).unwrap() { + Some(item) => item, + None => continue, // don't send equipment if it doesn't exist + } + }; + + let equipment_slot = equipment.to_i32().unwrap(); + + let packet = EntityEquipment { + entity_id: world.get::<NetworkId>(entity).0, + slot: equipment_slot, + item: Some(item), + }; + network.send(packet); + } +} + +/// System for sending the Set Slot packet +/// when a player's inventory is updated. +#[fecs::event_handler] +pub fn on_inventory_update_send_set_slot(event: &InventoryUpdateEvent, world: &mut World) { + if !world.has::<Player>(event.entity) { + return; + } + + let inv = world.get::<Inventory>(event.entity); + let network = world.get::<Network>(event.entity); + let window = world.get::<Window>(event.entity); + + for slot in &event.slots { + let converted = window.convert_slot(*slot, event.entity).unwrap_or(0); + let packet = SetSlot { + window_id: 0, + slot: converted as i16, + slot_data: inv.item_at(slot.area, slot.slot).unwrap(), + }; + + network.send(packet); + } +} + +/// Returns whether the given update to an inventory +/// is an equipment update. +fn is_equipment_update(held_item: usize, slot: SlotIndex) -> Result<Equipment, ()> { + if slot.area == Area::Hotbar && slot.slot == held_item { + Ok(Equipment::MainHand) + } else if let Some(equipment) = Equipment::from_slot_index(slot, held_item) { + Ok(equipment) + } else { + Err(()) + } +} + +/// System for damaging inventory items which should take damage. +#[fecs::event_handler] +pub fn on_damage_item(event: &ItemDamageEvent, game: &mut Game, world: &mut World) { + let inventory = world.get_mut::<Inventory>(event.player); + + let mut item = match inventory.item_at_mut(event.slot.area, event.slot.slot) { + Ok(guard) => guard.unwrap(), + Err(_) => return, + }; + + item.damage = Some(item.damage.unwrap_or_default() + event.damage_taken as i32); + let item_broken = if let Some(durability) = item.ty.durability() { + if item.damage.unwrap() >= durability as i32 { + inventory + .remove_item_at(event.slot.area, event.slot.slot) + .unwrap(); + true + } else { + inventory + .set_item_at(event.slot.area, event.slot.slot, item) + .unwrap(); + false + } + } else { + return; // Items with no durability shouldn't take damage + }; + drop(inventory); + + if item_broken { + send_item_broken_sound_effect(event.player, game, world); + } + + let inv_update = InventoryUpdateEvent { + slots: smallvec![slot(event.slot.area, event.slot.slot)], + entity: event.player, + }; + game.handle(world, inv_update); +} + +fn send_item_broken_sound_effect(player: Entity, game: &mut Game, world: &mut World) { + let (effect_pos_x, effect_pos_y, effect_pos_z) = { + let pos = world.get::<Position>(player); + ( + // https://wiki.vg/Data_types#Fixed-point_numbers + (pos.x * 8.0) as i32, + (pos.y * 8.0) as i32, + (pos.z * 8.0) as i32, + ) + }; + let mut rng = game.rng(); + let sound_packet = NamedSoundEffect { + sound_name: "entity.item.break".into(), + sound_category: SoundCategory::Players as i32, + effect_pos_x, + effect_pos_y, + effect_pos_z, + volume: 1.0, + pitch: rng.gen_range(0.8, 1.2), + }; + + let network = world.get::<Network>(player); + network.send(sound_packet); +} + +#[cfg(test)] +mod tests { + use super::*; + use feather_core::items::{Item, ItemStack}; + use feather_test_framework::Test; + use smallvec::smallvec; + + #[test] + fn broadcast_equipment_updates() { + let mut test = Test::new(); + + let player1 = test.player("", position!(0.0, 100.0, 0.0)); + let player2 = test.player("", position!(45.0, 150.0, 45.0)); + let player3 = test.player("", position!(1000.00, 100.0, 0.0)); + + let slot = SlotIndex { + area: Area::Hotbar, + slot: 2, + }; + let stack = ItemStack::new(Item::Stone, 48); + test.world.get_mut::<HeldItem>(player1).0 = 2; + test.world + .get::<Inventory>(player1) + .set_item_at(slot.area, slot.slot, stack) + .unwrap(); + + test.handle( + InventoryUpdateEvent { + slots: smallvec![slot], + entity: player1, + }, + on_inventory_update_broadcast_equipment_update, + ); + + let packet = test.sent::<EntityEquipment>(player2).unwrap(); + assert_eq!(packet.entity_id, test.id(player1)); + assert_eq!(packet.item, Some(stack)); + assert_eq!(packet.slot, Equipment::MainHand.to_i32().unwrap()); + + assert!(test.sent::<EntityEquipment>(player3).is_none()); + assert!(test.sent::<EntityEquipment>(player1).is_none()); + + // now do player3 + test.world.get_mut::<HeldItem>(player3).0 = 2; + test.world + .get::<Inventory>(player3) + .set_item_at(slot.area, slot.slot, stack) + .unwrap(); + + test.handle( + InventoryUpdateEvent { + slots: smallvec![slot], + entity: player3, + }, + on_inventory_update_broadcast_equipment_update, + ); + + for player in &[player1, player2, player3] { + assert!(test.sent::<EntityEquipment>(*player).is_none()); + } + } + + #[test] + fn send_equipment_on_send() { + let mut test = Test::new(); + + let stack = ItemStack::new(Item::EnderPearl, 15); + let slot = SlotIndex { + area: Area::Hotbar, + slot: 0, + }; + let (packet, player) = test.broadcast_routine::<EntityEquipment, _, _, _>( + |test, player1, player2| { + test.world + .get::<Inventory>(player1) + .set_item_at(slot.area, slot.slot, stack) + .unwrap(); + EntitySendEvent { + entity: player1, + client: player2, + } + }, + on_entity_send_send_equipment, + false, + ); + + assert_eq!(packet.slot, Equipment::MainHand.to_i32().unwrap()); + assert_eq!(packet.entity_id, test.id(player)); + assert_eq!(packet.item, Some(stack)); + } + + #[test] + fn send_set_slot() { + let mut test = Test::new(); + + let stack = ItemStack { + ty: Item::StoneShovel, + amount: 1, + damage: Some(10), + }; + let slot = SlotIndex { + area: Area::Main, + slot: 4, + }; + + let player1 = test.player("", position!(0.0, 74.0, 0.0)); + let player2 = test.player("", position!(0.0, 50.0, 1.5)); + + test.world + .get::<Inventory>(player1) + .set_item_at(slot.area, slot.slot, stack) + .unwrap(); + + test.handle( + InventoryUpdateEvent { + slots: smallvec![slot], + entity: player1, + }, + on_inventory_update_send_set_slot, + ); + + let packet = test.sent::<SetSlot>(player1).unwrap(); + assert_eq!( + packet.slot, + Window::player(player1).convert_slot(slot, player1).unwrap() as i16 + ); + assert_eq!(packet.slot_data, Some(stack)); + + assert!(test.sent::<SetSlot>(player2).is_none()); + } +} diff --git a/feather/old/server/entity/src/broadcasters/item_collect.rs b/feather/old/server/entity/src/broadcasters/item_collect.rs new file mode 100644 index 000000000..30b11c514 --- /dev/null +++ b/feather/old/server/entity/src/broadcasters/item_collect.rs @@ -0,0 +1,45 @@ +use feather_core::network::packets::CollectItem; +use feather_server_types::{Game, ItemCollectEvent, NetworkId}; +use fecs::World; + +/// Sends `CollectItem` packet when an item is collected. +#[fecs::event_handler] +pub fn on_item_collect_broadcast(event: &ItemCollectEvent, game: &Game, world: &mut World) { + let packet = CollectItem { + collected: world.get::<NetworkId>(event.item).0, + collector: world.get::<NetworkId>(event.collector).0, + count: event.amount as i32, + }; + + game.broadcast_entity_update(world, packet, event.item, None); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::item; + use feather_core::items::{Item, ItemStack}; + use feather_core::util::Position; + use feather_test_framework::Test; + + #[test] + fn broadcast_item_collect() { + let mut test = Test::new(); + + let stack = ItemStack::new(Item::Anvil, 2); + let item = test.entity(item::create(stack, Default::default()).with(Position::default())); + let (packet, player) = test.broadcast_routine::<CollectItem, _, _, _>( + |_test, player1, _player2| ItemCollectEvent { + item, + collector: player1, + amount: 1, + }, + on_item_collect_broadcast, + true, + ); + + assert_eq!(packet.collector, test.id(player)); + assert_eq!(packet.collected, test.id(item)); + assert_eq!(packet.count, 1); + } +} diff --git a/feather/old/server/entity/src/broadcasters/metadata.rs b/feather/old/server/entity/src/broadcasters/metadata.rs new file mode 100644 index 000000000..4b19d6dfd --- /dev/null +++ b/feather/old/server/entity/src/broadcasters/metadata.rs @@ -0,0 +1,60 @@ +//! Sending of entity metadata. + +use feather_core::entitymeta::EntityMetadata; +use feather_core::network::packets::PacketEntityMetadata; +use feather_server_types::{EntitySendEvent, Network, NetworkId}; +use fecs::World; + +/// System which sends entity metadata when an entity +/// is sent to a player. +#[fecs::event_handler] +pub fn on_entity_send_send_metadata(event: &EntitySendEvent, world: &mut World) { + if let Some(metadata) = world.try_get::<EntityMetadata>(event.entity) { + if let Some(network) = world.try_get::<Network>(event.client) { + let entity_id = world.get::<NetworkId>(event.entity).0; + let packet = PacketEntityMetadata { + entity_id, + metadata: (&*metadata).clone(), + }; + network.send(packet); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::item; + use feather_core::entitymeta::{MetaEntry, META_INDEX_ITEM_SLOT}; + use feather_core::items::{Item, ItemStack}; + use feather_core::util::Position; + use feather_test_framework::Test; + + #[test] + fn send_metadata() { + let mut test = Test::new(); + + let player1 = test.player("", position!(0.0, 64.0, 0.0)); + let player2 = test.player("", position!(0.0, 100.0, 0.0)); + + let stack = ItemStack::new(Item::String, 4); + let item = test.entity(item::create(stack, Default::default()).with(Position::default())); + + test.handle( + EntitySendEvent { + client: player1, + entity: item, + }, + on_entity_send_send_metadata, + ); + + let packet = test.sent::<PacketEntityMetadata>(player1).unwrap(); + assert_eq!(packet.entity_id, test.id(item)); + assert_eq!( + packet.metadata.get(META_INDEX_ITEM_SLOT), + Some(MetaEntry::Slot(Some(stack))) + ); + + assert!(test.sent::<PacketEntityMetadata>(player2).is_none()); + } +} diff --git a/feather/old/server/entity/src/broadcasters/movement.rs b/feather/old/server/entity/src/broadcasters/movement.rs new file mode 100644 index 000000000..6fb7c405b --- /dev/null +++ b/feather/old/server/entity/src/broadcasters/movement.rs @@ -0,0 +1,218 @@ +//! Broadcasting of movement updates. + +use feather_core::network::packets::{ + EntityHeadLook, EntityLook, EntityLookAndRelativeMove, EntityRelativeMove, EntityTeleport, + EntityVelocity, +}; +use feather_core::network::Packet; +use feather_core::util::Position; +use feather_server_types::{ + EntityClientRemoveEvent, EntitySendEvent, Game, LastKnownPositions, Network, NetworkId, + PreviousPosition, PreviousVelocity, Velocity, +}; +use feather_server_util::{calculate_relative_move, degrees_to_stops, protocol_velocity}; +use fecs::{IntoQuery, Read, World}; +use smallvec::SmallVec; +use std::ops::Deref; + +/// System to broadcast when an entity moves. +#[fecs::system] +pub fn broadcast_movement(game: &mut Game, world: &mut World) { + <(Read<Position>, Read<PreviousPosition>, Read<NetworkId>)>::query().par_entities_for_each( + world.inner(), + |(entity, (pos, prev_pos, id))| { + let pos: Position = *pos; + + let prev_pos = match prev_pos.0 { + Some(prev_pos) => prev_pos, + None => return, + }; + + if pos == prev_pos { + return; + } + + let entity_id = id.0; + + let chunk = pos.chunk(); + let players = game.chunk_holders.holders_for(chunk); + + for player in players.iter().filter(|player| **player != entity) { + if let Some(network) = world.try_get::<Network>(*player) { + let last_known_positions = world.get::<LastKnownPositions>(*player); + let last_known_positions = last_known_positions.deref(); + + if let Some(mut last_known_pos) = last_known_positions.0.get_mut(&entity) { + for packet in + packets_for_movement_update(entity_id, *last_known_pos.value(), pos) + { + network.send_boxed(packet); + } + + log::trace!("Updated position of {:?} on client {:?}", entity, player); + + *last_known_pos.value_mut() = pos; + } else { + log::trace!( + "Missing last position entry for {:?} on client {:?}", + entity, + player + ); + }; + } + } + }, + ); +} + +#[fecs::event_handler] +pub fn on_entity_send_update_last_known_positions(event: &EntitySendEvent, world: &mut World) { + if let Some(last_known_positions) = world.try_get::<LastKnownPositions>(event.client) { + let pos = *world.get::<Position>(event.entity); + last_known_positions.0.insert(event.entity, pos); + log::trace!( + "Inserted last position entry for {:?} (player: {:?})", + event.entity, + event.client + ); + } +} + +#[fecs::event_handler] +pub fn on_entity_client_remove_update_last_known_positions( + event: &EntityClientRemoveEvent, + world: &mut World, +) { + if let Some(last_known_positions) = world.try_get::<LastKnownPositions>(event.client) { + log::trace!( + "Removing last position entry for {:?} (player: {:?})", + event.entity, + event.client + ); + last_known_positions.0.remove(&event.entity); + } +} + +/// Broadcasts an entity's velocity. +#[fecs::system] +pub fn broadcast_velocity(world: &mut World, game: &mut Game) { + <(Read<Velocity>, Read<PreviousVelocity>, Read<NetworkId>)>::query().par_entities_for_each( + world.inner(), + |(entity, (vel, prev_vel, entity_id))| { + let entity_id = entity_id.0; + + let prev_vel = match prev_vel.0 { + Some(prev_vel) => prev_vel, + None => return, + }; + + if vel.0 == prev_vel { + return; + } + + let (velocity_x, velocity_y, velocity_z) = protocol_velocity(vel.0); + + if velocity_x == 0 && velocity_y == 0 && velocity_z == 0 { + return; + } + + let packet = EntityVelocity { + entity_id, + velocity_x, + velocity_y, + velocity_z, + }; + game.broadcast_entity_update(world, packet, entity, None); + }, + ); +} + +/// Returns the packet needed to notify a client +/// of a position update, from the old position to the new one. +#[allow(clippy::float_cmp)] +fn packets_for_movement_update( + entity_id: i32, + old_pos: Position, + new_pos: Position, +) -> SmallVec<[Box<dyn Packet>; 2]> { + if old_pos == new_pos { + return SmallVec::new(); + } + + let mut packets = SmallVec::new(); + + let has_moved = old_pos.x != new_pos.x || old_pos.y != new_pos.y || old_pos.z != new_pos.z; + let has_looked = old_pos.pitch != new_pos.pitch + || old_pos.yaw != new_pos.yaw + || old_pos.on_ground != new_pos.on_ground; + + if has_moved { + let dist = old_pos.distance_squared_to(new_pos); + if dist > 64.0 { + // Entity Teleport + let packet: Box<dyn Packet> = Box::new(EntityTeleport { + entity_id, + x: new_pos.x, + y: new_pos.y, + z: new_pos.z, + yaw: degrees_to_stops(new_pos.yaw), + pitch: degrees_to_stops(new_pos.pitch), + on_ground: new_pos.on_ground, + }); + packets.push(packet); + } else { + // Relative movement packets + let (rx, ry, rz) = calculate_relative_move(old_pos, new_pos); + + if (rx == 0 && ry == 0 && rz == 0) && !has_looked { + // Because of floating point errors, + // the physics system may trigger an + // event when the distance moved is minuscule, + // which causes jittering on the client. + // Don't send the packet if it has no effect. + return SmallVec::new(); + } + + if has_looked { + let packet: Box<dyn Packet> = Box::new(EntityLookAndRelativeMove { + entity_id, + delta_x: rx, + delta_y: ry, + delta_z: rz, + yaw: degrees_to_stops(new_pos.yaw), + pitch: degrees_to_stops(new_pos.pitch), + on_ground: new_pos.on_ground, + }); + packets.push(packet); + } else { + let packet: Box<dyn Packet> = Box::new(EntityRelativeMove { + entity_id, + delta_x: rx, + delta_y: ry, + delta_z: rz, + on_ground: new_pos.on_ground, + }); + packets.push(packet); + } + } + } else { + let packet: Box<dyn Packet> = Box::new(EntityLook { + entity_id, + yaw: degrees_to_stops(new_pos.yaw), + pitch: degrees_to_stops(new_pos.pitch), + on_ground: new_pos.on_ground, + }); + packets.push(packet); + } + + // Entity Head Look also needs to be sent if the entity turned its head + if has_looked { + let packet: Box<dyn Packet> = Box::new(EntityHeadLook { + entity_id, + head_yaw: degrees_to_stops(new_pos.yaw), + }); + packets.push(packet); + } + + packets +} diff --git a/feather/old/server/entity/src/drops.rs b/feather/old/server/entity/src/drops.rs new file mode 100644 index 000000000..f7fecfd94 --- /dev/null +++ b/feather/old/server/entity/src/drops.rs @@ -0,0 +1,90 @@ +use crate::{item, InventoryExt}; +use feather_core::items::ItemStack; +use feather_core::loot::{loot_table, Conditions}; +use feather_core::util::Position; +use feather_server_types::{ + BlockUpdateEvent, CanInstaBreak, EntitySpawnEvent, Game, Inventory, Velocity, TPS, +}; +use fecs::{Entity, World}; +use rand::Rng; + +/// When a block is broken with valid conditions, +/// yields items from the block's loot table. +#[fecs::event_handler] +pub fn on_block_break_drop_loot(event: &BlockUpdateEvent, game: &mut Game, world: &mut World) { + if event.old.is_air() || !event.new.is_air() { + return; + } + + let item = match event.cause { + feather_server_types::BlockUpdateCause::Entity(entity) => { + // If broken by a player who can insta-break, don't drop loot. + if world.has::<CanInstaBreak>(entity) { + return; + } + + let item = world + .try_get::<Inventory>(entity) + .map(|inv| inv.item_in_main_hand(entity, world)) + .flatten(); + + // If the block was not broken with the correct tool, don't drop loot. + if event.old.kind().best_tool_required() { + let tool_used = item.map(|item| item.ty.tool()).flatten(); + + let best_tool = event.old.kind().best_tool(); + + if tool_used != best_tool { + return; + } + } + + item + } + feather_server_types::BlockUpdateCause::Unsupported => None, + _ => return, + }; + + if let Some(loot_table) = loot_table(&format!("blocks/{}", &event.old.identifier()[10..])) { + let conditions = Conditions { item }; + let items = loot_table + .sample(&mut *game.rng(), &conditions) + .unwrap_or_else(|e| { + log::error!( + "Error sampling from loot table `{}`: {:?}", + event.old.identifier(), + e + ); + Default::default() + }); + + for item in items { + drop_item(game, world, item, event.pos.position()); + } + } +} + +/// "Naturally" drops an item caused by e.g. a broken block or a dead entity. +pub fn drop_item(game: &mut Game, world: &mut World, item: ItemStack, pos: Position) -> Entity { + // Compute velocity. Based on Glowstone's implementation of `World#dropItemNaturally()`. + let mut rng = game.rng(); + + let radius = 0.05f64; + let offset_x = rng.gen_range(0.0f64, radius * 2.0) - radius; + let offset_y = 0.15; + let mut offset_z = (radius.powi(2) - offset_x.powi(2)).sqrt(); + + if rng.gen() { + offset_z *= -1.0; + } + + let entity = item::create(item, game.tick_count + TPS) + .with(pos) + .with(Velocity(glm::vec3(offset_x, offset_y, offset_z))) + .build() + .spawn_in(world); + drop(rng); + game.handle(world, EntitySpawnEvent { entity }); + + entity +} diff --git a/feather/old/server/entity/src/fall_damage.rs b/feather/old/server/entity/src/fall_damage.rs new file mode 100644 index 000000000..3dfe89fbe --- /dev/null +++ b/feather/old/server/entity/src/fall_damage.rs @@ -0,0 +1,56 @@ +//! Handles fall damage for entities + +use feather_core::util::Position; +use feather_server_types::{ + BlocksFallen, BumpVec, CanTakeDamage, Dead, Game, Health, PreviousPosition, +}; +use fecs::{component, Entity, IntoQuery, Read, World, Write}; +use std::cell::RefCell; + +/// System which updates `BlocksFallen` for all entities. +#[fecs::system] +pub fn update_blocks_fallen(game: &mut Game, world: &mut World) { + // Entities who went from !on_ground => on_ground + + // (Legion for_each closures are not FnMuts; no idea why.) + let landed = RefCell::new(BumpVec::<Entity>::new_in(game.bump())); + + // TODO: use parallel iterator (blocked on allocator API) + // (BumpVec isn't Send.) + <(Read<Position>, Read<PreviousPosition>, Write<BlocksFallen>)>::query() + .filter(component::<Health>()) + .filter(component::<CanTakeDamage>()) + .filter(!component::<Dead>()) + .for_each_entities_mut( + world.inner_mut(), + |(entity, (pos, prev_pos, mut blocks_fallen))| { + match (prev_pos.0.map(|pos| pos.on_ground), pos.on_ground) { + (Some(false), false) => { + // In air: update blocks_fallen + blocks_fallen.0 += (prev_pos.0.unwrap().y - pos.y).max(0.0); + } + (Some(true), false) => { + // reset blocks_fallen + blocks_fallen.0 = 0.0; + } + (Some(false), true) => { + // landed + landed.borrow_mut().push(entity); + } + _ => (), + } + }, + ); + + // Damage landed entities + for entity in landed.into_inner() { + let blocks_fallen = world.get::<BlocksFallen>(entity).0; + + // https://minecraft.gamepedia.com/Damage#Fall_damage + let damage = (blocks_fallen - 3.0).max(0.0).round() as u32; + + if damage != 0 { + game.damage(entity, damage, world); + } + } +} diff --git a/feather/old/server/entity/src/inventory.rs b/feather/old/server/entity/src/inventory.rs new file mode 100644 index 000000000..bbcb705e6 --- /dev/null +++ b/feather/old/server/entity/src/inventory.rs @@ -0,0 +1,63 @@ +use feather_core::inventory::{slot, Area, SlotIndex}; +use feather_core::items::ItemStack; +use feather_server_types::{HeldItem, Inventory}; +use fecs::{Entity, World}; +use num_derive::{FromPrimitive, ToPrimitive}; + +pub trait InventoryExt { + /// Returns the item in the main hand of this entity. + fn item_in_main_hand(&self, entity: Entity, world: &World) -> Option<ItemStack>; +} + +impl InventoryExt for Inventory { + fn item_in_main_hand(&self, entity: Entity, world: &World) -> Option<ItemStack> { + let held_item = world.get::<HeldItem>(entity).0; + self.item_at(Area::Hotbar, held_item).unwrap() + } +} + +/// An equipment slot, with variants +/// listed in the order of the Entity Equipment +/// IDs to allow for easy conversion using `ToPrimitive`/`FromPrimitive`. +#[derive(Debug, Clone, Copy, ToPrimitive, FromPrimitive, PartialEq, Eq, Hash)] +pub enum Equipment { + MainHand, + OffHand, + Boots, + Leggings, + Chestplate, + Helmet, +} + +impl Equipment { + pub fn from_slot_index(index: SlotIndex, held_item: usize) -> Option<Self> { + use feather_core::inventory::Area::*; + match index.area { + Offhand => Some(Equipment::OffHand), + Feet => Some(Equipment::Boots), + Legs => Some(Equipment::Leggings), + Torso => Some(Equipment::Chestplate), + Head => Some(Equipment::Helmet), + Hotbar => { + if index.slot == held_item { + Some(Equipment::MainHand) + } else { + None + } + } + _ => None, + } + } + + pub fn slot_index(self, held_item: usize) -> SlotIndex { + use feather_core::inventory::Area::*; + match self { + Equipment::MainHand => slot(Hotbar, held_item), + Equipment::OffHand => slot(Offhand, 0), + Equipment::Boots => slot(Feet, 0), + Equipment::Leggings => slot(Legs, 0), + Equipment::Chestplate => slot(Torso, 0), + Equipment::Helmet => slot(Head, 0), + } + } +} diff --git a/feather/old/server/entity/src/lib.rs b/feather/old/server/entity/src/lib.rs new file mode 100644 index 000000000..e33788b0c --- /dev/null +++ b/feather/old/server/entity/src/lib.rs @@ -0,0 +1,80 @@ +//! Dealing with entities, including associated components and events. +//! Submodules here are implementations of specific entities, such as items, +//! block entities, monsters, etc. Player entities are handled in `crate::player`, +//! not here. + +#[macro_use] +extern crate feather_core; + +mod broadcasters; +pub mod drops; +mod fall_damage; +mod inventory; +mod mob; +mod object; +pub mod particle; + +pub use self::inventory::InventoryExt; +pub use broadcasters::*; +pub use drops::on_block_break_drop_loot; +pub use fall_damage::update_blocks_fallen; +pub use mob::*; +pub use object::falling_block::{on_entity_land_remove_falling_block, spawn_falling_blocks}; +pub use object::item::{item_collect, on_item_drop_spawn_item_entity}; +pub use object::*; + +extern crate nalgebra_glm as glm; + +use feather_core::util::Position; +use feather_server_types::{ + ChunkCrossEvent, Game, NetworkId, PreviousPosition, PreviousVelocity, Velocity, +}; +use fecs::{EntityBuilder, IntoQuery, Read, World, Write}; +use std::sync::atomic::{AtomicI32, Ordering}; + +/// Entity ID counter, used to create new entity IDs. +pub static ENTITY_ID_COUNTER: AtomicI32 = AtomicI32::new(0); + +#[fecs::system] +pub fn previous_position_velocity_reset(world: &mut World) { + <(Read<Position>, Write<PreviousPosition>)>::query().par_for_each_mut( + world.inner_mut(), + |(pos, mut previous_pos)| { + previous_pos.0.replace(*pos); + }, + ); + <(Read<Velocity>, Write<PreviousVelocity>)>::query().par_for_each_mut( + world.inner_mut(), + |(vel, mut previous_vel)| { + previous_vel.0.replace(vel.0); + }, + ); +} + +#[fecs::event_handler] +pub fn on_chunk_cross_mark_modified(event: &ChunkCrossEvent, game: &mut Game) { + if let Some(pos) = event.old { + if let Some(mut old_chunk) = game.chunk_map.chunk_at_mut(pos) { + old_chunk.set_modified() + } + } +} + +/// Inserts the base components for an entity into an `EntityBuilder`. +/// +/// This currently includes: +/// * Velocity (0) and PreviousVelocity +/// * Entity ID for the protocol +pub fn base() -> EntityBuilder { + let id = new_id(); + EntityBuilder::new() + .with(NetworkId(id)) + .with(Velocity::default()) + .with(PreviousVelocity::default()) + .with(PreviousPosition::default()) +} + +/// Returns a new entity ID. +pub fn new_id() -> i32 { + ENTITY_ID_COUNTER.fetch_add(1, Ordering::Relaxed) +} diff --git a/feather/old/server/entity/src/mob.rs b/feather/old/server/entity/src/mob.rs new file mode 100644 index 000000000..ee31f4fd5 --- /dev/null +++ b/feather/old/server/entity/src/mob.rs @@ -0,0 +1,134 @@ +//! Components and functionality shared across all mobs. + +mod boss; +mod defensive; +mod hostile; +mod neutral; +mod passive; + +pub use boss::*; +pub use defensive::*; +use feather_core::entitymeta::EntityMetadata; +use feather_core::network::packets::SpawnMob; +use feather_core::network::Packet; +use feather_core::util::Position; +use feather_server_types::{NetworkId, SpawnPacketCreator, Uuid, Velocity}; +use feather_server_util::{degrees_to_stops, protocol_velocity}; +use fecs::{EntityBuilder, EntityRef}; +pub use hostile::*; +pub use neutral::*; +pub use passive::*; + +/// Enumeration of mob types. Note that this enum should not be +/// used in queries to identify mobs of a given type. +/// +/// This is _not_ a component. It is only used for utility +/// functions such as `mob::spawn_packet_creator`. +/// +/// https://wiki.vg/Entity_metadata#Mobs +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(i32)] +pub enum MobKind { + Bat = 3, + Blaze = 4, + CaveSpider = 6, + Chicken = 7, + Cod = 8, + Cow = 9, + Creeper = 10, + Donkey = 11, + Dolphin = 12, + Drowned = 14, + ElderGuardian = 15, + EnderDragon = 16, + Enderman = 18, + Endermite = 19, + EvocationIllager = 21, + Ghast = 26, + Giant = 27, + Guardian = 28, + Horse = 29, + Husk = 30, + IllusionIllager = 31, + Llama = 36, + MagmaCube = 38, + Mule = 46, + MushroomCow = 47, + Ocelot = 48, + Parrot = 50, + Pig = 51, + Pufferfish = 52, + PigZombie = 53, + PolarBear = 54, + Rabbit = 56, + Salmon = 57, + Sheep = 58, + Shulker = 59, + Silverfish = 61, + Skeleton = 62, + SkeletonHorse = 63, + Slime = 64, + SnowGolem = 66, + Spider = 69, + Squid = 70, + Stray = 71, + TropicalFish = 72, + Turtle = 73, + Vex = 78, + Villager = 79, + IronGolem = 80, + VindicationIllager = 81, + Witch = 82, + Wither = 83, + WitherSkeleton = 84, + Wolf = 86, + Zombie = 87, + ZombieHorse = 88, + ZombieVillager = 89, + Phantom = 90, +} + +/// Returns the base components for a mob with the given +/// kind. +pub fn base(kind: MobKind) -> EntityBuilder { + super::base().with(spawn_packet_creator(kind)) +} + +/// Returns a `SpawnPacketCreator` for a mob with the given kind. +pub fn spawn_packet_creator(kind: MobKind) -> SpawnPacketCreator { + let f = Box::new(move |accessor: &EntityRef| { + let entity_id = accessor.get::<NetworkId>().0; + let uuid = accessor + .try_get::<Uuid>() + .map(|r| *r) + .unwrap_or_else(Uuid::new_v4); + + let position = *accessor.get::<Position>(); + let velocity = *accessor.get::<Velocity>(); + let meta = accessor + .try_get::<EntityMetadata>() + .map(|meta| (&*meta).clone()) + .unwrap_or_else(EntityMetadata::entity_base); + + let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocity.0); + + let res: Box<dyn Packet> = Box::new(SpawnMob { + entity_id, + entity_uuid: uuid, + ty: kind as i32, + x: position.x, + y: position.y, + z: position.z, + yaw: degrees_to_stops(position.yaw), + pitch: degrees_to_stops(position.pitch), + head_pitch: 0, // todo + velocity_x, + velocity_y, + velocity_z, + meta, + }); + res + }); + + SpawnPacketCreator(Box::leak(f)) +} diff --git a/feather/old/server/entity/src/mob/boss.rs b/feather/old/server/entity/src/mob/boss.rs new file mode 100644 index 000000000..3adebbbe3 --- /dev/null +++ b/feather/old/server/entity/src/mob/boss.rs @@ -0,0 +1,2 @@ +pub mod ender_dragon; +pub mod wither; diff --git a/feather/old/server/entity/src/mob/boss/ender_dragon.rs b/feather/old/server/entity/src/mob/boss/ender_dragon.rs new file mode 100644 index 000000000..33355695e --- /dev/null +++ b/feather/old/server/entity/src/mob/boss/ender_dragon.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct EnderDragon; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::EnderDragon).with(EnderDragon) +} diff --git a/feather/old/server/entity/src/mob/boss/wither.rs b/feather/old/server/entity/src/mob/boss/wither.rs new file mode 100644 index 000000000..7005fed6c --- /dev/null +++ b/feather/old/server/entity/src/mob/boss/wither.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Wither; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Wither).with(Wither) +} diff --git a/feather/old/server/entity/src/mob/defensive.rs b/feather/old/server/entity/src/mob/defensive.rs new file mode 100644 index 000000000..66354d1fa --- /dev/null +++ b/feather/old/server/entity/src/mob/defensive.rs @@ -0,0 +1 @@ +pub mod pufferfish; diff --git a/feather/old/server/entity/src/mob/defensive/pufferfish.rs b/feather/old/server/entity/src/mob/defensive/pufferfish.rs new file mode 100644 index 000000000..bee2f1644 --- /dev/null +++ b/feather/old/server/entity/src/mob/defensive/pufferfish.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Pufferfish; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Pufferfish).with(Pufferfish) +} diff --git a/feather/old/server/entity/src/mob/hostile.rs b/feather/old/server/entity/src/mob/hostile.rs new file mode 100644 index 000000000..bf4aa054f --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile.rs @@ -0,0 +1,22 @@ +pub mod blaze; +pub mod creeper; +pub mod drowned; +pub mod elder_guardian; +pub mod endermite; +pub mod evoker; +pub mod ghast; +pub mod guardian; +pub mod husk; +pub mod magma_cube; +pub mod phantom; +pub mod shulker; +pub mod silverfish; +pub mod skeleton; +pub mod slime; +pub mod stray; +pub mod vex; +pub mod vindicator; +pub mod witch; +pub mod wither_skeleton; +pub mod zombie; +pub mod zombie_villager; diff --git a/feather/old/server/entity/src/mob/hostile/blaze.rs b/feather/old/server/entity/src/mob/hostile/blaze.rs new file mode 100644 index 000000000..ace2fd6af --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/blaze.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Blaze; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Blaze).with(Blaze) +} diff --git a/feather/old/server/entity/src/mob/hostile/creeper.rs b/feather/old/server/entity/src/mob/hostile/creeper.rs new file mode 100644 index 000000000..19d1ecd64 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/creeper.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Creeper; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Creeper).with(Creeper) +} diff --git a/feather/old/server/entity/src/mob/hostile/drowned.rs b/feather/old/server/entity/src/mob/hostile/drowned.rs new file mode 100644 index 000000000..fbfebb796 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/drowned.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Drowned; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Drowned).with(Drowned) +} diff --git a/feather/old/server/entity/src/mob/hostile/elder_guardian.rs b/feather/old/server/entity/src/mob/hostile/elder_guardian.rs new file mode 100644 index 000000000..f0df7f270 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/elder_guardian.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct ElderGuardian; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::ElderGuardian).with(ElderGuardian) +} diff --git a/feather/old/server/entity/src/mob/hostile/endermite.rs b/feather/old/server/entity/src/mob/hostile/endermite.rs new file mode 100644 index 000000000..f375ceea6 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/endermite.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Endermite; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Endermite).with(Endermite) +} diff --git a/feather/old/server/entity/src/mob/hostile/evoker.rs b/feather/old/server/entity/src/mob/hostile/evoker.rs new file mode 100644 index 000000000..2919f44bf --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/evoker.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Evoker; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::EvocationIllager).with(Evoker) +} diff --git a/feather/old/server/entity/src/mob/hostile/ghast.rs b/feather/old/server/entity/src/mob/hostile/ghast.rs new file mode 100644 index 000000000..a1d6d5ee7 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/ghast.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Ghast; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Ghast).with(Ghast) +} diff --git a/feather/old/server/entity/src/mob/hostile/guardian.rs b/feather/old/server/entity/src/mob/hostile/guardian.rs new file mode 100644 index 000000000..aa4640901 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/guardian.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Guardian; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Guardian).with(Guardian) +} diff --git a/feather/old/server/entity/src/mob/hostile/husk.rs b/feather/old/server/entity/src/mob/hostile/husk.rs new file mode 100644 index 000000000..5bc49a416 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/husk.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Husk; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Husk).with(Husk) +} diff --git a/feather/old/server/entity/src/mob/hostile/magma_cube.rs b/feather/old/server/entity/src/mob/hostile/magma_cube.rs new file mode 100644 index 000000000..e57021994 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/magma_cube.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct MagmaCube; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::MagmaCube).with(MagmaCube) +} diff --git a/feather/old/server/entity/src/mob/hostile/phantom.rs b/feather/old/server/entity/src/mob/hostile/phantom.rs new file mode 100644 index 000000000..e8945fccc --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/phantom.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Phantom; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Phantom).with(Phantom) +} diff --git a/feather/old/server/entity/src/mob/hostile/shulker.rs b/feather/old/server/entity/src/mob/hostile/shulker.rs new file mode 100644 index 000000000..4e93523ad --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/shulker.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Shulker; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Shulker).with(Shulker) +} diff --git a/feather/old/server/entity/src/mob/hostile/silverfish.rs b/feather/old/server/entity/src/mob/hostile/silverfish.rs new file mode 100644 index 000000000..ffc9d07d6 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/silverfish.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Silverfish; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Silverfish).with(Silverfish) +} diff --git a/feather/old/server/entity/src/mob/hostile/skeleton.rs b/feather/old/server/entity/src/mob/hostile/skeleton.rs new file mode 100644 index 000000000..53fc1a7e2 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/skeleton.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Skeleton; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Skeleton).with(Skeleton) +} diff --git a/feather/old/server/entity/src/mob/hostile/slime.rs b/feather/old/server/entity/src/mob/hostile/slime.rs new file mode 100644 index 000000000..785a173ee --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/slime.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Slime; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Slime).with(Slime) +} diff --git a/feather/old/server/entity/src/mob/hostile/stray.rs b/feather/old/server/entity/src/mob/hostile/stray.rs new file mode 100644 index 000000000..f4fcd8e90 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/stray.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Stray; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Stray).with(Stray) +} diff --git a/feather/old/server/entity/src/mob/hostile/vex.rs b/feather/old/server/entity/src/mob/hostile/vex.rs new file mode 100644 index 000000000..df0c539eb --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/vex.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Vex; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Vex).with(Vex) +} diff --git a/feather/old/server/entity/src/mob/hostile/vindicator.rs b/feather/old/server/entity/src/mob/hostile/vindicator.rs new file mode 100644 index 000000000..2d1e9871e --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/vindicator.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Vindicator; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::VindicationIllager).with(Vindicator) +} diff --git a/feather/old/server/entity/src/mob/hostile/witch.rs b/feather/old/server/entity/src/mob/hostile/witch.rs new file mode 100644 index 000000000..e31487a81 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/witch.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Witch; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Witch).with(Witch) +} diff --git a/feather/old/server/entity/src/mob/hostile/wither_skeleton.rs b/feather/old/server/entity/src/mob/hostile/wither_skeleton.rs new file mode 100644 index 000000000..d8efda82a --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/wither_skeleton.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct WitherSkeleton; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::WitherSkeleton).with(WitherSkeleton) +} diff --git a/feather/old/server/entity/src/mob/hostile/zombie.rs b/feather/old/server/entity/src/mob/hostile/zombie.rs new file mode 100644 index 000000000..9e14f4d49 --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/zombie.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Zombie; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Zombie).with(Zombie) +} diff --git a/feather/old/server/entity/src/mob/hostile/zombie_villager.rs b/feather/old/server/entity/src/mob/hostile/zombie_villager.rs new file mode 100644 index 000000000..28b26e81b --- /dev/null +++ b/feather/old/server/entity/src/mob/hostile/zombie_villager.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct ZombieVillager; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::ZombieVillager).with(ZombieVillager) +} diff --git a/feather/old/server/entity/src/mob/neutral.rs b/feather/old/server/entity/src/mob/neutral.rs new file mode 100644 index 000000000..f2caabe4b --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral.rs @@ -0,0 +1,9 @@ +pub mod cave_spider; +pub mod dolphin; +pub mod enderman; +pub mod iron_golem; +pub mod llama; +pub mod polar_bear; +pub mod spider; +pub mod wolf; +pub mod zombie_pigman; diff --git a/feather/old/server/entity/src/mob/neutral/cave_spider.rs b/feather/old/server/entity/src/mob/neutral/cave_spider.rs new file mode 100644 index 000000000..241110b9a --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/cave_spider.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct CaveSpider; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::CaveSpider).with(CaveSpider) +} diff --git a/feather/old/server/entity/src/mob/neutral/dolphin.rs b/feather/old/server/entity/src/mob/neutral/dolphin.rs new file mode 100644 index 000000000..baf2e6eee --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/dolphin.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Dolphin; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Dolphin).with(Dolphin) +} diff --git a/feather/old/server/entity/src/mob/neutral/enderman.rs b/feather/old/server/entity/src/mob/neutral/enderman.rs new file mode 100644 index 000000000..4b1967b9e --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/enderman.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Enderman; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Enderman).with(Enderman) +} diff --git a/feather/old/server/entity/src/mob/neutral/iron_golem.rs b/feather/old/server/entity/src/mob/neutral/iron_golem.rs new file mode 100644 index 000000000..fd3464bcb --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/iron_golem.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct IronGolem; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::IronGolem).with(IronGolem) +} diff --git a/feather/old/server/entity/src/mob/neutral/llama.rs b/feather/old/server/entity/src/mob/neutral/llama.rs new file mode 100644 index 000000000..e03649549 --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/llama.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Llama; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Llama).with(Llama) +} diff --git a/feather/old/server/entity/src/mob/neutral/polar_bear.rs b/feather/old/server/entity/src/mob/neutral/polar_bear.rs new file mode 100644 index 000000000..1e1c3c7de --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/polar_bear.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct PolarBear; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::PolarBear).with(PolarBear) +} diff --git a/feather/old/server/entity/src/mob/neutral/spider.rs b/feather/old/server/entity/src/mob/neutral/spider.rs new file mode 100644 index 000000000..051478aed --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/spider.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Spider; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Spider).with(Spider) +} diff --git a/feather/old/server/entity/src/mob/neutral/wolf.rs b/feather/old/server/entity/src/mob/neutral/wolf.rs new file mode 100644 index 000000000..68c05e59c --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/wolf.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Wolf; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Wolf).with(Wolf) +} diff --git a/feather/old/server/entity/src/mob/neutral/zombie_pigman.rs b/feather/old/server/entity/src/mob/neutral/zombie_pigman.rs new file mode 100644 index 000000000..41dd7194d --- /dev/null +++ b/feather/old/server/entity/src/mob/neutral/zombie_pigman.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct ZombiePigman; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::PigZombie).with(ZombiePigman) +} diff --git a/feather/old/server/entity/src/mob/passive.rs b/feather/old/server/entity/src/mob/passive.rs new file mode 100644 index 000000000..adc6aaf72 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive.rs @@ -0,0 +1,23 @@ +pub mod bat; +pub mod cat; +pub mod chicken; +pub mod cod; +pub mod cow; +pub mod donkey; +pub mod horse; +pub mod mooshroom; +pub mod mule; +pub mod ocelot; +pub mod parrot; +pub mod pig; +pub mod rabbit; +pub mod salmon; +pub mod sheep; +pub mod skeleton_horse; +pub mod snow_golem; +pub mod squid; +pub mod tropical_fish; +pub mod turtle; +pub mod villager; + +// Base components for all passive mobs. diff --git a/feather/old/server/entity/src/mob/passive/bat.rs b/feather/old/server/entity/src/mob/passive/bat.rs new file mode 100644 index 000000000..583aef249 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/bat.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Bat; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Bat).with(Bat) +} diff --git a/feather/old/server/entity/src/mob/passive/cat.rs b/feather/old/server/entity/src/mob/passive/cat.rs new file mode 100644 index 000000000..a2a0f0146 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/cat.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Cat; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Ocelot).with(Cat) +} diff --git a/feather/old/server/entity/src/mob/passive/chicken.rs b/feather/old/server/entity/src/mob/passive/chicken.rs new file mode 100644 index 000000000..27694ba12 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/chicken.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Chicken; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Chicken).with(Chicken) +} diff --git a/feather/old/server/entity/src/mob/passive/cod.rs b/feather/old/server/entity/src/mob/passive/cod.rs new file mode 100644 index 000000000..cd6f0aa7c --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/cod.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Cod; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Cod).with(Cod) +} diff --git a/feather/old/server/entity/src/mob/passive/cow.rs b/feather/old/server/entity/src/mob/passive/cow.rs new file mode 100644 index 000000000..0fbf9e4d9 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/cow.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Cow; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Cow).with(Cow) +} diff --git a/feather/old/server/entity/src/mob/passive/donkey.rs b/feather/old/server/entity/src/mob/passive/donkey.rs new file mode 100644 index 000000000..d05a24bf2 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/donkey.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Donkey; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Donkey).with(Donkey) +} diff --git a/feather/old/server/entity/src/mob/passive/horse.rs b/feather/old/server/entity/src/mob/passive/horse.rs new file mode 100644 index 000000000..c670782d2 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/horse.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Horse; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Horse).with(Horse) +} diff --git a/feather/old/server/entity/src/mob/passive/mooshroom.rs b/feather/old/server/entity/src/mob/passive/mooshroom.rs new file mode 100644 index 000000000..d5f7d7cc9 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/mooshroom.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Mooshroom; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::MushroomCow).with(Mooshroom) +} diff --git a/feather/old/server/entity/src/mob/passive/mule.rs b/feather/old/server/entity/src/mob/passive/mule.rs new file mode 100644 index 000000000..1eaa2b9fc --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/mule.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Mule; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Mule).with(Mule) +} diff --git a/feather/old/server/entity/src/mob/passive/ocelot.rs b/feather/old/server/entity/src/mob/passive/ocelot.rs new file mode 100644 index 000000000..d867b8af9 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/ocelot.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Ocelot; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Ocelot).with(Ocelot) +} diff --git a/feather/old/server/entity/src/mob/passive/parrot.rs b/feather/old/server/entity/src/mob/passive/parrot.rs new file mode 100644 index 000000000..a6f7f368b --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/parrot.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Parrot; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Parrot).with(Parrot) +} diff --git a/feather/old/server/entity/src/mob/passive/pig.rs b/feather/old/server/entity/src/mob/passive/pig.rs new file mode 100644 index 000000000..680c13b0a --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/pig.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Pig; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Pig).with(Pig) +} diff --git a/feather/old/server/entity/src/mob/passive/rabbit.rs b/feather/old/server/entity/src/mob/passive/rabbit.rs new file mode 100644 index 000000000..a6e6852c6 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/rabbit.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Rabbit; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Rabbit).with(Rabbit) +} diff --git a/feather/old/server/entity/src/mob/passive/salmon.rs b/feather/old/server/entity/src/mob/passive/salmon.rs new file mode 100644 index 000000000..89f94d7d2 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/salmon.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Salmon; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Salmon).with(Salmon) +} diff --git a/feather/old/server/entity/src/mob/passive/sheep.rs b/feather/old/server/entity/src/mob/passive/sheep.rs new file mode 100644 index 000000000..47a12f385 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/sheep.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Sheep; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Sheep).with(Sheep) +} diff --git a/feather/old/server/entity/src/mob/passive/skeleton_horse.rs b/feather/old/server/entity/src/mob/passive/skeleton_horse.rs new file mode 100644 index 000000000..fa36c0e02 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/skeleton_horse.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct SkeletonHorse; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Horse).with(SkeletonHorse) +} diff --git a/feather/old/server/entity/src/mob/passive/snow_golem.rs b/feather/old/server/entity/src/mob/passive/snow_golem.rs new file mode 100644 index 000000000..c7c6ab065 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/snow_golem.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct SnowGolem; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::SnowGolem).with(SnowGolem) +} diff --git a/feather/old/server/entity/src/mob/passive/squid.rs b/feather/old/server/entity/src/mob/passive/squid.rs new file mode 100644 index 000000000..ec83849c9 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/squid.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Squid; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Squid).with(Squid) +} diff --git a/feather/old/server/entity/src/mob/passive/tropical_fish.rs b/feather/old/server/entity/src/mob/passive/tropical_fish.rs new file mode 100644 index 000000000..4a60dc677 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/tropical_fish.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct TropicalFish; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::TropicalFish).with(TropicalFish) +} diff --git a/feather/old/server/entity/src/mob/passive/turtle.rs b/feather/old/server/entity/src/mob/passive/turtle.rs new file mode 100644 index 000000000..4296ec9a5 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/turtle.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Turtle; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Turtle).with(Turtle) +} diff --git a/feather/old/server/entity/src/mob/passive/villager.rs b/feather/old/server/entity/src/mob/passive/villager.rs new file mode 100644 index 000000000..56bcad4b6 --- /dev/null +++ b/feather/old/server/entity/src/mob/passive/villager.rs @@ -0,0 +1,8 @@ +use crate::{mob, MobKind}; +use fecs::EntityBuilder; + +pub struct Villager; + +pub fn create() -> EntityBuilder { + mob::base(MobKind::Villager).with(Villager) +} diff --git a/feather/old/server/entity/src/object.rs b/feather/old/server/entity/src/object.rs new file mode 100644 index 000000000..0d38dd1ce --- /dev/null +++ b/feather/old/server/entity/src/object.rs @@ -0,0 +1,4 @@ +pub mod arrow; +pub mod falling_block; +pub mod item; +pub mod supported_blocks; diff --git a/feather/old/server/entity/src/object/arrow.rs b/feather/old/server/entity/src/object/arrow.rs new file mode 100644 index 000000000..29661e87b --- /dev/null +++ b/feather/old/server/entity/src/object/arrow.rs @@ -0,0 +1,57 @@ +use feather_core::anvil::entity::{ArrowEntityData, BaseEntityData, EntityData}; +use feather_core::network::packets::SpawnObject; +use feather_core::network::Packet; +use feather_core::util::{Position, Vec3d}; +use feather_server_types::{ + ComponentSerializer, Game, NetworkId, PhysicsBuilder, SpawnPacketCreator, Uuid, Velocity, +}; +use feather_server_util::{degrees_to_stops, protocol_velocity}; +use fecs::{EntityBuilder, EntityRef}; + +pub fn create() -> EntityBuilder { + crate::base() + .with(SpawnPacketCreator(&create_spawn_packet)) + .with(ComponentSerializer(&serialize)) + .with( + PhysicsBuilder::new() + .bbox(0.5, 0.5, 0.5) + .gravity(-0.05) + .slip_multiplier(0.0) + .drag(0.99) + .build(), + ) +} + +fn create_spawn_packet(accessor: &EntityRef) -> Box<dyn Packet> { + let position = *accessor.get::<Position>(); + let velocity = *accessor.get::<Velocity>(); + let entity_id = accessor.get::<NetworkId>().0; + + let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocity.0); + + let packet = SpawnObject { + entity_id, + object_uuid: Uuid::new_v4(), + ty: 60, // Type 60 for arrow projectile + x: position.x, + y: position.y, + z: position.z, + pitch: degrees_to_stops(position.pitch), + yaw: degrees_to_stops(position.yaw), + data: entity_id + 1, + velocity_x, + velocity_y, + velocity_z, + }; + + Box::new(packet) +} + +fn serialize(_game: &Game, accessor: &EntityRef) -> EntityData { + let vel = accessor.get::<Velocity>().0; + + EntityData::Arrow(ArrowEntityData { + entity: BaseEntityData::new(*accessor.get::<Position>(), Vec3d::new(vel.x, vel.y, vel.z)), + critical: 0, // TODO + }) +} diff --git a/feather/old/server/entity/src/object/falling_block.rs b/feather/old/server/entity/src/object/falling_block.rs new file mode 100644 index 000000000..759c2ea6f --- /dev/null +++ b/feather/old/server/entity/src/object/falling_block.rs @@ -0,0 +1,183 @@ +//! Implements falling block entities: sand, gravel, etc. + +use crate::drops::drop_item; +use feather_core::blocks::{BlockId, BlockKind, SimplifiedBlockKind}; +use feather_core::entitymeta::{EntityMetadata, META_INDEX_FALLING_BLOCK_SPAWN_POSITION}; +use feather_core::item_block::BlockToItem; +use feather_core::items::ItemStack; +use feather_core::network::packets::{Effect, SpawnObject}; +use feather_core::network::Packet; +use feather_core::util::{BlockPosition, Position}; +use feather_server_types::{ + BlockUpdateCause, BumpVec, EntityLandEvent, EntitySpawnEvent, Game, NetworkId, PhysicsBuilder, + SpawnPacketCreator, Uuid, Velocity, +}; +use feather_server_util::{ + degrees_to_stops, protocol_velocity, BlockNotifyBlock, BlockNotifyFallingBlock, + BlockNotifyPosition, +}; +use fecs::{component, EntityBuilder, EntityRef, IntoQuery, Read, World}; + +/// Marker component indicating an entity is a falling block. +#[derive(Copy, Clone, Debug)] +pub struct FallingBlock; + +/// Component storing the block type for a falling block. +#[derive(Copy, Clone, Debug)] +pub struct FallingBlockType(pub BlockId); + +/// System to create a falling block when a block notify +/// entity is spawned with `BlockNotifyFallingBlock`. +#[fecs::system] +pub fn spawn_falling_blocks(game: &mut Game, world: &mut World) { + let mut actions = BumpVec::new_in(game.bump()); + + actions.extend( + <(Read<BlockNotifyBlock>, Read<BlockNotifyPosition>)>::query() + .filter(component::<BlockNotifyFallingBlock>()) + .iter_entities(world.inner()) + .map(|(entity, (block, position))| { + let builder = if game.block_at(position.0 - BlockPosition::new(0, 1, 0)) + == Some(BlockId::air()) + { + Some( + create(block.0, position.0) + .with(position.0.position() + position!(0.0, -0.5, 0.0)), + ) + } else { + None + }; + + (entity, builder, position.0) + }), + ); + + for (entity_to_delete, entity_builder, block_to_clear) in actions { + world.despawn(entity_to_delete); + + if let Some(entity_builder) = entity_builder { + let created_entity = entity_builder.build().spawn_in(world); + game.handle( + world, + EntitySpawnEvent { + entity: created_entity, + }, + ); + + game.set_block_at( + world, + block_to_clear, + BlockId::air(), + BlockUpdateCause::Unknown, + ); + } + } +} + +/// When a falling block lands on the ground, deletes +/// it and creates a solid block where it landed or +/// drops it on the ground if the block in the land position +/// is not solid. +#[fecs::event_handler] +pub fn on_entity_land_remove_falling_block( + event: &EntityLandEvent, + game: &mut Game, + world: &mut World, +) { + if let Some(block) = world + .try_get::<FallingBlockType>(event.entity) + .map(|block| block.0) + { + let pos = event.pos.block(); + if !drop_falling_block(pos, &block, game, world) { + game.set_block_at(world, pos, block, BlockUpdateCause::Unknown); + + if block.simplified_kind() == SimplifiedBlockKind::Anvil { + game.broadcast_chunk_update( + world, + Effect { + effect_id: 1031, // TODO remove hardcoded magic number + location: pos, + data: 0, + disable_relative_volume: false, + }, + event.pos.chunk(), + None, + ); + } + } + + game.despawn(event.entity, world); + } +} + +/// Drops falling block as item when the block on the ground +/// is not a solid block. +fn drop_falling_block( + pos: BlockPosition, + falling_block: &BlockId, + game: &mut Game, + world: &mut World, +) -> bool { + let item = falling_block.to_item(); + + let not_solid_block_kind = game + .block_at(pos) + .map(|block| block.kind()) + .filter(|kind| !kind.solid() && kind != &BlockKind::Air); + + if let Some(item) = item { + if not_solid_block_kind.is_some() { + drop_item(game, world, ItemStack::new(item, 1), pos.position()); + return true; + } + } + + false +} + +/// Returns an `EntityBuilder` for a falling block of the given type. +pub fn create(ty: BlockId, spawn_pos: BlockPosition) -> EntityBuilder { + let meta = + EntityMetadata::entity_base().with(META_INDEX_FALLING_BLOCK_SPAWN_POSITION, spawn_pos); + + crate::base() + .with(FallingBlock) + .with(FallingBlockType(ty)) + .with(SpawnPacketCreator(&create_spawn_packet)) + .with( + PhysicsBuilder::new() + .bbox(0.98, 0.98, 0.98) + .drag(0.98) + .gravity(-0.04) + .build(), + ) + .with(meta) +} + +fn create_spawn_packet(accessor: &EntityRef) -> Box<dyn Packet> { + let data = i32::from(accessor.get::<FallingBlockType>().0.vanilla_id()); + let position = accessor.get::<Position>(); + let entity_id = accessor.get::<NetworkId>().0; + + let velocity = accessor.get::<Velocity>().0; + + let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocity); + + let packet = SpawnObject { + entity_id, + object_uuid: Uuid::new_v4(), + ty: 70, // Type 70 for falling block + x: position.x, + y: position.y, + z: position.z, + pitch: degrees_to_stops(position.pitch), + yaw: degrees_to_stops(position.yaw), + data, + velocity_x, + velocity_y, + velocity_z, + }; + + Box::new(packet) +} diff --git a/feather/old/server/entity/src/object/item.rs b/feather/old/server/entity/src/object/item.rs new file mode 100644 index 000000000..2ff631b03 --- /dev/null +++ b/feather/old/server/entity/src/object/item.rs @@ -0,0 +1,264 @@ +//! Handling of item entities. + +use feather_core::anvil::entity::{ + BaseEntityData, EntityData, EntityDataKind, ItemData, ItemEntityData, ItemNbt, +}; +use feather_core::entitymeta::{EntityMetadata, META_INDEX_ITEM_SLOT}; +use feather_core::inventory::Inventory; +use feather_core::items::{Item, ItemStack}; +use feather_core::network::packets::SpawnObject; +use feather_core::network::Packet; +use feather_core::util::{Position, Vec3d}; +use feather_server_types::{ + ComponentSerializer, Dead, EntityLoaderRegistration, EntitySpawnEvent, Game, + InventoryUpdateEvent, ItemCollectEvent, ItemDropEvent, NetworkId, PhysicsBuilder, Player, + SpawnPacketCreator, Uuid, Velocity, PLAYER_EYE_HEIGHT, TPS, +}; +use feather_server_util::{degrees_to_stops, nearby_entities, protocol_velocity}; +use fecs::{component, EntityBuilder, EntityRef, IntoQuery, Read, World, Write}; +use parking_lot::Mutex; +use rand::Rng; +use std::sync::atomic::{AtomicBool, Ordering}; + +/// Component which stores the world time at which an item +/// will be collectable. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct CollectableAt(u64); + +/// Component used to store whether an item has been collected/ +/// removed on a given tick. Used by `item_collect` and `item_merge` +/// systems. +#[derive(Debug)] +struct IsRemoved(AtomicBool); + +inventory::submit! { + EntityLoaderRegistration::new(EntityDataKind::Item, &load) +} + +/// Handler for spawning an item entity when +/// an item is dropped. +#[fecs::event_handler] +pub fn on_item_drop_spawn_item_entity(event: &ItemDropEvent, game: &mut Game, world: &mut World) { + // Spawn item entity. + + // Position is player's eye height minus 0.3 + let mut pos = { + let player_pos = + *world.get::<Position>(event.player) + glm::vec3(0.0, PLAYER_EYE_HEIGHT, 0.0); + player_pos - glm::vec3(0.0f64, 0.3, 0.0) + }; + + pos.on_ground = false; + + let mut rng = game.rng(); + + // This velocity calculation was sourced from Glowstone's + // work. See https://github.com/GlowstoneMC/Glowstone/blob/dev/src/main/java/net/glowstone/entity/GlowHumanEntity.java + // (method drop(ItemStack stack)) for their code. + let velocity = { + let mut vel = glm::DVec3::from_column_slice(&(pos.direction() * 0.3).into_array()); + let rand_offset = 0.02; + + let x = rng.gen_range(0.0, rand_offset) - rand_offset / 2.0; + let y = rng.gen_range(0.0, 0.12); + let z = rng.gen_range(0.0, rand_offset) - rand_offset / 2.0; + + vel += glm::vec3(x, y, z); + + vel + }; + + drop(rng); + + let entity = create(event.stack, game.tick_count + TPS) + .with(pos) + .with(Velocity(velocity)) + .build() + .spawn_in(world); + game.handle(world, EntitySpawnEvent { entity }); +} + +/// System to add items to player inventories when the player comes near. +#[fecs::system] +pub fn item_collect(game: &mut Game, world: &mut World) { + // run every 1/10 second + if game.tick_count % (TPS / 10) != 0 { + return; + } + + let items_to_remove = Mutex::new(vec![]); + let inventory_update_events = Mutex::new(vec![]); + let item_collect_events = Mutex::new(vec![]); + + // For each player, check for nearby items and try collecting them + // Safety: we only iterate over entities which are players, + // and we only access item entities inside the loop. As such, + // we will not have multiple mutable references to the same component. + unsafe { + <(Read<Position>, Write<Inventory>)>::query() + .filter(component::<Player>()) + .filter(!component::<Dead>()) + .par_entities_for_each_unchecked(world.inner(), |(player, (pos, mut inventory))| { + let inventory: &mut Inventory = &mut *inventory; + + let nearby_entities = nearby_entities(world, game, *pos, glm::vec3(1.0, 1.0, 1.0)); + let nearby_items = nearby_entities.iter().filter_map(|entity| { + world + .try_get::<CollectableAt>(*entity) + .map(|collectable_at| { + if collectable_at.0 <= game.time.world_age() { + Some(*entity) + } else { + None + } + }) + .flatten() + }); + + for item in nearby_items { + debug_assert!(!world.has::<Player>(item)); + // try to mark this item is collected + // (this ensures another thread has not collected it + // as well, which makes the mutable access below + // safe) + let is_removed = world.get::<IsRemoved>(item); + + if !is_removed.0.compare_and_swap(false, true, Ordering::AcqRel) { + // we now have unique access to this item and its components. + let mut stack = world.get_mut_unchecked::<ItemStack>(item); + + let (slots, stack_remaining) = inventory.collect_item(*stack); + + let initial_remaining = stack.amount; + + let event = InventoryUpdateEvent { + slots, + entity: player, + }; + inventory_update_events.lock().push(event); + + // update stack + if stack_remaining == 0 { + items_to_remove.lock().push(item); + } else { + stack.amount = stack_remaining; + world + .get_mut_unchecked::<EntityMetadata>(item) + .set(META_INDEX_ITEM_SLOT, Some(*stack)); + } + + item_collect_events.lock().push(ItemCollectEvent { + item, + collector: player, + amount: initial_remaining - stack_remaining, + }); + } + } + }); + } + + // Trigger events + deferred entity deletes. + for event in item_collect_events.into_inner() { + game.handle(world, event); + } + + for item in items_to_remove.into_inner() { + game.despawn(item, world); + } + + for event in inventory_update_events.into_inner() { + game.handle(world, event); + } + + // Reset `IsRemoved`. + <Read<IsRemoved>>::query().for_each(world.inner(), |rem| rem.0.store(false, Ordering::Relaxed)); +} + +/// Returns an entity builder to create an item entity +/// with the given stack and collectable tick. +pub fn create(stack: ItemStack, collectable_at: u64) -> EntityBuilder { + let meta = EntityMetadata::entity_base().with(META_INDEX_ITEM_SLOT, Some(stack)); + let collectable_at = CollectableAt(collectable_at); + + crate::base() + .with(stack) + .with(IsRemoved(AtomicBool::new(false))) + .with(collectable_at) + .with(SpawnPacketCreator(&create_spawn_packet)) + .with(ComponentSerializer(&serialize)) + .with(meta) + .with( + PhysicsBuilder::new() + .bbox(0.25, 0.25, 0.25) + .drag(0.98) + .gravity(-0.04) + .build(), + ) +} + +fn create_spawn_packet(accessor: &EntityRef) -> Box<dyn Packet> { + let position = *accessor.get::<Position>(); + let velocity = *accessor.get::<Velocity>(); + let entity_id = accessor.get::<NetworkId>().0; + + let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocity.0); + + let packet = SpawnObject { + entity_id, + object_uuid: Uuid::new_v4(), + ty: 2, // Type 2 for item stack + x: position.x, + y: position.y, + z: position.z, + pitch: degrees_to_stops(position.pitch), + yaw: degrees_to_stops(position.yaw), + data: 1, // Has velocity + velocity_x, + velocity_y, + velocity_z, + }; + + Box::new(packet) +} + +fn serialize(game: &Game, accessor: &EntityRef) -> EntityData { + let vel = accessor.get::<Velocity>().0; + let item = accessor.get::<ItemStack>(); + let nbt = ItemNbt::from(*item); + let nbt = if nbt == Default::default() { + None + } else { + Some(nbt) + }; + EntityData::Item(ItemEntityData { + entity: BaseEntityData::new(*accessor.get::<Position>(), Vec3d::new(vel.x, vel.y, vel.z)), + age: 0, // todo + pickup_delay: (accessor.get::<CollectableAt>().0 as i64 - game.tick_count as i64).max(0) + as i16, + item: ItemData { + count: item.amount as i8, + item: item.ty.identifier().to_owned(), + nbt, + }, + health: 5, // todo + }) +} + +fn load(data: EntityData) -> anyhow::Result<EntityBuilder> { + match data { + EntityData::Item(data) => { + let pos = data.entity.read_position()?; + let vel = data.entity.read_velocity()?; + + Item::from_identifier(&data.item.item) + .ok_or_else(|| anyhow::anyhow!("invalid item {}", data.item.item))?; + let stack = data.item.into(); + let collectable_at = data.pickup_delay; + + Ok(create(stack, collectable_at as u64) + .with(pos) + .with(Velocity(glm::vec3(vel.x, vel.y, vel.z)))) + } + _ => panic!("attempted to use item::load to load a non-item"), + } +} diff --git a/feather/old/server/entity/src/object/supported_blocks.rs b/feather/old/server/entity/src/object/supported_blocks.rs new file mode 100644 index 000000000..5d0290278 --- /dev/null +++ b/feather/old/server/entity/src/object/supported_blocks.rs @@ -0,0 +1,39 @@ +//! Implements blocks that break when not supported by a full block: torches, snow, grass, etc. + +use feather_core::blocks::BlockId; +use feather_server_types::{BlockUpdateCause, BumpVec, Game}; +use feather_server_util::{ + is_block_supported_at, BlockNotifyBlock, BlockNotifyPosition, BlockNotifySupportedBlock, +}; +use fecs::{component, IntoQuery, Read, World}; + +/// System to check for supporting block when a block notify +/// entity is spawned with `BlockNotifySupportedBlock`. +#[fecs::system] +pub fn break_unsupported_blocks(game: &mut Game, world: &mut World) { + let mut actions = BumpVec::new_in(game.bump()); + + actions.extend( + <(Read<BlockNotifyBlock>, Read<BlockNotifyPosition>)>::query() + .filter(component::<BlockNotifySupportedBlock>()) + .iter_entities(world.inner()) + .map(|(entity, (block, position))| { + let pos = if !is_block_supported_at(block.0, game, position.0) { + Some(position.0) // Mark block for destruction + } else { + None + }; + + (entity, pos) + }), + ); + + for (entity, pos) in actions { + world.despawn(entity); // Despawn BlockNotify entity + + if let Some(pos) = pos { + // Destroy block + game.set_block_at(world, pos, BlockId::air(), BlockUpdateCause::Unsupported); + } + } +} diff --git a/feather/old/server/entity/src/particle.rs b/feather/old/server/entity/src/particle.rs new file mode 100644 index 000000000..84be9eec6 --- /dev/null +++ b/feather/old/server/entity/src/particle.rs @@ -0,0 +1,34 @@ +//! Implements particle entities. + +use feather_core::misc::ParticleData; +use feather_core::network::{packets, Packet}; +use feather_core::util::Position; +use feather_server_types::{ParticleCount, SpawnPacketCreator}; +use fecs::{EntityBuilder, EntityRef}; + +/// Creates a particle with the given kind and count. +pub fn create(kind: ParticleData, count: u32) -> EntityBuilder { + crate::base() + .with(kind) + .with(ParticleCount(count)) + .with(SpawnPacketCreator(&create_spawn_packet)) +} + +fn create_spawn_packet(accessor: &EntityRef) -> Box<dyn Packet> { + let particle = accessor.get::<ParticleData>(); + let count = accessor.get::<ParticleCount>().0; + let pos = *accessor.get::<Position>(); + + Box::new(packets::Particle { + long_distance: false, + x: pos.x as f32, + y: pos.y as f32, + z: pos.z as f32, + offset_x: 0.0, // TODO: offsets + offset_y: 0.0, + offset_z: 0.0, + particle_data: 0.0, // TODO: what is this? + particle_count: count as i32, + data: *particle, + }) +} diff --git a/feather/old/server/lighting/Cargo.toml b/feather/old/server/lighting/Cargo.toml new file mode 100644 index 000000000..b6418cf30 --- /dev/null +++ b/feather/old/server/lighting/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "feather-server-lighting" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-physics = { path = "../physics" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +arrayvec = "0.5" +smallvec = "1.4" +ahash = "0.3" +crossbeam = "0.7" +parking_lot = "0.10" +log = "0.4" +nalgebra-glm = "0.6" diff --git a/feather/old/server/lighting/src/lib.rs b/feather/old/server/lighting/src/lib.rs new file mode 100644 index 000000000..9e165cd45 --- /dev/null +++ b/feather/old/server/lighting/src/lib.rs @@ -0,0 +1,623 @@ +//! An implementation of lighting, primarily based on 3D flood fill +//! algorithms. +//! +//! # Structure +//! Lighting is done on a separate _lighting worker thread_ which +//! stores its own copy of the chunk map. The server notifies +//! it when chunks are loaded and unloaded, and it can +//! request that it handle a lighting update, either for +//! an entire chunk or for a single block update. Since the lighting +//! worker has clones of the `Arc`s in which chunks are held, any +//! updates it makes to light data are visible to the server thread. +//! +//! # Algorithms: block light +//! For block light calculation, we define four types of block +//! updates for which to perform lighting: +//! +//! * Creation of a light-emitting block. We simply propagate +//! the light update using flood fill. +//! +//! * Removal of a light-emitting block. We first perform flood fill +//! and set any blocks which were previously affected by this block's +//! light to 0. Then, we recalculate lighting for light sources within +//! a range of 30 blocks based on algorithm #1. +//! +//! * Creation of an opaque, non-emitting block. We first set the created +//! block to air temporarily. We then query for nearby lights +//! within a range of 15 (the maximum distance travelled by light) and perform +//! algorithm #2 on them. Finally, we set the created block back to the correct +//! value and perform algorithm #1 on all lights. +//! +//! * Removal of an opaque, non-emitting block. In this case, +//! we set the new air block's light to the highest value of an +//! adjacent block minus 1. We then perform algorithm #1 on this new block. +//! +//! Each algorithm is implemented in a separate function, and `LightingSystem` +//! determines which to use based on the values of the block update event. +//! +//! If we are recalculating light for an entire chunk, e.g. when a chunk is generated, +//! we first zero out light, then find all light sources in the chunk and perform +//! algorithm #1 on them as if they had just been placed. + +extern crate nalgebra_glm as glm; + +#[cfg_attr(test, macro_use)] +extern crate smallvec; + +use ahash::{AHashMap, AHashSet}; +use arrayvec::ArrayVec; +use feather_core::util::{BlockPosition, ChunkPosition}; + +use feather_core::blocks::BlockId; +use feather_core::chunk::Chunk; +use feather_core::chunk_map::{chunk_relative_pos, ChunkMap}; +use feather_server_types::{BlockUpdateEvent, ChunkLoadEvent, ChunkUnloadEvent, Game}; +use feather_server_util::chunks_within_distance; +use parking_lot::{RwLock, RwLockWriteGuard}; +use smallvec::SmallVec; +use std::collections::VecDeque; +use std::marker::PhantomData; +use std::sync::Arc; + +#[fecs::event_handler] +pub fn on_block_update_notify_lighting_worker( + event: &BlockUpdateEvent, + #[default] handle: &LightingWorkerHandle, +) { + let (pos, old, new) = (event.pos, event.old, event.new); + handle + .tx + .send(Request::HandleBlockUpdate { pos, old, new }) + .expect("failed to notify lighting worker of block update"); +} + +#[fecs::event_handler] +pub fn on_chunk_load_notify_lighting_worker( + event: &ChunkLoadEvent, + game: &mut Game, + handle: &LightingWorkerHandle, +) { + let chunk_handle = game + .chunk_map + .chunk_handle_at(event.chunk) + .expect("chunk load event triggered, but chunk not in chunk map"); + + handle + .tx + .send(Request::LoadChunk { + pos: event.chunk, + handle: chunk_handle, + }) + .expect("failed to notify lighting worker of chunk load"); +} + +#[fecs::event_handler] +pub fn on_chunk_unload_notify_lighting_worker( + event: &ChunkUnloadEvent, + handle: &LightingWorkerHandle, +) { + handle + .tx + .send(Request::UnloadChunk { pos: event.chunk }) + .expect("failed to notify lighting worker of chunk unload"); +} + +/// A request sent to the lighting worker. +pub enum Request { + /// Notifies the worker of a new loaded chunk. + LoadChunk { + pos: ChunkPosition, + handle: ChunkHandle, + }, + /// Notifies the worker that a chunk was unloaded. + UnloadChunk { pos: ChunkPosition }, + /// Requests that the lighting worker shuts down. + ShutDown, + /// Requests that the lighting worker handles a block update. + HandleBlockUpdate { + /// The position of the block which was updated. + pos: BlockPosition, + /// The old value of the block. + old: BlockId, + /// The new value of the block. + new: BlockId, + }, +} + +/// Handle to the lighting worker. +#[derive(Clone)] +pub struct LightingWorkerHandle { + pub tx: crossbeam::Sender<Request>, + pub shutdown_rx: crossbeam::Receiver<()>, +} + +impl Default for LightingWorkerHandle { + fn default() -> Self { + start_worker() + } +} + +/// Starts the lighting worker, returning a handle to it. +fn start_worker() -> LightingWorkerHandle { + let (tx, rx) = crossbeam::bounded(512); + let (shutdown_tx, shutdown_rx) = crossbeam::bounded(1); + + std::thread::spawn(move || run_worker(rx, shutdown_tx)); + + LightingWorkerHandle { tx, shutdown_rx } +} + +/// Cache storing the light sources in each chunk. +#[derive(Debug, Default)] +struct ChunkLights(AHashMap<ChunkPosition, SmallVec<[BlockPosition; 8]>>); + +impl ChunkLights { + /// Returns an iterator over light sources within the given radius + /// of a block position. + pub fn lights_within_radius<'a>( + &'a self, + pos: BlockPosition, + radius: u8, + ) -> impl Iterator<Item = BlockPosition> + 'a + Clone { + let radius = f64::from(radius); + let chunks = chunks_within_distance(pos.position(), glm::vec3(radius, radius, radius)); + + chunks + .into_iter() + .flat_map(move |chunk| { + self.0 + .get(&chunk) + .map(|vec| vec.as_slice()) + .unwrap_or(&[]) + .iter() + }) + .copied() + } +} + +/// Internal worker state. +struct Worker { + /// Receiver for new requests. + rx: crossbeam::Receiver<Request>, + /// The worker's own copy of the chunk map, with `Arc`s + /// being cloned from the server thread's "official" chunk map. + chunk_map: ChunkMap, + /// Caches the light sources in each chunk. + lights: ChunkLights, + /// Whether the worker should shut down. + should_shut_down: bool, +} + +fn run_worker(rx: crossbeam::Receiver<Request>, shutdown_tx: crossbeam::Sender<()>) { + let mut worker = Worker { + rx, + chunk_map: Default::default(), + lights: Default::default(), + should_shut_down: false, + }; + + log::info!("Lighting worker started"); + while let Ok(request) = worker.rx.recv() { + handle_request(&mut worker, request); + + if worker.should_shut_down { + break; + } + } + + log::info!("Lighting worker shutting down"); + let _ = shutdown_tx.try_send(()); +} + +fn handle_request(worker: &mut Worker, request: Request) { + match request { + Request::ShutDown => worker.should_shut_down = true, + Request::LoadChunk { pos, handle } => load_chunk(worker, pos, handle), + Request::UnloadChunk { pos } => unload_chunk(worker, pos), + Request::HandleBlockUpdate { pos, old, new } => handle_block_update(worker, pos, old, new), + } +} + +fn load_chunk(worker: &mut Worker, pos: ChunkPosition, handle: Arc<RwLock<Chunk>>) { + worker + .lights + .0 + .insert(pos, lights_in_chunk(&*handle.read()).collect()); + worker.chunk_map.0.insert(pos, handle); +} + +fn lights_in_chunk<'a>(chunk: &'a Chunk) -> impl Iterator<Item = BlockPosition> + 'a { + (0..16) + .flat_map(|x| (0..256).map(move |y| (x, y))) + .flat_map(|(x, y)| (0..16).map(move |z| (x, y, z))) + .filter_map(move |(x, y, z)| { + let block = chunk.block_at(x, y, z); + + if block.light_emission() > 0 { + Some(BlockPosition::new(x as i32, y as i32, z as i32)) + } else { + None + } + }) +} + +fn unload_chunk(worker: &mut Worker, pos: ChunkPosition) { + worker.lights.0.remove(&pos); + worker.chunk_map.0.remove(&pos); +} + +/// Lighter context, used to cache things during +/// a lighting iteration. +struct Context<'a> { + /// Reference to the current cached chunk. + /// This is used to avoid repetitive hashmap + /// accesses in the chunk map when groups + /// of clustered blocks are queried for. + current_chunk: RwLockWriteGuard<'static, Chunk>, + + chunk_map: *const ChunkMap, + + _phantom: PhantomData<&'a ()>, +} + +impl<'a> Context<'a> { + fn new(chunk_map: &'a ChunkMap, start_chunk: ChunkPosition) -> Option<Self> { + Some(Self { + current_chunk: unsafe { + std::mem::transmute::<RwLockWriteGuard<'a, Chunk>, RwLockWriteGuard<'static, Chunk>>( + chunk_map.chunk_at_mut(start_chunk)?, + ) + }, + chunk_map: chunk_map as *const _, + _phantom: PhantomData, + }) + } + + fn chunk_at_mut(&mut self, pos: ChunkPosition) -> Option<&mut Chunk> { + if pos == self.current_chunk.position() { + Some(&mut *self.current_chunk) + } else { + self.current_chunk = unsafe { &*self.chunk_map }.chunk_at_mut(pos)?; + Some(&mut *self.current_chunk) + } + } + + fn block_light_at(&mut self, pos: BlockPosition) -> u8 { + match self.chunk_at_mut(pos.chunk()) { + Some(chunk) => { + let (x, y, z) = chunk_relative_pos(pos); + chunk.block_light_at(x, y, z) + } + None => 0, // TODO: graceful handling of missing chunk information? + } + } + + fn set_block_light_at(&mut self, pos: BlockPosition, value: u8) { + if let Some(chunk) = self.chunk_at_mut(pos.chunk()) { + let (x, y, z) = chunk_relative_pos(pos); + chunk.set_block_light_at(x, y, z, value); + } + } + + fn block_at(&mut self, pos: BlockPosition) -> BlockId { + match self.chunk_at_mut(pos.chunk()) { + Some(chunk) => { + let (x, y, z) = chunk_relative_pos(pos); + chunk.block_at(x, y, z) + } + None => BlockId::air(), + } + } + + fn set_block_at(&mut self, pos: BlockPosition, block: BlockId) { + if let Some(chunk) = self.chunk_at_mut(pos.chunk()) { + let (x, y, z) = chunk_relative_pos(pos); + chunk.set_block_at(x, y, z, block); + } + } +} + +const MAX_TRAVEL_DISTANCE: u8 = 15; + +fn handle_block_update(worker: &mut Worker, pos: BlockPosition, old: BlockId, new: BlockId) { + let mut ctx = match Context::new(&worker.chunk_map, pos.chunk()) { + Some(ctx) => ctx, + None => return, // Unloaded chunk + }; + + // Determine which algorithm to use. + if old.light_emission() < new.light_emission() { + ctx.set_block_light_at(pos, new.light_emission()); + emitting_creation(&mut ctx, pos); + } else if new.light_emission() == 0 && old.light_emission() > 0 { + ctx.set_block_light_at(pos, 0); + emitting_removal(&mut ctx, &worker.lights, pos, old); + } else if old.is_opaque() && !new.is_opaque() { + opaque_non_emitting_removal(&mut ctx, pos); + } else { + opaque_non_emitting_creation(&mut ctx, &worker.lights, pos, new); + } + + // Update `ChunkLights`. + if old.light_emission() != new.light_emission() { + if new.light_emission() == 0 { + worker + .lights + .0 + .entry(pos.chunk()) + .or_default() + .retain(|p| *p != pos); + } else if old.light_emission() == 0 { + worker.lights.0.entry(pos.chunk()).or_default().push(pos); + } + } +} + +/// Algorithm #1, as described in the module-level docs. +fn emitting_creation(context: &mut Context, position: BlockPosition) { + let emission = context.block_light_at(position); + // Perform flood fill starting from `position`. + // For each block, set the light value to the maximum light + // value of any adjacent block minus 1. + flood_fill(context, position, emission, |ctx, pos| { + let light = light_value_for_block(ctx, pos); + ctx.set_block_light_at(pos, light); + }); +} + +/// Algorithm #2, as described in the module-level docs. +fn emitting_removal( + context: &mut Context, + chunk_lights: &ChunkLights, + position: BlockPosition, + old_block: BlockId, +) { + // Perform flood fill and set all blocks affected by the old light to 0 light. + flood_fill(context, position, old_block.light_emission(), |ctx, pos| { + ctx.set_block_light_at(pos, 0); + }); + + // For all lights which could have affected the blocks we just set to 0, + // recalculate lighting using algorithm #1. + let nearby_lights = chunk_lights.lights_within_radius(position, MAX_TRAVEL_DISTANCE * 2); + + for light in nearby_lights { + if light != position { + emitting_creation(context, light); + } + } +} + +/// Algorithm #3, as described in the module-level docs. +fn opaque_non_emitting_creation( + context: &mut Context, + chunk_lights: &ChunkLights, + position: BlockPosition, + new_block: BlockId, +) { + // Re-calculate all lights that could have affected this block. + // We ensure that all areas are correctly set to dark by first + // faking that the block was never created. + context.set_block_at(position, BlockId::air()); + + let nearby_lights = chunk_lights.lights_within_radius(position, MAX_TRAVEL_DISTANCE); + + for light in nearby_lights { + let block = context.block_at(light); + emitting_removal(context, chunk_lights, light, block); + } + + // Set block back to correct value. + context.set_block_at(position, new_block); + + let nearby_lights = chunk_lights.lights_within_radius(position, MAX_TRAVEL_DISTANCE); + + // Recalculate nearby lights. + for light in nearby_lights { + emitting_creation(context, light); + } +} + +/// Algorithm #4, as described in the module-level docs. +fn opaque_non_emitting_removal(context: &mut Context, position: BlockPosition) { + let value = light_value_for_block(context, position); + + context.set_block_light_at(position, value); + + // Propagate new light value for this block, as if it were a new light source. + if value > 0 { + emitting_creation(context, position); + } +} + +/// Returns the light value for the block at `position`, +/// equivalent to the maximum light value of an adjacent block +/// minus 1. +fn light_value_for_block(context: &mut Context, position: BlockPosition) -> u8 { + // Find highest light value of 6 adjacent blocks. + let adjacent = adjacent_blocks(position); + + let mut value = adjacent + .into_iter() + .map(|pos| context.block_light_at(pos)) + .max() + .unwrap(); + + if value > 0 { + value -= 1; + } + + value +} + +/// Performs flood fill starting at `start` and travelling up +/// to `max_dist` blocks. +/// +/// For each block iterated over, the provided closure will be invoked. +/// No block will be iterated more than once. +fn flood_fill<F>(context: &mut Context, start: BlockPosition, max_dist: u8, mut f: F) +where + F: FnMut(&mut Context, BlockPosition), +{ + // TODO: bump allocate these data structures. + // Don't iterate over same block more than once + let mut touched = AHashSet::with_capacity_and_hasher(64, ahash::RandomState::new()); + touched.insert(start); + + // We use a queue-based algorithm rather than a recursive + // one. + let mut queue = VecDeque::with_capacity(64); + + queue.push_back(start); + + while let Some(pos) = queue.pop_front() { + let blocks = adjacent_blocks(pos); + + for pos in blocks { + if pos.manhattan_distance(start) > max_dist as i32 { + // Finished + return; + } + + // Skip if we already went over this block + if !touched.insert(pos) { + continue; + } + + let block = context.block_at(pos); + if block.is_opaque() { + continue; // Stop iterating + } + + // Call closure + f(context, pos); + + // Add block to queue + queue.push_back(pos); + } + } +} + +/// Returns the up to six adjacent blocks to a given block position. +fn adjacent_blocks(to: BlockPosition) -> ArrayVec<[BlockPosition; 6]> { + let offsets = [ + (-1, 0, 0), + (1, 0, 0), + (0, -1, 0), + (0, 1, 0), + (0, 0, -1), + (0, 0, 1), + ]; + offsets + .iter() + .map(|(x, y, z)| BlockPosition::new(to.x + *x, to.y + *y, to.z + *z)) + .filter(|pos| pos.y >= 0 && pos.y < 256) + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_context() { + let mut chunk_map = ChunkMap::new(); + + let pos = ChunkPosition::new(0, 0); + chunk_map.insert(Chunk::new(pos)); + let pos2 = ChunkPosition::new(0, 1); + chunk_map.insert(Chunk::new(pos2)); + + let mut ctx = Context::new(&chunk_map, pos).unwrap(); + + assert_eq!(ctx.chunk_at_mut(pos).unwrap().position(), pos); + assert_eq!(ctx.chunk_at_mut(pos2).unwrap().position(), pos2); + assert_eq!(ctx.chunk_at_mut(pos).unwrap().position(), pos); + } + + #[test] + fn test_emitting_creation() { + let chunk_map = chunk_map(); + let mut ctx = Context::new(&chunk_map, ChunkPosition::new(0, 0)).unwrap(); + + let pos = BlockPosition::new(0, 100, 0); + ctx.set_block_at(pos, BlockId::glowstone()); + ctx.set_block_light_at(pos, BlockId::glowstone().light_emission()); + + emitting_creation(&mut ctx, pos); + + assert_eq!(ctx.block_light_at(BlockPosition::new(0, 99, 0)), 14); + assert_eq!(ctx.block_light_at(BlockPosition::new(0, 99, 1)), 13); + } + + #[test] + fn test_opaque_non_emitting_removal() { + let chunk_map = chunk_map(); + let mut ctx = Context::new(&chunk_map, ChunkPosition::new(0, 0)).unwrap(); + + ctx.set_block_light_at(BlockPosition::new(0, 0, 0), 10); + ctx.set_block_light_at(BlockPosition::new(0, 2, 0), 9); + ctx.set_block_light_at(BlockPosition::new(1, 1, 0), 8); + ctx.set_block_light_at(BlockPosition::new(-1, 1, 0), 11); + ctx.set_block_light_at(BlockPosition::new(0, 1, 1), 0); + ctx.set_block_light_at(BlockPosition::new(0, 1, -1), 12); + ctx.set_block_light_at(BlockPosition::new(0, 1, 0), 15); + + opaque_non_emitting_removal(&mut ctx, BlockPosition::new(0, 1, 0)); + + assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 0)), 11); + assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 1)), 10); + assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 2)), 9); + assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 3)), 8); + assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 4)), 7); + // ... + } + + #[test] + fn test_flood_fill() { + let chunk_map = chunk_map(); + let mut ctx = Context::new(&chunk_map, ChunkPosition::new(0, 0)).unwrap(); + + let mut count = 0; + + flood_fill(&mut ctx, BlockPosition::new(100, 100, 100), 1, |_, _| { + count += 1 + }); + + assert_eq!(count, 6); + } + + #[test] + fn test_chunk_lights() { + let mut chunk_lights = ChunkLights::default(); + chunk_lights.0.insert( + ChunkPosition::new(0, 0), + smallvec![BlockPosition::new(0, 0, 0)], + ); + chunk_lights.0.insert( + ChunkPosition::new(1, 0), + smallvec![BlockPosition::new(16, 0, 0)], + ); + + assert_eq!( + chunk_lights + .lights_within_radius(BlockPosition::new(0, 0, 0), 16) + .collect::<Vec<_>>() + .as_slice(), + &[BlockPosition::new(0, 0, 0), BlockPosition::new(16, 0, 0)] + ); + } + + fn chunk_map() -> ChunkMap { + let mut chunk_map = ChunkMap::new(); + + for x in -1..=1 { + for z in -1..=1 { + let pos = ChunkPosition::new(x, z); + chunk_map.insert(Chunk::new(pos)); + } + } + + chunk_map + } +} diff --git a/feather/old/server/network/Cargo.toml b/feather/old/server/network/Cargo.toml new file mode 100644 index 000000000..a60c4c15f --- /dev/null +++ b/feather/old/server/network/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "feather-server-network" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +tokio = { version = "0.2", features = ["full"] } +tokio-util = { version = "0.3", features = ["codec"] } +flume = "0.7" +derivative = "2.1" +mojang-api = "0.6" +parking_lot = "0.10" +log = "0.4" +once_cell = "1.3" +futures = "0.3" +anyhow = "1.0" +thiserror = "1.0" +serde_json = "1.0" +num-bigint-dig = "0.6" +uuid = { version = "0.8", features = ["v3"] } +md5 = "0.7" + +# Crypto +rsa = "0.2" +rsa-der = "0.2" +rand = "0.7" diff --git a/feather/old/server/network/src/initial_handler.rs b/feather/old/server/network/src/initial_handler.rs new file mode 100644 index 000000000..3737da4f2 --- /dev/null +++ b/feather/old/server/network/src/initial_handler.rs @@ -0,0 +1,984 @@ +//! The initial handler is responsible for +//! handling new connections and getting +//! through the login sequence. After login +//! is completed, control is handed over to the server +//! thread, which is responsible for sending chunks/inventory/ +//! players and then spawning the player. +//! +//! The initial handler is also responsible for handling +//! server list pings. To do this, it shares an `Arc<AtomicInteger>` +//! representing the player count with the server. +//! +//! The initial handler runs on the IO worker thread. +//! This is done to ensure minimal latency in packet handling, +//! speeding up the login process and making the latency calculation in +//! the server list ping as low as possible. + +use std::net::SocketAddr; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::{Arc, RwLock}; +use std::time::SystemTime; + +use rand::rngs::OsRng; +use rsa::{PaddingScheme, PublicKey, RSAPrivateKey}; +use rsa_der as der; + +use thiserror::Error; + +use feather_core::network::{cast_packet, Packet, PacketStage, PacketType}; +use feather_core::text::{Text, TextRoot}; + +use crate::{PROTOCOL_VERSION, SERVER_VERSION}; +use feather_core::network::packets::{ + DisconnectLogin, EncryptionRequest, EncryptionResponse, Handshake, HandshakeState, LoginStart, + LoginSuccess, Ping, Pong, Request, Response, SetCompression, +}; +use feather_server_types::{BanInfo, Config, ProxyMode}; +use feather_server_util::name_to_uuid_offline; +use mojang_api::ProfileProperty; +use once_cell::sync::Lazy; +use uuid::Uuid; + +/// The key used for symmetric encryption. +pub type Key = [u8; 16]; +/// The verify token used to ensure that encryption +/// is working correctly. +type VerifyToken = [u8; 4]; + +/// The number of bits used for the RSA key. +const RSA_KEY_BITS: usize = 1024; +/// The number of bytes in the shared secret +const SHARED_SECRET_LEN: usize = 128 / 8; + +pub static RSA_KEY: Lazy<RSAPrivateKey> = Lazy::new(|| { + let mut rng = OsRng; + RSAPrivateKey::new(&mut rng, RSA_KEY_BITS).unwrap() +}); + +/// An action for the worker thread to execute +/// after `InitialHandler::handle_packet` is called. +pub enum Action { + EnableCompression(i32), + EnableEncryption(Key), + SendPacket(Box<dyn Packet>), + Disconnect, + SetStage(PacketStage), + JoinGame(JoinResult), +} + +/// The type returned for when a player has completed the login process. +#[derive(Clone, Debug)] +pub struct JoinResult { + pub username: Option<String>, + pub uuid: Uuid, + pub props: Vec<mojang_api::ProfileProperty>, +} + +impl JoinResult { + /// Creates a `JoinResult` for an offline mode player with the given username. + /// + /// The UUID will be computed using Minecraft's method for computing offline mode + /// UUIDs as a function of the username. + fn with_username(username: String) -> Self { + let mut join_result = JoinResult::default(); + + join_result.uuid = name_to_uuid_offline(&username); + join_result.username = Some(username); + + join_result + } +} + +impl Default for JoinResult { + fn default() -> Self { + JoinResult { + username: None, + uuid: Uuid::new_v4(), + props: vec![], + } + } +} + +/// An initial handler for a connection. +/// +/// When a packet is received from the client this initial +/// handler is registered with, `handle_packet` should be called. +/// This function runs all the necessary code to handle the +/// login sequence or the server list ping. +/// +/// The initial handler is able to communicate with the worker +/// implementation by exposing the `actions_to_execute` method, +/// which returns a vector of actions for the worker to execute. +/// These may include, for example, enabling encryption or sending +/// a packet. +pub struct InitialHandler { + /// A queue of actions to perform. When `actions_to_execute` + /// is called, the queue is flushed. + action_queue: Vec<Action>, + + /// If set to a value, indicates that encryption + /// should be enabled with the given key. + key: Option<Key>, + + /// If set to a value, indicates that compression + /// should be enabled with the given threshold. + compression_threshold: Option<i32>, + + /// The verify token generated for this exchange. + verify_token: VerifyToken, + + /// The server's configuration. + config: Arc<Config>, + /// Server bans + ban_info: Arc<RwLock<BanInfo>>, + /// The server's player count. + player_count: Arc<AtomicU32>, + /// The server's icon, if any was loaded. + server_icon: Arc<Option<String>>, + + /// The client's IP address. + client_ip: SocketAddr, + + /// The player info, set to `Some` once + /// the initial handler is finished and + /// the player should join. + info: Option<JoinResult>, + + /// The stage of this initial handler. + stage: Stage, +} + +impl InitialHandler { + pub fn new( + config: Arc<Config>, + ban_info: Arc<RwLock<BanInfo>>, + player_count: Arc<AtomicU32>, + server_icon: Arc<Option<String>>, + client_ip: SocketAddr, + ) -> Self { + Self { + action_queue: vec![], + + key: None, + compression_threshold: None, + + verify_token: rand::random(), + + config, + ban_info, + player_count, + server_icon, + + client_ip, + + info: None, + + stage: Stage::AwaitHandshake, + } + } + + /// Notifies this initial handler of a packet + /// received from the client. After calling this + /// function, `action_queue` should be called + /// and the actions should be executed in order. + pub async fn handle_packet(&mut self, packet: Box<dyn Packet>) { + if self.stage == Stage::Finished { + panic!("Called InitialHandler::handle_packet() after completion"); + } + + if let Err(e) = _handle_packet(self, packet).await { + // Disconnect + disconnect_login(self, Text::from(e.to_string())); + + let username = self + .info + .as_ref() + .and_then(|info| info.username.as_deref()) + .unwrap_or("unkown"); + log::info!("Player {} disconnected: {}", username, e); + } + } + + /// Returns a vector of actions to perform. + pub fn actions_to_execute(&mut self) -> Vec<Action> { + let mut new_vec = vec![]; + std::mem::swap(&mut new_vec, &mut self.action_queue); + + new_vec + } +} + +/// Handles a packet, returning `Err` if the player +/// should be disconnected. +async fn _handle_packet(ih: &mut InitialHandler, packet: Box<dyn Packet>) -> Result<(), Error> { + // Find packet type and forward to correct function + match packet.ty() { + PacketType::Handshake => handle_handshake(ih, &cast_packet::<Handshake>(packet))?, + PacketType::Request => handle_request(ih, &cast_packet::<Request>(packet))?, + PacketType::Ping => handle_ping(ih, &cast_packet::<Ping>(packet))?, + PacketType::LoginStart => handle_login_start(ih, &cast_packet::<LoginStart>(packet))?, + PacketType::EncryptionResponse => { + handle_encryption_response(ih, &cast_packet::<EncryptionResponse>(packet)).await? + } + ty => return Err(Error::InvalidPacket(ty, ih.stage)), + } + + Ok(()) +} + +fn handle_handshake(ih: &mut InitialHandler, packet: &Handshake) -> Result<(), Error> { + check_stage(ih, Stage::AwaitHandshake, packet.ty())?; + + ih.stage = match packet.next_state { + HandshakeState::Status => { + ih.action_queue.push(Action::SetStage(PacketStage::Status)); + Stage::AwaitRequest + } + HandshakeState::Login => { + // While status requests can use differing + // protocol versions, a client + // needs to have a matching protocol version + // to log in. + if packet.protocol_version != PROTOCOL_VERSION { + return Err(Error::InvalidProtocol(packet.protocol_version)); + } + + // If the server has BungeeCord proxy mode enabled, extract the data that is submitted + // by BungeeCord if IP forwarding is enabled. + if ih.config.proxy.proxy_mode == ProxyMode::BungeeCord { + let bungeecord_data = extract_bungeecord_data(packet)?; + ih.info = Some(JoinResult { + username: None, + uuid: bungeecord_data.uuid, + props: bungeecord_data.properties, + }); + } + + ih.action_queue.push(Action::SetStage(PacketStage::Login)); + Stage::AwaitLoginStart + } + }; + + Ok(()) +} + +/// Tries to extract the player information that is sent in the `server_address` field of a +/// Handshake packet that originates from a BungeeCord style proxy. This is used to enable IP +/// forwarding for BungeeCord style proxies. +/// +/// The server address field should have 4 parts if a client is connecting via BungeeCord. The field +/// has the following format: +/// +/// format!("{}\0{}\0{}\0{}", host, address, uuid, mojang_response); +/// +/// | Variable | Definition | +/// |-----------------|-----------------------------------------------------| +/// | Host | The IP address of the BungeeCord instance | +/// | Address | The IP address of the connecting client | +/// | UUID | The UUID that is associated to the clients account | +/// | Mojang response | A JSON formatted version of the `properties` field +/// in [Mojangs response](https://wiki.vg/Protocol_Encryption#Server) | +fn extract_bungeecord_data(packet: &Handshake) -> Result<BungeeCordData, Error> { + let bungee_information: Vec<&str> = packet.server_address.split('\0').collect(); + Ok(BungeeCordData::from_vec(&bungee_information)?) +} + +#[derive(Debug, PartialEq)] +struct BungeeCordData { + host: String, + client: String, + uuid: Uuid, + properties: Vec<ProfileProperty>, +} + +impl BungeeCordData { + pub fn from_vec(data: &[&str]) -> Result<Self, Error> { + if data.len() != 4 { + return Err(Error::BungeeSpecMismatch("Incorrect length".to_string())); + } + + let host = (*data.get(0).unwrap()).to_string(); + let client = (*data.get(1).unwrap()).to_string(); + let uuid = Uuid::parse_str(*data.get(2).unwrap()) + .map_err(|e| Error::BungeeSpecMismatch(e.to_string()))?; + let properties = serde_json::from_str(data.get(3).unwrap()) + .map_err(|e| Error::BungeeSpecMismatch(e.to_string()))?; + + Ok(BungeeCordData { + host, + client, + uuid, + properties, + }) + } +} + +fn handle_request(ih: &mut InitialHandler, packet: &Request) -> Result<(), Error> { + check_stage(ih, Stage::AwaitRequest, packet.ty())?; + let server_icon = (*ih.server_icon).clone().unwrap_or_default(); + + // Send response packet + let mut json = serde_json::json!({ + "version": { + "name": SERVER_VERSION, + "protocol": PROTOCOL_VERSION, + }, + "players": { + "max": ih.config.server.max_players, + "online": ih.player_count.load(Ordering::SeqCst), + }, + "description": { + "text": ih.config.server.motd, + }, + "favicon": server_icon, + }); + + // Remove the favicon field if there is no favicon + if server_icon.is_empty() { + json.as_object_mut().unwrap().remove("favicon"); + } + + let response = Response { + json_response: json.to_string(), + }; + send_packet(ih, response); + + ih.stage = Stage::AwaitPing; + + Ok(()) +} + +fn handle_ping(ih: &mut InitialHandler, packet: &Ping) -> Result<(), Error> { + check_stage(ih, Stage::AwaitPing, packet.ty())?; + + let pong = Pong { + payload: packet.payload, + }; + send_packet(ih, pong); + + // After sending pong, we should disconnect. + ih.action_queue.push(Action::Disconnect); + ih.stage = Stage::Finished; + + Ok(()) +} + +fn handle_login_start(ih: &mut InitialHandler, packet: &LoginStart) -> Result<(), Error> { + check_stage(ih, Stage::AwaitLoginStart, packet.ty())?; + + if ih.player_count.load(Ordering::Acquire) >= ih.config.server.max_players as u32 { + disconnect_login(ih, Text::from("Server is full!")); + return Ok(()); + } + + let (reason, remove_ban) = { + let ban_info = ih.ban_info.read().unwrap(); + let ip_ban = ban_info.ip_bans.get(&ih.client_ip.ip()); + + if let Some(ban) = ip_ban { + // Expire the ban if it's over. + if let Some(expires) = ban.expires_after { + if expires < SystemTime::now() { + (None, true) + } else { + (Some(Text::from(ban.reason.clone())), false) + } + } else { + (Some(Text::from(ban.reason.clone())), false) + } + } else { + (None, false) + } + }; + + if let Some(reason) = reason { + disconnect_login(ih, reason); + return Ok(()); + } else if remove_ban { + ih.ban_info + .write() + .unwrap() + .ip_bans + .remove(&ih.client_ip.ip()); + } + + // If in online mode, encryption needs to be enabled, + // and authentication needs to be performed. + // If not in online mode, the login sequence is + // already finished, so we can call `finish` after + // setting the player's info. + if ih.config.server.online_mode { + use num_bigint_dig::{BigInt, Sign::Plus}; + // Start enabling encryption + let der = der::public_key_to_der( + &BigInt::from_biguint(Plus, RSA_KEY.n().clone()).to_signed_bytes_be(), + &BigInt::from_biguint(Plus, RSA_KEY.e().clone()).to_signed_bytes_be(), + ); + + let encryption_request = EncryptionRequest { + server_id: "".to_string(), // Server ID - always empty + public_key: der, + verify_token: ih.verify_token.to_vec(), + }; + send_packet(ih, encryption_request); + + ih.info = Some(JoinResult::with_username(packet.username.clone())); + + ih.stage = Stage::AwaitEncryptionResponse; + } else { + let username = packet.username.clone(); + + // Check if there is some info about the client available. This can be the case if the + // handshake is made by an IP forwarding proxy. + if let Some(info) = ih.info.as_mut() { + if info.username.is_none() { + info.username = Some(username); + } + } else { + // Finished - set info and join + ih.info = Some(JoinResult::with_username(username)) + } + + finish(ih); + } + + Ok(()) +} + +async fn handle_encryption_response( + ih: &mut InitialHandler, + packet: &EncryptionResponse, +) -> Result<(), Error> { + check_stage(ih, Stage::AwaitEncryptionResponse, packet.ty())?; + + // Decrypt verify token + shared secret + let shared_secret = decrypt_using_rsa(&packet.secret, &RSA_KEY)?; + if shared_secret.len() != SHARED_SECRET_LEN { + return Err(Error::BadSecretLength); + } + + let verify_token = decrypt_using_rsa(&packet.verify_token, &RSA_KEY)?; + if verify_token.len() != ih.verify_token.len() { + return Err(Error::VerifyTokenMismatch); + } + + // Check that verify token matches + if verify_token.as_slice() != ih.verify_token { + return Err(Error::VerifyTokenMismatch); + } + + // Enable encryption + let mut key = [0u8; SHARED_SECRET_LEN]; + for (i, x) in shared_secret[..SHARED_SECRET_LEN].iter().enumerate() { + key[i] = *x; + } + + ih.key = Some(key); + ih.action_queue + .push(Action::EnableEncryption(ih.key.unwrap())); + + use num_bigint_dig::{BigInt, Sign::Plus}; + let der = der::public_key_to_der( + &BigInt::from_biguint(Plus, RSA_KEY.n().clone()).to_signed_bytes_be(), + &BigInt::from_biguint(Plus, RSA_KEY.e().clone()).to_signed_bytes_be(), + ); + + // This unwrapping can be shorter with the use of .flatten() which will stabilize in Rust 1.40. + let username = ih + .info + .as_ref() + .map(|x| x.username.as_ref()) + .and_then(|x| x) + .ok_or(Error::OptionIsNone)?; + + // Perform authentication + let auth_result = mojang_api::server_auth( + &mojang_api::server_hash("", ih.key.unwrap(), der.as_slice()), + username, + ) + .await; + + match auth_result { + Ok(auth) => { + let info = JoinResult { + username: Some(auth.name), + uuid: auth.id, + props: auth.properties, + }; + ih.info = Some(info); + } + Err(e) => return Err(Error::AuthenticationFailed(e)), + } + + finish(ih); + + Ok(()) +} + +fn decrypt_using_rsa(data: &[u8], key: &RSAPrivateKey) -> Result<Vec<u8>, Error> { + let buf = key + .decrypt(PaddingScheme::PKCS1v15, data) + .map_err(|_| Error::BadEncryption)?; + + Ok(buf) +} + +/// Terminates the login process, sending Set Compression (if necessary) +/// and Login Success. +/// +/// Before calling this function, it is expected that: +/// * `info` is set to a valid value +/// * Encryption has been enabled, if necessary +/// * All other login processes have already run +fn finish(ih: &mut InitialHandler) { + assert!(ih.info.is_some()); + assert!(ih.info.as_ref().unwrap().username.is_some()); + + // Enable compression if necessary + let compression_threshold = ih.config.io.compression_threshold; + if compression_threshold > 0 { + enable_compression(ih, compression_threshold); + } + + let info = ih.info.as_ref().unwrap(); + + let uuid_str = info.uuid.to_hyphenated_ref().to_string(); + + // Make sure they're not UUID banned + let (reason, remove_ban) = { + let ban_info = ih.ban_info.read().unwrap(); + let ip_ban = ban_info.uuid_bans.get(&uuid_str); + + if let Some(ban) = ip_ban { + // Expire the ban if it's over. + if let Some(expires) = ban.expires_after { + if expires < SystemTime::now() { + (None, true) + } else { + (Some(Text::from(ban.reason.clone())), false) + } + } else { + (Some(Text::from(ban.reason.clone())), false) + } + } else { + (None, false) + } + }; + + if let Some(reason) = reason { + disconnect_login(ih, reason); + return; + } else if remove_ban { + ih.ban_info.write().unwrap().uuid_bans.remove(&uuid_str); + } + + // Send Login Success + let login_success = LoginSuccess { + uuid: uuid_str, + username: info.username.as_ref().unwrap().to_string(), + }; + send_packet(ih, login_success); + ih.action_queue.push(Action::SetStage(PacketStage::Play)); + ih.action_queue + .push(Action::JoinGame(ih.info.clone().unwrap())); +} + +/// Enables compression, sending the Set Compression +/// packet. +fn enable_compression(ih: &mut InitialHandler, threshold: i32) { + ih.compression_threshold = Some(threshold); + send_packet(ih, SetCompression { threshold }); + ih.action_queue.push(Action::EnableCompression(threshold)); +} + +/// Checks that the initial handler stage matches +/// the expected stage, returning `Err` with a proper +/// error message if not. +fn check_stage(ih: &InitialHandler, expected: Stage, packet_ty: PacketType) -> Result<(), Error> { + if ih.stage != expected { + Err(Error::InvalidPacket(packet_ty, ih.stage)) + } else { + Ok(()) + } +} + +/// Disconnects the initial handler, sending +/// a disconnect packet containing the reason. +fn disconnect_login(ih: &mut InitialHandler, reason: Text) { + let packet = DisconnectLogin { + reason: TextRoot::from(reason).into(), + }; + send_packet(ih, packet); + + ih.action_queue.push(Action::Disconnect); +} + +/// Adds a packet to the internal packet queue. +fn send_packet<P: Packet + 'static>(ih: &mut InitialHandler, packet: P) { + ih.action_queue.push(Action::SendPacket(Box::new(packet))); +} + +#[derive(Error, Debug, PartialEq)] +enum Error { + #[error("invalid packet type {0:?} sent at stage {1:?}")] + InvalidPacket(PacketType, Stage), + #[error("unsupported protocol version {0:?}")] + InvalidProtocol(u32), + #[error("invalid encryption")] + BadEncryption, + #[error("verify tokens do not match")] + VerifyTokenMismatch, + #[error("shared secret length is not correct")] + BadSecretLength, + #[cfg(debug_assertions)] + #[error("authentication failure: {0:?}")] + AuthenticationFailed(mojang_api::Error), + #[cfg(not(debug_assertions))] + #[error("Failed to verify username!")] + AuthenticationFailed(mojang_api::Error), + #[error("received BungeeCord data does not match the specification: {0}")] + BungeeSpecMismatch(String), + #[error("option that should not be None was None")] + /// An Error type than can be used as the error type of using the Try operator on Option + /// types. In rust-core, this is an unstable feature (issue #42327) + OptionIsNone, +} + +/// The stage of an initial handler. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Stage { + AwaitHandshake, + AwaitRequest, + AwaitPing, + AwaitLoginStart, + AwaitEncryptionResponse, + Finished, +} + +#[cfg(test)] +mod tests { + use feather_core::network::cast_packet; + use feather_core::network::packets::{ + Handshake, HandshakeState, LoginSuccess, Ping, Pong, Request, Response, SetCompression, + }; + use feather_core::network::PacketType; + + use crate::PROTOCOL_VERSION; + + use super::*; + use mojang_api::ProfileProperty; + + #[test] + fn extract_bungeecord_data_normal() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\0192.168.1.67\0905c7e4fb96b45139645d123225575e2\0[{\"name\":\"textures\",\"value\":\"textures_value\",\"signature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + assert_eq!( + extract_bungeecord_data(&handshake).unwrap(), + BungeeCordData { + host: "192.168.1.87".to_string(), + client: "192.168.1.67".to_string(), + uuid: Uuid::parse_str("905c7e4fb96b45139645d123225575e2").unwrap(), + properties: vec![ProfileProperty { + name: "textures".to_string(), + value: "textures_value".to_string(), + signature: "textures_signature".to_string(), + }], + } + ); + } + + #[test] + fn extract_bungeecord_data_too_short() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\0192.168.1.67\0905c7e4fb96b45139645d123225575e2" + .to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + assert_eq!( + extract_bungeecord_data(&handshake).err().unwrap(), + Error::BungeeSpecMismatch("Incorrect length".to_string()) + ); + } + + #[test] + fn extract_bungeecord_data_too_long() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\0192.168.1.67\0905c7e4fb96b45139645d123225575e2\0a\0b" + .to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + assert_eq!( + extract_bungeecord_data(&handshake).err().unwrap(), + Error::BungeeSpecMismatch("Incorrect length".to_string()) + ); + } + + #[test] + fn extract_bungeecord_data_localhost_host_ip() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "localhost\0192.168.1.67\0905c7e4fb96b45139645d123225575e2\0[{\"name\":\"textures\",\"value\":\"textures_value\",\"signature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + assert_eq!( + extract_bungeecord_data(&handshake).unwrap(), + BungeeCordData { + host: "localhost".to_string(), + client: "192.168.1.67".to_string(), + uuid: Uuid::parse_str("905c7e4fb96b45139645d123225575e2").unwrap(), + properties: vec![ProfileProperty { + name: "textures".to_string(), + value: "textures_value".to_string(), + signature: "textures_signature".to_string(), + }], + } + ); + } + + #[test] + fn extract_bungeecord_data_localhost_client_ip() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\0localhost\0905c7e4fb96b45139645d123225575e2\0[{\"name\":\"textures\",\"value\":\"textures_value\",\"signature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + assert_eq!( + extract_bungeecord_data(&handshake).unwrap(), + BungeeCordData { + host: "192.168.1.87".to_string(), + client: "localhost".to_string(), + uuid: Uuid::parse_str("905c7e4fb96b45139645d123225575e2").unwrap(), + properties: vec![ProfileProperty { + name: "textures".to_string(), + value: "textures_value".to_string(), + signature: "textures_signature".to_string(), + }], + } + ); + } + + #[test] + fn extract_bungeecord_data_invalid_uuid() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\0192.168.1.67\005c7e4fb9675e2\0[{\"name\":\"textures\",\"value\":\"textures_value\",\"signature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + let error = extract_bungeecord_data(&handshake).err().unwrap(); + if let Error::BungeeSpecMismatch(e) = error { + assert!(e.contains("invalid length")); + } else { + panic!(); + } + } + + #[test] + fn extract_bungeecord_data_invalid_properties() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\0192.168.1.67\0905c7e4fb96b45139645d123225575e2\0[{\"name\":\"textures\",\"value\":\"textures_value\",\"sinature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + let error = extract_bungeecord_data(&handshake).err().unwrap(); + if let Error::BungeeSpecMismatch(e) = error { + assert!(e.contains("missing field `signature`")); + } else { + panic!(); + } + } + + #[test] + fn test_initial_handler_new() { + let mut ih = ih(); + + assert!(ih.actions_to_execute().is_empty()); + } + + #[tokio::test] + async fn test_status_ping() { + let player_count = 24; + let mut ih = ih_with_player_count(player_count); + + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: String::default(), // Unused - server address + server_port: 25565, + next_state: HandshakeState::Status, + }; + ih.handle_packet(Box::new(handshake)).await; + + // Confirm that stage was switched and no other actions were performed + let actions = ih.actions_to_execute(); + assert_eq!(actions.len(), 1); + match actions.first().unwrap() { + Action::SetStage(stage) => assert_eq!(*stage, PacketStage::Status), + _ => panic!(), + } + + let request = Request {}; + ih.handle_packet(Box::new(request)).await; + + let mut actions = ih.actions_to_execute(); + + // Confirm that correct response was received + assert_eq!(actions.len(), 1); + + let response = actions.remove(0); + match response { + Action::SendPacket(response) => { + assert_eq!(response.ty(), PacketType::Response); + + let response = cast_packet::<Response>(response); + let _: serde_json::Value = serde_json::from_str(&response.json_response).unwrap(); + } + _ => panic!(), + } + + // Send ping + let payload = 39842; + let ping = Ping { payload }; + ih.handle_packet(Box::new(ping)).await; + + let mut actions = ih.actions_to_execute(); + + assert_eq!(actions.len(), 2); + let pong = actions.remove(0); + match pong { + Action::SendPacket(pong) => { + assert_eq!(pong.ty(), PacketType::Pong); + let pong = cast_packet::<Pong>(pong); + assert_eq!(pong.payload, payload); + } + _ => panic!(), + } + + let disconnect = actions.remove(0); + match disconnect { + Action::Disconnect => (), + _ => panic!(), + } + } + + #[tokio::test] + async fn test_login_sequence() { + let mut config = Config::default(); + config.server.online_mode = false; + let mut ih = ih_with_config(config.clone()); + + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: String::default(), // Unused - server address + server_port: 25565, + next_state: HandshakeState::Login, + }; + ih.handle_packet(Box::new(handshake)).await; + + let actions = ih.actions_to_execute(); + assert_eq!(actions.len(), 1); + match actions.first().unwrap() { + Action::SetStage(stage) => assert_eq!(*stage, PacketStage::Login), + _ => panic!(), + } + + let username = "test"; + let login_start = LoginStart { + username: String::from(username), + }; + ih.handle_packet(Box::new(login_start)).await; + + let mut actions = ih.actions_to_execute(); + assert_eq!(actions.len(), 5); + + let set_compression = actions.remove(0); + + match set_compression { + Action::SendPacket(set_compression) => { + assert_eq!(set_compression.ty(), PacketType::SetCompression); + + let set_compression = cast_packet::<SetCompression>(set_compression); + assert_eq!(set_compression.threshold, config.io.compression_threshold); + } + _ => panic!(), + } + + let enable_compression = actions.remove(0); + match enable_compression { + Action::EnableCompression(threshold) => { + assert_eq!(threshold, config.io.compression_threshold); + } + _ => panic!(), + } + + let login_success = actions.remove(0); + + match login_success { + Action::SendPacket(login_success) => { + assert_eq!(login_success.ty(), PacketType::LoginSuccess); + + let login_success = cast_packet::<LoginSuccess>(login_success); + assert_eq!(login_success.username, username.to_string()); + } + _ => panic!(), + } + + match actions.remove(0) { + Action::SetStage(stage) => assert_eq!(stage, PacketStage::Play), + _ => panic!(), + } + + let join = actions.remove(0); + match join { + Action::JoinGame(_) => (), + _ => panic!(), + } + } + + fn ih() -> InitialHandler { + InitialHandler::new( + Arc::new(Config::default()), + Arc::new(RwLock::new(BanInfo::default())), + Arc::new(AtomicU32::new(0)), + Arc::new(Some(String::from("test"))), + "127.0.0.1:8080".parse().unwrap(), + ) + } + + fn ih_with_player_count(count: u32) -> InitialHandler { + InitialHandler::new( + Arc::new(Config::default()), + Arc::new(RwLock::new(BanInfo::default())), + Arc::new(AtomicU32::new(count)), + Arc::new(Some(String::from("test"))), + "127.0.0.1:8080".parse().unwrap(), + ) + } + + fn ih_with_config(config: Config) -> InitialHandler { + InitialHandler::new( + Arc::new(config), + Arc::new(RwLock::new(BanInfo::default())), + Arc::new(AtomicU32::new(0)), + Arc::new(Some(String::from("test"))), + "127.0.0.1:8080".parse().unwrap(), + ) + } +} diff --git a/feather/old/server/network/src/lib.rs b/feather/old/server/network/src/lib.rs new file mode 100644 index 000000000..daafe779e --- /dev/null +++ b/feather/old/server/network/src/lib.rs @@ -0,0 +1,148 @@ +#![forbid(unsafe_code)] + +//! The networking implementation for the server, based on async/await +//! and Tokio. Contains a listener task which accepts new connections +//! and a worker task for each client which reads and writes packets. + +pub const PROTOCOL_VERSION: u32 = 404; +pub const SERVER_VERSION: &str = "Feather 1.13.2"; + +#[macro_use] +extern crate feather_core; + +use derivative::Derivative; +use feather_core::anvil::player::PlayerData; +use feather_core::util::Position; +use feather_server_types::{ + Config, PacketBuffers, ServerToWorkerMessage, Uuid, WorkerToServerMessage, WrappedBanInfo, +}; +use fecs::Entity; +use once_cell::sync::Lazy; +use parking_lot::Mutex; +use std::net::SocketAddr; +use std::sync::atomic::AtomicU32; +use std::sync::Arc; +use tokio::net::TcpListener; + +mod initial_handler; +mod listener; +mod worker; + +#[derive(Debug)] +#[allow(clippy::large_enum_variant)] +pub enum ListenerToServerMessage { + /// Notifies the server thread that a new client connected. + /// + /// This message is sent after initial handling completes. + NewClient(NewClientInfo), + /// Requests that the server create an empty `Entity` and send + /// it to the listener. This entity will later be used as a player. + RequestEntity, + /// Tells the server that a requested entity is no longer needed + /// and may be deleted. + /// + /// This typically happens when a connection comes in the form + /// of a status ping, where the entity is no longer needed + /// but has never served any purpose. + DeleteEntity(Entity), +} + +#[derive(Debug)] +pub enum ServerToListenerMessage { + /// Sends an entity to the listener as a response + /// to `ListenerToServerMessage::RequestEntity`. + Entity(Entity), +} + +#[derive(Derivative)] +#[derivative(Debug)] +pub struct NewClientInfo { + pub ip: SocketAddr, + pub username: String, + pub profile: Vec<mojang_api::ProfileProperty>, + pub uuid: Uuid, + pub data: PlayerData, + pub position: Position, + + #[derivative(Debug = "ignore")] + pub sender: flume::Sender<ServerToWorkerMessage>, + #[derivative(Debug = "ignore")] + pub receiver: flume::Receiver<WorkerToServerMessage>, + + pub entity: Entity, +} + +pub struct NetworkIoManager { + pub rx: Mutex<flume::Receiver<ListenerToServerMessage>>, + pub tx: flume::Sender<ServerToListenerMessage>, + /// Used for testing + pub listener_tx: flume::Sender<ListenerToServerMessage>, +} + +impl NetworkIoManager { + /// Starts a new IO listener. + pub fn start( + listener: TcpListener, + config: Arc<Config>, + ban_info: WrappedBanInfo, + player_count: Arc<AtomicU32>, + server_icon: Arc<Option<String>>, + packet_buffers: Arc<PacketBuffers>, + ) -> Self { + let (listener_tx, rx) = flume::bounded(16); + let (tx, listener_rx) = flume::bounded(16); + + let future = run_listener( + listener, + listener_tx.clone(), + listener_rx, + (config, ban_info), + player_count, + server_icon, + packet_buffers, + ); + + if cfg!(test) { + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.spawn(future); + } else { + tokio::spawn(future); + } + + Self { + rx: Mutex::new(rx), + tx, + listener_tx, + } + } +} + +/// Initializes certain static variables. +pub fn init() { + Lazy::force(&initial_handler::RSA_KEY); +} + +async fn run_listener( + listener: TcpListener, + tx: flume::Sender<ListenerToServerMessage>, + rx: flume::Receiver<ServerToListenerMessage>, + config_bans: (Arc<Config>, WrappedBanInfo), + player_count: Arc<AtomicU32>, + server_icon: Arc<Option<String>>, + packet_buffers: Arc<PacketBuffers>, +) { + if let Err(e) = listener::run_listener( + listener, + tx, + rx, + config_bans, + player_count, + server_icon, + packet_buffers, + ) + .await + { + log::error!("An error occurred while binding to socket: {:?}", e); + std::process::exit(1); + } +} diff --git a/feather/old/server/network/src/listener.rs b/feather/old/server/network/src/listener.rs new file mode 100644 index 000000000..e88daaf98 --- /dev/null +++ b/feather/old/server/network/src/listener.rs @@ -0,0 +1,51 @@ +//! Listener Tokio task. +//! +//! This task listens on a `TcpListener` and accepts +//! connections, spawning worker tasks to handle them,4. + +use crate::worker::run_worker; +use crate::{ListenerToServerMessage, ServerToListenerMessage}; +use feather_server_types::{Config, PacketBuffers, WrappedBanInfo}; + +use std::sync::atomic::AtomicU32; +use std::sync::Arc; +use tokio::io; +use tokio::net::TcpListener; +use tokio::sync::Mutex; + +pub async fn run_listener( + mut listener: TcpListener, + tx: flume::Sender<ListenerToServerMessage>, + rx: flume::Receiver<ServerToListenerMessage>, + config_bans: (Arc<Config>, WrappedBanInfo), + player_count: Arc<AtomicU32>, + server_icon: Arc<Option<String>>, + packet_buffers: Arc<PacketBuffers>, +) -> Result<(), io::Error> { + let rx = Arc::new(Mutex::new(rx)); + + loop { + let (stream, ip) = match listener.accept().await { + Ok(res) => res, + Err(e) => { + log::info!("Failed to accept connection: {}", e); + continue; + } + }; + + log::info!("Connection received from {}", ip); + + tokio::spawn(run_worker( + stream, + ip, + tx.clone(), + Arc::clone(&rx), + Arc::clone(&config_bans.0), + Arc::clone(&config_bans.1), + Arc::clone(&player_count), + Arc::clone(&server_icon), + Arc::clone(&packet_buffers), + )); + tokio::task::yield_now().await; + } +} diff --git a/feather/old/server/network/src/worker.rs b/feather/old/server/network/src/worker.rs new file mode 100644 index 000000000..65a5fcab1 --- /dev/null +++ b/feather/old/server/network/src/worker.rs @@ -0,0 +1,261 @@ +//! Worker Tokio task. +//! +//! This is responsible for handling connections by +//! both sending and receiving packets. +//! +//! Packet send requests are sent over a channel from the server threads +//! to the worker for any given client. + +use crate::initial_handler::{Action, InitialHandler}; +use crate::{ListenerToServerMessage, NewClientInfo, ServerToListenerMessage}; +use feather_core::anvil::entity::{AnimalData, BaseEntityData}; +use feather_core::anvil::player::PlayerData; +use feather_core::network::{MinecraftCodec, Packet, PacketDirection}; +use feather_core::util::{Position, Vec3d}; +use feather_server_types::{ + BanInfo, Config, PacketBuffers, ServerToWorkerMessage, Uuid, WorkerToServerMessage, +}; +use fecs::Entity; +use futures::future::Either; +use futures::SinkExt; +use futures::StreamExt; +use std::net::SocketAddr; +use std::path::Path; +use std::sync::atomic::AtomicU32; +use std::sync::Arc; +use std::sync::RwLock; +use tokio::net::TcpStream; +use tokio::sync::Mutex; +use tokio_util::codec::Framed; + +struct Worker { + framed: Framed<TcpStream, MinecraftCodec>, + config: Arc<Config>, + ip: SocketAddr, + /// The listener's sender to send the initial `NewClient` message + /// to the server. Also used to request an entity for the player. + listener_tx: flume::Sender<ListenerToServerMessage>, + /// Packet buffers to which we write packets received from the client. + packet_buffers: Arc<PacketBuffers>, + /// The channel which will be used by the server thread + /// to send messages to `rx`. + server_tx: flume::Sender<ServerToWorkerMessage>, + /// Channel to receive messages from the server, linked to `server_tx`. + rx: flume::Receiver<ServerToWorkerMessage>, + /// The channel which will be used by the server thread + /// to receive messages from the worker. + server_rx: Option<flume::Receiver<WorkerToServerMessage>>, + /// Channel to send messages to the server, linked to `server_rx`. + tx: flume::Sender<WorkerToServerMessage>, + /// Initial handler, set to `None` after the player has completed + /// the login process. + initial_handler: Option<InitialHandler>, + /// The entity for the player on the server thread. + entity: Entity, +} + +/// Runs a worker task for the given client. +#[allow(clippy::too_many_arguments)] +pub async fn run_worker( + stream: TcpStream, + ip: SocketAddr, + listener_tx: flume::Sender<ListenerToServerMessage>, + listener_rx: Arc<Mutex<flume::Receiver<ServerToListenerMessage>>>, + config: Arc<Config>, + ban_info: Arc<RwLock<BanInfo>>, + player_count: Arc<AtomicU32>, + server_icon: Arc<Option<String>>, + packet_buffers: Arc<PacketBuffers>, +) { + let (server_tx, rx) = flume::unbounded(); + let (tx, server_rx) = flume::unbounded(); + + let initial_handler = Some(InitialHandler::new( + Arc::clone(&config), + Arc::clone(&ban_info), + Arc::clone(&player_count), + Arc::clone(&server_icon), + ip, + )); + + let codec = MinecraftCodec::new(PacketDirection::Serverbound); + let framed = Framed::new(stream, codec); + + let entity = request_entity(&listener_tx, &mut *listener_rx.lock().await).await; + + let mut worker = Worker { + framed, + ip, + listener_tx, + packet_buffers, + server_tx, + rx, + server_rx: Some(server_rx), + tx, + initial_handler, + entity, + config, + }; + + let msg = match run_worker_impl(&mut worker).await { + Ok(()) => String::from("client disconnected"), + Err(e) => format!("{}", e), + }; + + let _ = worker + .tx + .send(WorkerToServerMessage::NotifyDisconnected { reason: msg }); + + // If server is not aware of connection (and thus + // will not receive the above message), instruct it + // to delete the entity. Otherwise, it will delete it + // through the message above. + if worker.server_rx.is_some() { + let _ = worker + .listener_tx + .send(ListenerToServerMessage::DeleteEntity(worker.entity)); + } +} + +async fn request_entity( + listener_tx: &flume::Sender<ListenerToServerMessage>, + listener_rx: &mut flume::Receiver<ServerToListenerMessage>, +) -> Entity { + let _ = listener_tx.send(ListenerToServerMessage::RequestEntity); + + let recv = listener_rx.next().await.expect("server disconnected"); + + match recv { + ServerToListenerMessage::Entity(entity) => entity, + } +} + +async fn run_worker_impl(worker: &mut Worker) -> anyhow::Result<()> { + loop { + let received_message = worker.rx.next(); + let received_packet = worker.framed.next(); + + let select = futures::future::select(received_message, received_packet); + + match select.await { + Either::Left((msg, _)) => { + if let Some(msg) = msg { + handle_server_to_worker_message(worker, msg).await?; + } + } + Either::Right((packet_res, _)) => { + let packet_res = + packet_res.ok_or_else(|| anyhow::anyhow!("client disconnected"))?; + + let packet = packet_res?; + + handle_packet(worker, packet).await?; + } + } + + tokio::task::yield_now().await; + } +} + +async fn handle_server_to_worker_message( + worker: &mut Worker, + msg: ServerToWorkerMessage, +) -> anyhow::Result<()> { + match msg { + ServerToWorkerMessage::SendPacket(packet) => worker.framed.send(packet).await?, + ServerToWorkerMessage::Disconnect => anyhow::bail!("server requested disconnect"), + } + + Ok(()) +} + +async fn handle_packet(worker: &mut Worker, packet: Box<dyn Packet>) -> anyhow::Result<()> { + if let Some(ref mut ih) = worker.initial_handler { + ih.handle_packet(packet).await; + + handle_ih_actions(worker).await?; + } else { + worker.packet_buffers.push(worker.entity, packet); + } + + Ok(()) +} + +async fn handle_ih_actions(worker: &mut Worker) -> anyhow::Result<()> { + for action in worker + .initial_handler + .as_mut() + .unwrap() + .actions_to_execute() + { + match action { + Action::SendPacket(packet) => worker.framed.send(packet).await?, + Action::EnableCompression(threshold) => worker + .framed + .codec_mut() + .enable_compression(threshold as usize), + Action::EnableEncryption(key) => worker.framed.codec_mut().enable_encryption(key), + Action::Disconnect => anyhow::bail!("initial handler requested disconnect"), + Action::SetStage(stage) => worker.framed.codec_mut().set_stage(stage), + Action::JoinGame(info) => { + let data = load_player_data(&worker.config, info.uuid).await?; + let position = data.animal.base.read_position()?; + let info = NewClientInfo { + ip: worker.ip, + username: info.username.unwrap_or_else(|| String::from("undefined")), + profile: info.props, + uuid: info.uuid, + data, + position, + sender: worker.server_tx.clone(), + receiver: worker.server_rx.take().unwrap(), + entity: worker.entity, + }; + + let _ = worker + .listener_tx + .send(ListenerToServerMessage::NewClient(info)); + + worker.initial_handler = None; + return Ok(()); + } + } + } + + Ok(()) +} + +const DEFAULT_POSITION: Position = position!(0.0, 70.0, 0.0); // TODO: better calculation + +async fn load_player_data(config: &Config, uuid: Uuid) -> Result<PlayerData, anyhow::Error> { + log::debug!("Loading player data for UUID {}", uuid); + match feather_core::anvil::player::load_player_data(Path::new(&config.world.name), uuid).await { + Ok(data) => Ok(data), + Err(e) => { + log::debug!( + "Failed to load player data for {} ({}); creating default data", + uuid, + e, + ); + + let data = PlayerData { + animal: AnimalData::new( + BaseEntityData::new(DEFAULT_POSITION, Vec3d::broadcast(0.0)), + 20.0, + ), + gamemode: config.server.default_gamemode.id() as i32, + inventory: vec![], + held_item: 0, + }; + + feather_core::anvil::player::save_player_data( + Path::new(&config.world.name), + uuid, + &data, + ) + .await?; + + Ok(data) + } + } +} diff --git a/feather/old/server/packet_buffer/Cargo.toml b/feather/old/server/packet_buffer/Cargo.toml new file mode 100644 index 000000000..94c728a15 --- /dev/null +++ b/feather/old/server/packet_buffer/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "feather-server-packet-buffer" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +smallvec = "1.4" +parking_lot = "0.10" +strum = "0.18" +num-traits = "0.2" +ahash = "0.3" +once_cell = "1.3" +indexmap = "1.3" +crossbeam = "0.7" diff --git a/feather/old/server/packet_buffer/src/lib.rs b/feather/old/server/packet_buffer/src/lib.rs new file mode 100644 index 000000000..dcff47b84 --- /dev/null +++ b/feather/old/server/packet_buffer/src/lib.rs @@ -0,0 +1,387 @@ +#![forbid(unsafe_code)] + +//! Two implementations of a packet buffer. +//! +//! A packet buffer is used to hold the packets of a given type received +//! from players. When a packet is received, the IO threads +//! push the packet onto the buffer, and systems on the server +//! thread poll these packets out of the buffer. +//! +//! We provide two implementations, optimized for different cases: +//! * A buffer based on a large array, with two slots for each player. +//! This buffer works well for cases when packets of this type are received +//! very often, such as position updates. +//! * A buffer based on `crossbeam-channel`, best for cases where fewer +//! packets of this type are received. +//! +//! The former is not yet implemented, and we are currently using a `DashMap<Entity, SmallVec<[Box<dyn Packet>; 4]>>`. + +use ahash::AHashMap; +use feather_core::network::{cast_packet, Packet, PacketType}; +use fecs::Entity; +use indexmap::set::IndexSet; +use num_traits::ToPrimitive; +use once_cell::sync::Lazy; +use parking_lot::{Mutex, RwLock}; +use smallvec::SmallVec; +use std::iter; +use strum::IntoEnumIterator; + +/// The global packet store, storing packet buffers for packets of each type. +pub struct PacketBuffers { + /// Packet buffers, indexed by the `ToPrimitive` implementation + /// of `PacketType`. + buffers: Vec<PacketBuffer>, +} + +static USE_MAP_FOR: Lazy<IndexSet<PacketType>> = Lazy::new(|| { + indexmap::indexset![ + PacketType::PlayerPosition, + PacketType::PlayerPositionAndLookServerbound, + PacketType::PlayerLook, + ] +}); + +impl Default for PacketBuffers { + fn default() -> Self { + Self::new() + } +} + +impl PacketBuffers { + /// Creates a new packet store with buffers allocated for all packet types. + pub fn new() -> Self { + Self { + buffers: PacketType::iter() + .map(|ty| { + if USE_MAP_FOR.contains(&ty) { + PacketBuffer::Map(MapBuffer::default()) + } else { + PacketBuffer::Channel(ChannelBuffer::new()) + } + }) + .collect(), + } + } + + /// Pushes a received packet onto the packet buffer for the packet's + /// type. + pub fn push(&self, entity: Entity, packet: Box<dyn Packet>) { + let index = packet.ty().to_usize().unwrap(); + + self.buffers[index].push(entity, packet); + } + + /// Returns an iterator over packets received with type `T`. + /// + /// # Panics + /// Panics if the underlying buffer is not a `ChannelBuffer`. + /// `received_for()` should be used instead if using an `ArrayBuffer`. + pub fn received<'a, T>(&'a self) -> impl Iterator<Item = (Entity, T)> + 'a + where + T: Packet, + { + let ty = T::ty_sized(); + + let index = ty.to_usize().unwrap(); + + self.buffers[index] + .poll() + .map(|(player, boxed)| (player, cast_packet(boxed))) + } + + /// Returns an iterator over packets of type `T` received by the given player. + /// + /// # Panics + /// Panics if the underlying buffer for this packet type is not a `MapBuffer` or an + /// `ArrayBuffer`. Use `received` instead. + pub fn received_for<T>(&self, player: Entity) -> impl Iterator<Item = T> + where + T: Packet, + { + let ty = T::ty_sized(); + + let index = ty.to_usize().unwrap(); + + self.buffers[index] + .received_for(player) + .map(|boxed| cast_packet(boxed)) + } +} + +/// One of two packet buffer implementations. +pub enum PacketBuffer { + Channel(ChannelBuffer), + Map(MapBuffer), +} + +impl PacketBuffer { + /// Polls this buffer for newly received packets. + /// + /// # Panics + /// Panics if the underlying buffer is not a `ChannelBuffer`. + /// `received_for()` should be used instead if using an `ArrayBuffer`. + pub fn poll<'a>(&'a self) -> impl Iterator<Item = (Entity, Box<dyn Packet>)> + 'a { + match self { + PacketBuffer::Channel(chan) => chan.poll(), + PacketBuffer::Map(_) => panic!("cannot poll a map-based packet buffer"), + } + } + + /// Pushes a packet onto this buffer. + pub fn push(&self, player: Entity, packet: Box<dyn Packet>) { + match self { + PacketBuffer::Channel(chan) => chan.push(player, packet), + PacketBuffer::Map(map) => map.push(player, packet), + } + } + + /// Drains packets received by the given player. + /// + /// # Panics + /// Panics if the underlying buffer is not a `MapBuffer` or an `ArrayBuffer`. + pub fn received_for(&self, player: Entity) -> impl Iterator<Item = Box<dyn Packet>> { + match self { + PacketBuffer::Map(map) => map.received_for(player), + PacketBuffer::Channel(_) => { + panic!("cannot use received_for for a channel-based packet buffer") + } + } + } +} + +/// A packet buffer based on an MPMC channel. Best for packet types +/// which are received less frequently. +pub struct ChannelBuffer { + sender: crossbeam::Sender<(Entity, Box<dyn Packet>)>, + receiver: crossbeam::Receiver<(Entity, Box<dyn Packet>)>, +} + +impl ChannelBuffer { + fn new() -> Self { + let (sender, receiver) = crossbeam::unbounded(); + Self { sender, receiver } + } + + fn push(&self, player: Entity, packet: Box<dyn Packet>) { + let _ = self.sender.send((player, packet)); + } + + fn poll<'a>(&'a self) -> impl Iterator<Item = (Entity, Box<dyn Packet>)> + 'a { + self.receiver.try_iter() + } +} + +enum Either<A, B> { + Left(A), + Right(B), +} + +impl<A, B, I> Iterator for Either<A, B> +where + A: Iterator<Item = I>, + B: Iterator<Item = I>, +{ + type Item = I; + + fn next(&mut self) -> Option<Self::Item> { + match self { + Either::Left(a) => a.next(), + Either::Right(b) => b.next(), + } + } +} + +type MapBufferVec = SmallVec<[Box<dyn Packet>; 2]>; +type MapBufferInner = AHashMap<Entity, Mutex<MapBufferVec>>; + +#[derive(Default)] +pub struct MapBuffer(RwLock<MapBufferInner>); + +impl MapBuffer { + fn push(&self, player: Entity, packet: Box<dyn Packet>) { + let guard = self.0.read(); + if let Some(vec) = guard.get(&player) { + vec.lock().push(packet); + } else { + drop(guard); + self.0 + .write() + .insert(player, Mutex::new(std::iter::once(packet).collect())); + } + } + + fn received_for(&self, player: Entity) -> impl Iterator<Item = Box<dyn Packet>> { + let map_guard = self.0.read(); + + if let Some(vec) = map_guard.get(&player) { + let vec = vec + .lock() + .drain(..) + .collect::<SmallVec<[Box<dyn Packet>; 2]>>(); + + Either::Left(vec.into_iter()) + } else { + Either::Right(iter::empty()) + } + } +} + +/* TODO: audit this implementation. +/// A packet buffer using an array of slots. +pub struct ArrayBuffer { + /// Internal array of length `2 * (num_players rounded up to the next power of two)`. + /// Packets received for a player with index `i` will + /// be located at `array[i]` and `array[n + i]`, where `n` is the number + /// of players rounded up to the next power of two. + /// + /// Note that this array is type-erased; we do this as an optimization + /// to store the packets directly in the array instead of going through a + /// `Box`. + array: RwLock<NonNull<u8>>, + /// Memory layout of `array`. + array_layout: Mutex<Layout>, + /// Layout of a single packet. + single_packet: Layout, + /// Number of players for which this buffer has capacity. + max_players: AtomicUsize, + /// Pointer to the `None` value for the packet. + none_ptr: NonNull<u8>, + /// Length of the `None` value for the packet. + none_len: usize, +} + +impl ArrayBuffer { + /// Creates a new, empty `ArrayBuffer` for packets of type `T`. + pub fn new<T>() -> Self { + let starting_n = 8; + + let none = Box::new(Option::<T>::None); + let none_ptr = NonNull::new(Box::into_raw(none).cast()).expect("box has null pointer"); + + let (array, array_layout) = + unsafe { Self::allocate_for(Layout::new::<Option<T>>(), starting_n, none_ptr) }; + + Self { + array: RwLock::new(array), + array_layout: Mutex::new(array_layout), + single_packet: Layout::new::<Option<T>>(), + max_players: AtomicUsize::new(starting_n), + none_ptr, + none_len: std::mem::size_of::<Option<T>>(), + } + } + + /// Returns the number of players supported by this buffer. + pub fn max_players(&self) -> usize { + self.max_players.load(Ordering::Acquire) + } + + /// Extends this array buffer to support at least `n` __more__ players. + pub fn reserve(&self, extra: usize) { + let mut old_array = self.array.write(); + let mut old_layout = self.array_layout.lock(); + + let current_max = self.max_players.load(Ordering::Acquire); + let new_max = (current_max + extra).next_power_of_two(); + + let (new_array, new_layout) = + unsafe { Self::allocate_for(self.single_packet, new_max, self.none_ptr) }; + + assert!(new_layout.size() > old_layout.size()); + assert_eq!(new_layout.size() % 2, 0); + assert_eq!(old_layout.size() % 2, 0); + + // copy existing packets to new array + unsafe { + std::ptr::copy_nonoverlapping( + old_array.as_ptr(), + new_array.as_ptr(), + old_layout.size() / 2, + ); + std::ptr::copy_nonoverlapping( + old_array.as_ptr().offset((old_layout.size() / 2) as isize), + new_array.as_ptr().offset((new_layout.size() / 2) as isize), + old_layout.size() / 2, + ); + } + + *old_array = new_array; + *old_layout = new_layout; + self.max_players.store(new_max, Ordering::Release); + } + + unsafe fn allocate_for( + single_packet: Layout, + max_players: usize, + none_ptr: NonNull<u8>, + ) -> (NonNull<u8>, Layout) { + let new_layout = single_packet + .repeat(max_players * 2) + .map(|(layout, offset)| { + assert_eq!(offset, single_packet.size()); + layout + }) + .expect("invalid packet buffer layout"); + + let new_array = + NonNull::new(std::alloc::alloc(new_layout)).expect("allocator returned null pointer"); + + // fill array with `None` values + for i in 0..max_players * 2 { + let ptr = new_array + .as_ptr() + .offset((i * single_packet.size()) as isize); + std::ptr::copy_nonoverlapping(none_ptr.as_ptr(), ptr, single_packet.size()); + } + + (new_array, new_layout) + } +} +*/ + +#[cfg(test)] +mod tests { + use super::*; + use feather_core::network::packets::Request; + use fecs::{EntityBuilder, World}; + + #[test] + fn map_buffer() { + let buffer = MapBuffer::default(); + + let mut world = World::new(); + let entity = EntityBuilder::new().build().spawn_in(&mut world); + + dbg!(); + buffer.push(entity, Box::new(Request {})); + dbg!(); + + let mut received = buffer.received_for(entity).collect::<Vec<_>>(); + dbg!(); + + assert_eq!(received.len(), 1); + + let first = received.remove(0); + let _ = cast_packet::<Request>(first); + } + + #[test] + fn channel_buffer() { + let buffer = ChannelBuffer::new(); + + let mut world = World::new(); + let entity = EntityBuilder::new().build().spawn_in(&mut world); + + buffer.push(entity, Box::new(Request {})); + + let mut received = buffer.poll().collect::<Vec<_>>(); + + assert_eq!(received.len(), 1); + + let (rentity, first) = received.remove(0); + let _ = cast_packet::<Request>(first); + + assert_eq!(entity, rentity); + } +} diff --git a/feather/old/server/physics/Cargo.toml b/feather/old/server/physics/Cargo.toml new file mode 100644 index 000000000..67f295a9e --- /dev/null +++ b/feather/old/server/physics/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "feather-server-physics" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +nalgebra = "0.20" +nalgebra-glm = "0.6" +ncollide3d = "0.22" +heapless = "0.5" +smallvec = "1.4" +bitflags = "1.2" +parking_lot = "0.10" diff --git a/feather/old/server/physics/src/block_bboxes.rs b/feather/old/server/physics/src/block_bboxes.rs new file mode 100644 index 000000000..0a51842a4 --- /dev/null +++ b/feather/old/server/physics/src/block_bboxes.rs @@ -0,0 +1,25 @@ +//! Bounding boxes for every non-cubic block. + +use feather_core::blocks::{BlockId, SimplifiedBlockKind}; +use nalgebra::Point3; +use ncollide3d::bounding_volume::AABB; + +/// Returns the bounding box for the given block. +/// +/// Non-solid blocks have no bounding box, +/// and the bounding box for a non-solid block +/// is undefined. +pub fn bbox_for_block(block: BlockId) -> AABB<f64> { + if matches!( + block.simplified_kind(), + SimplifiedBlockKind::Bed | SimplifiedBlockKind::Slab + ) { + bbox(1.0, 0.5, 1.0) + } else { + bbox(1.0, 1.0, 1.0) + } +} + +fn bbox(x: f64, y: f64, z: f64) -> AABB<f64> { + AABB::new(Point3::from([0.0, 0.0, 0.0]), Point3::from([x, y, z])) +} diff --git a/feather/old/server/physics/src/entity.rs b/feather/old/server/physics/src/entity.rs new file mode 100644 index 000000000..98a7571b3 --- /dev/null +++ b/feather/old/server/physics/src/entity.rs @@ -0,0 +1,138 @@ +//! Module for performing entity physics, including velocity, drag +//! and position updates each tick. + +use crate::{block_impacted_by_ray, blocks_intersecting_bbox, Side}; +use feather_core::blocks::BlockKind; +use feather_core::position; +use feather_core::util::Position; +use feather_server_types::{AABBExt, EntityLandEvent, Game, Physics, Velocity}; +use fecs::{IntoQuery, Read, World, Write}; +use parking_lot::Mutex; + +/// System for updating all entities' positions and velocities +/// each tick. +#[fecs::system] +pub fn entity_physics(game: &mut Game, world: &mut World) { + // Go through entities and update their positions according + // to their velocities. + let land_events = Mutex::new(vec![]); + + let query = <(Write<Position>, Write<Velocity>, Read<Physics>)>::query(); + query.par_entities_for_each_mut( + world.inner_mut(), + |(entity, (mut position, mut velocity, physics))| { + let mut pending_position = *position + velocity.0; + + // Check for blocks along path between old position and pending position. + // This prevents entities from flying through blocks when their + // velocity is sufficiently high. + let origin = (*position).into(); + let direction = (pending_position - *position).into(); + let distance_squared = pending_position.distance_squared_to(*position); + + if let Some(impacted) = block_impacted_by_ray(game, origin, direction, distance_squared) + { + // Set velocities along correct axis to 0 and then set position + // to just before the bbox would have impacted the block. + let face = impacted.face; + let impact = impacted.pos; + + if face.contains(Side::EAST) || face.contains(Side::WEST) { + velocity.0.x = 0.0; + pending_position.x = impact.x + physics.bbox.size().x * face.as_vector().x; + } + if face.contains(Side::NORTH) || face.contains(Side::SOUTH) { + velocity.0.z = 0.0; + pending_position.z = impact.z + physics.bbox.size().z * face.as_vector().z; + } + if face.contains(Side::TOP) || face.contains(Side::BOTTOM) { + velocity.0.y = 0.0; + pending_position.y = impact.y + physics.bbox.size().y * face.as_vector().y; + } + if face.contains(Side::TOP) { + pending_position.on_ground = true; + } + } + + // Check for blocks around the bbox and apply offset + // to position to stop the bbox from intersecting blocks. + let intersect = + blocks_intersecting_bbox(game, *position, pending_position, &physics.bbox); + intersect.apply_to(&mut pending_position); + + if intersect.x_affected() { + velocity.0.x = 0.0; + } + + if intersect.y_affected() { + velocity.0.y = 0.0; + } + + if intersect.z_affected() { + velocity.0.z = 0.0; + } + + // Delete entity if it has gone into unloaded chunks. + let block_at_pos = match game.block_at(pending_position.block()) { + Some(block) => block, + None => { + // TODO: delete entity + return; + } + }; + + // Set on ground status. + pending_position.on_ground = match game.block_at( + position!( + pending_position.x, + pending_position.y - physics.bbox.size().y / 2.0 - 0.01, + pending_position.z + ) + .block(), + ) { + Some(block) => block.is_solid(), + None => false, + }; + if pending_position.on_ground && !position.on_ground { + land_events.lock().push(EntityLandEvent { + entity, + pos: pending_position, + }); + } + + // Apply drag and gravity. + + // In water and lava, gravity is four times less, and velocity is multiplied by a special drag force. + let liquid_drag = 0.8; + match block_at_pos.kind() { + BlockKind::Water => { + velocity.0 *= liquid_drag; + velocity.0.y += physics.gravity / 4.0; + } + BlockKind::Lava => { + velocity.0 *= liquid_drag - 0.3; + velocity.0.y += physics.gravity / 4.0; + } + _ => { + let slip_multiplier = physics.slip_multiplier; + if pending_position.on_ground { + velocity.0.x *= slip_multiplier; + velocity.0.z *= slip_multiplier; + } else { + velocity.0.y = physics.drag * velocity.0.y + physics.gravity; + velocity.0.x *= physics.drag; + velocity.0.z *= physics.drag; + } + } + } + + // Set new position. + *position = pending_position; + }, + ); + + // Trigger land events. + for event in land_events.into_inner() { + game.handle(world, event); + } +} diff --git a/feather/old/server/physics/src/lib.rs b/feather/old/server/physics/src/lib.rs new file mode 100644 index 000000000..6ba04e530 --- /dev/null +++ b/feather/old/server/physics/src/lib.rs @@ -0,0 +1,10 @@ +//! Module for calculating physics interactions. + +extern crate nalgebra_glm as glm; + +mod block_bboxes; +mod entity; +mod math; + +pub use entity::entity_physics; +pub use math::*; diff --git a/server/src/physics/math.rs b/feather/old/server/physics/src/math.rs similarity index 83% rename from server/src/physics/math.rs rename to feather/old/server/physics/src/math.rs index 18dcfc116..6f5494391 100644 --- a/server/src/physics/math.rs +++ b/feather/old/server/physics/src/math.rs @@ -1,12 +1,12 @@ //! A bunch of math-related functions for use with //! the physics system. -use crate::entity::{ChunkEntities, PositionComponent}; -use crate::physics::block_bboxes::bbox_for_block; -use crate::physics::AABBExt; -use feather_blocks::Block; -use feather_core::world::{BlockPosition, ChunkMap, Position}; -use feather_core::{BlockExt, ChunkPosition}; +use crate::block_bboxes::bbox_for_block; +use bitflags::bitflags; +use feather_core::blocks::BlockId; +use feather_core::util::{BlockPosition, Position}; +use feather_server_types::{AABBExt, Game}; + use glm::{vec3, DVec3, Vec3}; use heapless::consts::*; use nalgebra::{Isometry3, Point3}; @@ -15,8 +15,6 @@ use ncollide3d::query; use ncollide3d::query::{Ray, RayCast}; use ncollide3d::shape::{Compound, Cuboid, ShapeHandle}; use smallvec::SmallVec; -use specs::storage::GenericReadStorage; -use specs::Entity; use std::cmp::Ordering; use std::f64::INFINITY; @@ -89,7 +87,7 @@ pub struct RayImpact { /// Traces up to `max_distance` before returning `None` /// if no block was found. pub fn block_impacted_by_ray( - chunk_map: &ChunkMap, + game: &Game, origin: DVec3, ray: DVec3, max_distance_squared: f64, @@ -164,29 +162,26 @@ pub fn block_impacted_by_ray( _ => (), } - let mut current_pos = Position::from(origin).block_pos(); + let mut current_pos = Position::from(origin).block(); while dist_traveled.magnitude_squared() < max_distance_squared { - if let Some(block) = chunk_map.block_at(current_pos) { + if let Some(block) = game.block_at(current_pos) { if block.is_solid() { // Calculate world-space position of // impact using `ncollide`. let ray = Ray::new(Point3::from(origin), direction); - let shape = block_shape(&block); + let shape = block_shape(block); let isometry = block_isometry(current_pos); - let impact = match shape.toi_and_normal_with_ray(&isometry, &ray, true) { - Some(toi) => toi, - None => continue, - }; - - let pos = Position::from(origin + impact.toi * direction); + if let Some(impact) = shape.toi_and_normal_with_ray(&isometry, &ray, 1000.0, true) { + let pos = Position::from(origin + impact.toi * direction); - return Some(RayImpact { - block: current_pos, - pos, - face, - }); + return Some(RayImpact { + block: current_pos, + pos, + face, + }); + } } } else { // Traveled outside loaded chunks - no blocks found @@ -229,48 +224,6 @@ pub fn block_impacted_by_ray( None } -/// Returns all entities within the given distance of the given -/// position. -/// -/// # Panics -/// Panics if either coordinate of the radius is negative. -pub fn nearby_entities<S>( - chunk_entities: &ChunkEntities, - positions: &S, - pos: Position, - radius: DVec3, -) -> SmallVec<[Entity; 4]> -where - S: GenericReadStorage<Component = PositionComponent>, -{ - assert!(radius.x >= 0.0); - assert!(radius.y >= 0.0); - assert!(radius.z >= 0.0); - - let mut result = smallvec![]; - - for chunk in chunks_within_distance(pos, radius) { - let entities = chunk_entities.entities_in_chunk(chunk); - entities - .iter() - .copied() - .filter(|e| { - let epos = positions.get(*e); - if let Some(epos) = epos { - let epos = epos.current; - (epos.x - pos.x).abs() <= radius.x - && (epos.y - pos.y).abs() <= radius.y - && (epos.z - pos.z).abs() <= radius.z - } else { - false - } - }) - .for_each(|e| result.push(e)); - } - - result -} - /// The offsets which need to be applied to a position /// to prevent it from intersecting with a block. #[derive(Debug, Clone)] @@ -318,7 +271,7 @@ impl BlockIntersect { /// than 1 are not supported. If the bounding box's size /// is more than 1, this function will panic. pub fn blocks_intersecting_bbox( - chunk_map: &ChunkMap, + game: &Game, mut from: Position, mut dest: Position, bbox: &AABB<f64>, @@ -345,20 +298,20 @@ pub fn blocks_intersecting_bbox( let axis = [(1, 1), (1, -1), (0, 1), (0, -1), (2, 1), (2, -1)]; // Compute a vector of compound shapes and axis normals representing adjacent blocks. - let mut blocks: SmallVec<[Compound<f64>; 4]> = smallvec![]; + let mut blocks: SmallVec<[Compound<f64>; 4]> = SmallVec::new(); // Don't check the same block twice. let mut checked = heapless::FnvIndexSet::new(); for (axis, sign) in &axis { - let compound = adjacent_to_bbox(*axis, *sign, bbox, dest, &chunk_map, &mut checked); + let compound = adjacent_to_bbox(*axis, *sign, bbox, dest, &game, &mut checked); blocks.push(compound); } // Go through blocks and check for time of impact from original // position to the block. If the time of impact is <= 1, the entity // has collided with the block; update the position accordingly. - let velocity = (dest - from).as_vec(); + let velocity = (dest - from).into(); let bbox_shape = bbox_to_cuboid(&bbox); for compound in blocks { @@ -366,7 +319,7 @@ pub fn blocks_intersecting_bbox( &Isometry3::translation(0.0, 0.0, 0.0), &vec3(0.0, 0.0, 0.0), &compound, - &Isometry3::new(from.as_vec(), vec3(0.0, 0.0, 0.0)), + &Isometry3::new(from.into(), vec3(0.0, 0.0, 0.0)), &velocity, &bbox_shape, 1.0, @@ -393,7 +346,7 @@ pub fn blocks_intersecting_bbox( } }; - result.offset += absolute_offset.as_vec().component_mul(&normal); + result.offset += <Position as Into<DVec3>>::into(absolute_offset).component_mul(&normal); if normal.x != 0.0 { result.x = true; @@ -426,7 +379,7 @@ pub fn adjacent_to_bbox( sign: i32, bbox: &AABB<f64>, pos: Position, - chunk_map: &ChunkMap, + game: &Game, checked: &mut heapless::FnvIndexSet<BlockPosition, U32>, ) -> Compound<f64> { assert!(axis <= 2); @@ -435,7 +388,7 @@ pub fn adjacent_to_bbox( let sign = f64::from(sign); let size = bbox.size() / 2.0; - let mut blocks: SmallVec<[(BlockPosition, Block); 4]> = smallvec![]; + let mut blocks: SmallVec<[(BlockPosition, BlockId); 4]> = SmallVec::new(); let other_axis1 = match axis { 0 => 1, @@ -480,13 +433,13 @@ pub fn adjacent_to_bbox( // Go through offsets and append block position if the block is solid. for offset in &offsets { - let block_pos = (pos + *offset).block_pos(); + let block_pos = (pos + *offset).block(); if checked.contains(&block_pos) { continue; } - match chunk_map.block_at(block_pos) { + match game.block_at(block_pos) { Some(block) => { if block.is_solid() { checked.insert(block_pos).unwrap(); @@ -501,7 +454,7 @@ pub fn adjacent_to_bbox( for (block_pos, block) in &blocks { let isometry = block_isometry(*block_pos); - let shape = block_shape(&block); + let shape = block_shape(*block); shapes.push((isometry, ShapeHandle::new(shape))); } @@ -509,7 +462,7 @@ pub fn adjacent_to_bbox( } /// Returns an `ncollide` `Cuboid` corresponding to the given block. -pub fn block_shape(block: &Block) -> Cuboid<f64> { +pub fn block_shape(block: BlockId) -> Cuboid<f64> { let bbox = bbox_for_block(block); Cuboid::new(bbox.half_extents()) } @@ -526,58 +479,6 @@ pub fn block_isometry(pos: BlockPosition) -> Isometry3<f64> { ) } -/// Finds all chunks within a given distance (in blocks) -/// of a position. -/// -/// The Y coordinate of `distance` is ignored. -pub fn chunks_within_distance( - mut pos: Position, - mut distance: DVec3, -) -> SmallVec<[ChunkPosition; 9]> { - assert!(distance.x >= 0.0); - assert!(distance.z >= 0.0); - - let mut result = smallvec![]; - - let mut x_len = 0; - let mut z_len = 0; - - let center_chunk_pos = pos.chunk_pos(); - - loop { - let needed = ((pos.x + 16.0) / 16.0).floor() * 16.0 - pos.x; - if needed > distance.x { - break; - } - - distance.x -= needed; - pos.x += needed; - x_len += 1; - } - - loop { - let needed = ((pos.z + 16.0) / 16.0).floor() * 16.0 - pos.z; - if needed > distance.z { - break; - } - - distance.z -= needed; - pos.z += needed; - z_len += 1; - } - - for x in -x_len..=x_len { - for z in -z_len..=z_len { - result.push(ChunkPosition::new( - x + center_chunk_pos.x, - z + center_chunk_pos.z, - )); - } - } - - result -} - /// Returns a point at the "front" of the bounding /// box when it is traveling in the given direction. /// @@ -598,6 +499,7 @@ pub fn bbox_front(bbox: &AABB<f64>, direction: Vec3) -> Position { .toi_with_ray( &Isometry3::new(vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0)), &ray, + 1000.0, false, ) .unwrap(); @@ -614,15 +516,12 @@ pub fn bbox_to_cuboid(bbox: &AABB<f64>) -> Cuboid<f64> { Cuboid::new(half_lengths) } +/* TODO: update #[cfg(test)] mod tests { use super::*; - use crate::entity::test; - use crate::testframework as t; - use feather_core::world::chunk::Chunk; use feather_core::world::ChunkPosition; use feather_core::Block; - use specs::{Builder, WorldExt}; use std::collections::HashSet; #[test] @@ -833,3 +732,4 @@ mod tests { assert!(checked.contains(&BlockPosition::new(0, 64, 0))); } } +*/ diff --git a/feather/old/server/player/Cargo.toml b/feather/old/server/player/Cargo.toml new file mode 100644 index 000000000..bf503679c --- /dev/null +++ b/feather/old/server/player/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "feather-server-player" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-definitions = { path = "../../definitions" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } +feather-server-network = { path = "../network" } +feather-server-commands = { path = "../commands" } +entity = { path = "../entity", package = "feather-server-entity" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +log = "0.4" +mojang-api = "0.6" +once_cell = "1.4.0" +nalgebra-glm = "0.6" +smallvec = "1.4" +itertools = "0.9" +ahash = "0.3" +parking_lot = "0.10" +thiserror = "1.0" +anyhow = "1.0" +inventory = "0.1" diff --git a/feather/old/server/player/src/broadcasters.rs b/feather/old/server/player/src/broadcasters.rs new file mode 100644 index 000000000..635d44906 --- /dev/null +++ b/feather/old/server/player/src/broadcasters.rs @@ -0,0 +1,15 @@ +mod animation; +mod block; +mod chat; +mod gamemode; +mod health; +mod keepalive; +mod teleport; + +pub use animation::on_player_animation_broadcast_animation; +pub use block::*; +pub use chat::{flush_player_message_receiver, on_chat_broadcast}; +pub use gamemode::*; +pub use health::on_health_update_send; +pub use keepalive::broadcast_keepalive; +pub use teleport::send_teleported; diff --git a/feather/old/server/player/src/broadcasters/animation.rs b/feather/old/server/player/src/broadcasters/animation.rs new file mode 100644 index 000000000..4284903ac --- /dev/null +++ b/feather/old/server/player/src/broadcasters/animation.rs @@ -0,0 +1,17 @@ +use feather_core::network::packets::AnimationClientbound; +use feather_server_types::{Game, NetworkId, PlayerAnimationEvent}; +use fecs::World; + +/// Broadcasts animations. +#[fecs::event_handler] +pub fn on_player_animation_broadcast_animation( + event: &PlayerAnimationEvent, + game: &mut Game, + world: &mut World, +) { + let packet = AnimationClientbound { + entity_id: world.get::<NetworkId>(event.player).0, + animation: event.animation, + }; + game.broadcast_entity_update(world, packet, event.player, Some(event.player)); +} diff --git a/feather/old/server/player/src/broadcasters/block.rs b/feather/old/server/player/src/broadcasters/block.rs new file mode 100644 index 000000000..26e1b3ee1 --- /dev/null +++ b/feather/old/server/player/src/broadcasters/block.rs @@ -0,0 +1,94 @@ +//! Broadcasting of block updates, i.e. when a block is changed to another. + +use crate::packet_handlers::Digging; +use crate::{FinishDiggingEvent, StartDiggingEvent}; +use feather_core::network::packets::{BlockBreakAnimation, BlockChange, Effect}; +use feather_server_types::{BlockUpdateCause, BlockUpdateEvent, BumpVec, Game, NetworkId}; +use fecs::{IntoQuery, Read, World, Write}; + +/// System for broadcasting block update +/// events to all clients. +#[fecs::event_handler] +pub fn on_block_update_broadcast(event: &BlockUpdateEvent, game: &mut Game, world: &mut World) { + // Broadcast Block Change packet. + let packet = BlockChange { + location: event.pos, + block_id: event.new.vanilla_id() as i32, + }; + game.broadcast_chunk_update(world, packet, event.pos.into(), None); +} + +/// Sends an `Effect` packet with status `BlockBreak` +/// when a block is broken by a player. +#[fecs::event_handler] +pub fn on_block_break_broadcast_effect( + event: &BlockUpdateEvent, + game: &mut Game, + world: &mut World, +) { + if let BlockUpdateCause::Entity(source) = event.cause { + let packet = Effect { + effect_id: 2001, // TODO remove hardcoded magic number + location: event.pos, + data: event.old.vanilla_id() as i32, + disable_relative_volume: false, + }; + game.broadcast_chunk_update(world, packet, event.pos.chunk(), Some(source)); + } +} + +/// Component storing the most recently sent `BlockBreakAnimation` +/// destroy stage for a player. +#[derive(Copy, Clone, Debug)] +struct LastDestroyStage(i8); + +/// Sends `BlockBreakAnimation` while a block is being dug. +#[fecs::system] +pub fn broadcast_block_break_animation(game: &mut Game, world: &mut World) { + let mut broadcasts = BumpVec::new_in(game.bump()); + for (entity, (digging, entity_id, mut last_destroy_stage)) in + <(Read<Digging>, Read<NetworkId>, Write<LastDestroyStage>)>::query() + .iter_entities_mut(world.inner_mut()) + { + let destroy_stage = ((digging.progress / digging.time) * 9.0).floor().min(9.0) as i8; + if destroy_stage == last_destroy_stage.0 { + return; // no new data to send + } + last_destroy_stage.0 = destroy_stage; + + let packet = BlockBreakAnimation { + entity_id: entity_id.0, + location: digging.pos, + destroy_stage, + }; + broadcasts.push((packet, entity)); + } + + for (packet, entity) in broadcasts { + game.broadcast_entity_update(world, packet, entity, Some(entity)); + } +} + +/// Removes `LastDestroyStage` and broadcasts +/// that a block animation is finished a player finishes digging. +#[fecs::event_handler] +pub fn on_finish_digging_remove_animation( + event: &FinishDiggingEvent, + game: &mut Game, + world: &mut World, +) { + let _ = world.remove::<LastDestroyStage>(event.player); + + let packet = BlockBreakAnimation { + entity_id: world.get::<NetworkId>(event.player).0, + location: event.digging.pos, + destroy_stage: -1, // value outside of [0, 9] removes the animation + }; + game.broadcast_entity_update(world, packet, event.player, None); +} + +/// Inserts `LastDestroyStage` when a player starts digging. +#[fecs::event_handler] +pub fn on_start_digging_init_stage(event: &StartDiggingEvent, world: &mut World) { + let _ = world.add(event.player, LastDestroyStage(-1)); +} diff --git a/feather/old/server/player/src/broadcasters/chat.rs b/feather/old/server/player/src/broadcasters/chat.rs new file mode 100644 index 000000000..6d3e6fcdf --- /dev/null +++ b/feather/old/server/player/src/broadcasters/chat.rs @@ -0,0 +1,34 @@ +//! Broadcasting of chat messages + +use feather_core::network::packets::ChatMessageClientbound; +use feather_server_types::{ChatEvent, ChatPosition, Game, MessageReceiver, Network, Player}; +use fecs::{component, IntoQuery, Read, World, Write}; + +/// System that broadcasts chat messages to all players +#[fecs::event_handler] +pub fn on_chat_broadcast(event: &ChatEvent, game: &Game, world: &mut World) { + let packet = ChatMessageClientbound { + json_data: event.message.clone(), + position: match event.position { + ChatPosition::Chat => 0, + ChatPosition::SystemMessage => 1, + ChatPosition::GameInfo => 2, + }, + }; + game.broadcast_global(world, packet, None); +} + +/// System to flush a players `MessageReceiver` component and send the messages. +#[fecs::system] +pub fn flush_player_message_receiver(world: &mut World) { + <(Write<MessageReceiver>, Read<Network>)>::query() + .filter(component::<Player>()) + .par_for_each_mut(world.inner_mut(), |(mut receiver, network)| { + for message in receiver.flush() { + network.send(ChatMessageClientbound { + json_data: message.to_string(), + position: 0, + }); + } + }); +} diff --git a/feather/old/server/player/src/broadcasters/gamemode.rs b/feather/old/server/player/src/broadcasters/gamemode.rs new file mode 100644 index 000000000..e7a695e04 --- /dev/null +++ b/feather/old/server/player/src/broadcasters/gamemode.rs @@ -0,0 +1,22 @@ +use feather_core::network::packets::ChangeGameState; +use feather_core::util::Gamemode; +use feather_server_types::{GamemodeUpdateEvent, Network}; +use fecs::World; + +/// Sends a Change Game State packet to update player's gamemode. +#[fecs::event_handler] +pub fn on_gamemode_update_send(event: &GamemodeUpdateEvent, world: &mut World) { + let packet = ChangeGameState { + reason: 3, // change gamemode + value: match event.new { + Gamemode::Survival => 0.0, + Gamemode::Creative => 1.0, + Gamemode::Adventure => 2.0, + Gamemode::Spectator => 3.0, + }, + }; + + if let Some(network) = world.try_get::<Network>(event.player) { + network.send(packet); + } +} diff --git a/feather/old/server/player/src/broadcasters/health.rs b/feather/old/server/player/src/broadcasters/health.rs new file mode 100644 index 000000000..3ca7725ca --- /dev/null +++ b/feather/old/server/player/src/broadcasters/health.rs @@ -0,0 +1,16 @@ +use feather_core::network::packets::UpdateHealth; +use feather_server_types::{HealthUpdateEvent, Network}; +use fecs::World; + +/// When a player's health is updated, updates it on the client. +#[fecs::event_handler] +pub fn on_health_update_send(event: &HealthUpdateEvent, world: &mut World) { + if let Some(network) = world.try_get::<Network>(event.entity) { + let packet = UpdateHealth { + health: event.new as f32, + food: 20, // todo + saturation: 5.0, // todo + }; + network.send(packet); + } +} diff --git a/feather/old/server/player/src/broadcasters/keepalive.rs b/feather/old/server/player/src/broadcasters/keepalive.rs new file mode 100644 index 000000000..258c895d2 --- /dev/null +++ b/feather/old/server/player/src/broadcasters/keepalive.rs @@ -0,0 +1,14 @@ +use feather_core::network::packets::KeepAliveClientbound; +use feather_server_types::{Game, TPS}; +use fecs::World; + +/// Broadcasts keepalives every second. +#[fecs::system] +pub fn broadcast_keepalive(game: &Game, world: &mut World) { + if game.tick_count % TPS == 0 { + let packet = KeepAliveClientbound { + keep_alive_id: game.tick_count, + }; + game.broadcast_global(world, packet, None); + } +} diff --git a/feather/old/server/player/src/broadcasters/teleport.rs b/feather/old/server/player/src/broadcasters/teleport.rs new file mode 100644 index 000000000..b4bc7e773 --- /dev/null +++ b/feather/old/server/player/src/broadcasters/teleport.rs @@ -0,0 +1,36 @@ +use feather_core::network::packets::PlayerPositionAndLookClientbound; +use feather_core::util::Position; +use feather_server_types::{BumpVec, Game, Network, Teleported}; +use fecs::{component, IntoQuery, Read, World}; +use std::sync::atomic::{AtomicI32, Ordering}; + +/// TODO: how are we supposed to handle this? +static TELEPORT_ID_COUNTER: AtomicI32 = AtomicI32::new(1); + +/// System which polls for players with the `Teleported` component +/// and notifies them of their new position. +#[fecs::system] +pub fn send_teleported(world: &mut World, game: &mut Game) { + let mut to_delete = BumpVec::new_in(game.bump()); + for (entity, (network, pos)) in <(Read<Network>, Read<Position>)>::query() + .filter(component::<Teleported>()) + .iter_entities(world.inner()) + { + let teleport_id = TELEPORT_ID_COUNTER.fetch_add(1, Ordering::AcqRel); + let packet = PlayerPositionAndLookClientbound { + x: pos.x, + y: pos.y, + z: pos.z, + yaw: pos.yaw, + pitch: pos.pitch, + flags: 0, + teleport_id, // todo: properly handle the teleport ID + }; + network.send(packet); + to_delete.push(entity); + } + + for entity in to_delete { + let _ = world.remove::<Teleported>(entity); + } +} diff --git a/feather/old/server/player/src/chat.rs b/feather/old/server/player/src/chat.rs new file mode 100644 index 000000000..743e13a5f --- /dev/null +++ b/feather/old/server/player/src/chat.rs @@ -0,0 +1,26 @@ +use feather_core::text::{Color, TextRoot, Translate}; +use feather_server_types::{ChatEvent, ChatPosition, Game, Name, PlayerJoinEvent}; +use fecs::World; + +#[fecs::event_handler] +pub fn on_player_join_broadcast_join_message( + event: &PlayerJoinEvent, + game: &mut Game, + world: &mut World, +) { + let message: String = { + let name = world.get::<Name>(event.player); + TextRoot::from( + Translate::MultiplayerPlayerJoined * vec![name.0.to_string()] * Color::Yellow, + ) + .into() + }; + + game.handle( + world, + ChatEvent { + message, + position: ChatPosition::Chat, + }, + ); +} diff --git a/feather/old/server/player/src/death.rs b/feather/old/server/player/src/death.rs new file mode 100644 index 000000000..ab003efbc --- /dev/null +++ b/feather/old/server/player/src/death.rs @@ -0,0 +1,60 @@ +//! Handles when a player dies. +//! +//! Player deaths have some annoying properties which makes a correct implementation difficult. +//! Most notably, a dead player (one who is currently on the respawn screen) has no physical +//! presence within the world, despite them still being connected to the server and existing +//! in that sense. + +use entity::drops::drop_item; +use feather_core::util::Position; +use feather_server_types::{Dead, EntityDeathEvent, Game, Inventory, InventoryUpdateEvent, Player}; +use fecs::World; + +/// Scatters a player's items when they die. +#[fecs::event_handler] +pub fn on_player_death_scatter_inventory( + event: &EntityDeathEvent, + game: &mut Game, + world: &mut World, +) { + if !world.has::<Player>(event.entity) { + return; + } + + let inventory = world.get::<Inventory>(event.entity); + let pos = *world.get::<Position>(event.entity); + + // Remove items and drop on ground + let slots_to_update = inventory + .enumerate() + .filter_map(|(index, slot)| slot.map(|_| index)); + let event = InventoryUpdateEvent { + entity: event.entity, + slots: slots_to_update.collect(), + }; + + let items_to_spawn = inventory + .iter_mut() + .filter_map(|mut item| item.take()) + .collect::<Vec<_>>(); + + drop(inventory); + + for item in items_to_spawn { + drop_item(game, world, item, pos); + } + + game.handle(world, event); +} + +/// Adds the `Dead` component to a player when they die to +/// avoid causing them to be physically interacted with. +/// +/// The component will be removed once the user clicks the respawn +/// button. +#[fecs::event_handler] +pub fn on_player_death_mark_dead(event: &EntityDeathEvent, world: &mut World) { + if world.has::<Player>(event.entity) { + world.add(event.entity, Dead).unwrap(); + } +} diff --git a/feather/old/server/player/src/join.rs b/feather/old/server/player/src/join.rs new file mode 100644 index 000000000..dc7c03c83 --- /dev/null +++ b/feather/old/server/player/src/join.rs @@ -0,0 +1,167 @@ +//! Join logic for players. + +use feather_core::blocks::BlockId; +use feather_core::network::packets::{ + HeldItemChangeClientbound, JoinGame, PlayerPositionAndLookClientbound, SpawnPosition, Tags, +}; +use feather_core::util::{BlockPosition, Difficulty, Dimension, Gamemode, Position}; +use feather_server_network::{ListenerToServerMessage, NetworkIoManager, ServerToListenerMessage}; +use feather_server_types::{ + BumpVec, ChunkSendEvent, Game, HeldItem, Network, NetworkId, PlayerJoinEvent, + WorkerToServerMessage, +}; +use fecs::{IntoQuery, Read, World}; +use std::iter; + +/// System which polls for player disconnects. +#[fecs::system] +pub fn poll_player_disconnect(game: &mut Game, world: &mut World) { + // For each player with a Network component, + // check their channel for disconnects. + let mut to_despawn = BumpVec::new_in(game.bump()); + <Read<Network>>::query() + .iter_entities(world.inner()) + .for_each(|(entity, network)| { + while let Ok(msg) = network.rx.lock().try_recv() { + match msg { + WorkerToServerMessage::NotifyDisconnected { reason } => { + to_despawn.push((entity, reason)); + } + } + } + }); + + to_despawn.into_iter().for_each(|(player, reason)| { + game.disconnect(player, world, reason); + }); +} + +/// System which polls for new clients from the listener task. +#[fecs::system] +pub fn poll_new_clients(game: &mut Game, world: &mut World, io_handle: &mut NetworkIoManager) { + while let Ok(msg) = io_handle.rx.lock().try_recv() { + match msg { + ListenerToServerMessage::NewClient(info) => { + crate::create(game, world, info); + } + ListenerToServerMessage::RequestEntity => { + let entity = world.spawn(iter::once(()))[0]; + let _ = io_handle.tx.send(ServerToListenerMessage::Entity(entity)); + } + ListenerToServerMessage::DeleteEntity(entity) => { + // no need to use `Game::despawn` here as + // the entity hasn't actually "existed" yet; + // it has no components + world.despawn(entity); + } + } + } +} + +// After chunks are sent to a client, we complete the login sequence +// by sending Spawn Position, Player Position and Look, and inventory, +// among others. This is handled by the event handler below; + +/// Component indicating that a player has completed the join sequence. +#[derive(Default, Debug)] +pub struct Joined; + +/// System to run the join sequence. To determine when a player is ready to join, +/// we wait for the chunk that the player is in to be sent—this appears to work +/// well with the client. +#[fecs::event_handler] +pub fn on_chunk_send_join_player(event: &ChunkSendEvent, game: &Game, world: &mut World) { + if world.try_get::<Joined>(event.player).is_some() { + return; // already joined + } + + let pos = { + let pos = world.get::<Position>(event.player); + + if pos.chunk() != event.chunk { + return; + } + + *pos + }; + + // Run the join sequence. + world.add(event.player, Joined).unwrap(); + + let network = world.get::<Network>(event.player); + + let packet = SpawnPosition { + location: BlockPosition::new(game.level.spawn_x, game.level.spawn_y, game.level.spawn_z), + }; + network.send(packet); + + let packet = PlayerPositionAndLookClientbound { + x: pos.x, + y: pos.y, + z: pos.z, + yaw: pos.yaw, + pitch: pos.pitch, + flags: 0, + teleport_id: 0, + }; + network.send(packet); +} + +#[fecs::event_handler] +pub fn on_player_join_send_join_packets(event: &PlayerJoinEvent, game: &Game, world: &mut World) { + let network = world.get::<Network>(event.player); + let id = world.get::<NetworkId>(event.player); + let gamemode = *world.get::<Gamemode>(event.player); + let held_item_slot = world.get::<HeldItem>(event.player); + + // TODO + let join_packet = JoinGame { + entity_id: id.0, + gamemode: gamemode.id(), + dimension: Dimension::Overwold.id(), + difficulty: Difficulty::Medium.id(), + max_players: game.config.server.max_players as u8, + level_type: game.level.generator_name.clone(), + reduced_debug_info: false, + }; + network.send(join_packet); + + let held_item_packet = HeldItemChangeClientbound { + slot: held_item_slot.0 as i8, + }; + network.send(held_item_packet); + + // TODO declare recipes + + let tags_packet = Tags { + block_tags: vec![], + item_tags: vec![], + fluid_tags: vec![ + ( + "minecraft:water".into(), + vec![ + BlockId::water().vanilla_fluid_id().unwrap() as i32, + BlockId::water() + .with_water_level(1) + .vanilla_fluid_id() + .unwrap() as i32, + ], + ), + ( + "minecraft:lava".into(), + vec![ + BlockId::lava().vanilla_fluid_id().unwrap() as i32, + BlockId::lava() + .with_water_level(1) + .vanilla_fluid_id() + .unwrap() as i32, + ], + ), + ], + }; + network.send(tags_packet); + + // TODO declare commands + + // TODO unlock recipes +} diff --git a/feather/old/server/player/src/lib.rs b/feather/old/server/player/src/lib.rs new file mode 100644 index 000000000..efe572d81 --- /dev/null +++ b/feather/old/server/player/src/lib.rs @@ -0,0 +1,219 @@ +#![forbid(unsafe_code)] + +extern crate nalgebra_glm as glm; + +mod broadcasters; +mod chat; +mod death; +mod join; +mod packet_handlers; +mod view; + +use feather_core::inventory::{Area, Inventory, SlotIndex, Window}; +use feather_core::network::packets::{PlayerInfo, PlayerInfoAction, SpawnPlayer}; +use feather_core::network::Packet; +use feather_core::text::Text; +use feather_core::util::{Gamemode, Position}; +use feather_server_network::NewClientInfo; +use feather_server_types::{ + BlocksFallen, CanBreak, CanInstaBreak, CanRespawn, CanTakeDamage, ChunkHolder, + CreationPacketCreator, EntitySpawnEvent, Game, GamemodeUpdateEvent, Health, HealthUpdateEvent, + HeldItem, InventoryUpdateEvent, LastKnownPositions, MaxHealth, MessageReceiver, Name, Network, + NetworkId, OpenWindowCount, Player, PlayerJoinEvent, PlayerPreJoinEvent, PreviousPosition, + PreviousVelocity, ProfileProperties, SpawnPacketCreator, Uuid, Velocity, +}; +use feather_server_util::degrees_to_stops; +use fecs::{Entity, EntityRef, World}; + +pub use broadcasters::*; +pub use chat::*; +pub use death::*; +pub use join::*; +pub use packet_handlers::*; +use std::sync::atomic::Ordering; +pub use view::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ItemTimedUse { + pub tick_start: u64, +} + +/// Creates a new player from the given `NewClientInfo`. +/// +/// This function also triggers events for the player join. +pub fn create(game: &mut Game, world: &mut World, info: NewClientInfo) -> Entity { + // TODO: blocked on https://github.com/TomGillen/legion/issues/36 + let entity = info.entity; + world.add(entity, NetworkId(entity::new_id())).unwrap(); + world.add(entity, info.position).unwrap(); + world.add(entity, PreviousPosition::default()).unwrap(); + world.add(entity, Velocity::default()).unwrap(); + world.add(entity, PreviousVelocity::default()).unwrap(); + world.add(entity, info.uuid).unwrap(); + world + .add( + entity, + Network { + tx: info.sender, + rx: info.receiver.into(), + }, + ) + .unwrap(); + world.add(entity, info.ip).unwrap(); + world.add(entity, ProfileProperties(info.profile)).unwrap(); + world.add(entity, Name(info.username)).unwrap(); + world.add(entity, OpenWindowCount::default()).unwrap(); + world.add(entity, ChunkHolder::default()).unwrap(); + world.add(entity, LastKnownPositions::default()).unwrap(); + world + .add(entity, SpawnPacketCreator(&create_spawn_packet)) + .unwrap(); + world + .add(entity, CreationPacketCreator(&create_initialization_packet)) + .unwrap(); + + let gamemode = Gamemode::from_id(info.data.gamemode as u8); + add_gamemode_comps(world, gamemode, entity); + + let items = info + .data + .inventory + .iter() + .map(|slot| (slot.convert_index().unwrap_or_default(), slot.into())); + + let (window, slots) = { + let inventory = Inventory::player(); + let window = Window::player(entity); + world.add(entity, inventory).unwrap(); + + let accessor = window.accessor(world).unwrap(); + items.for_each(|(index, item)| { + let _ = accessor.set_item_at(index, item); + }); + + let window2 = window.clone(); + let slots = info.data.inventory.iter().map(move |slot| { + window2 + .convert_network(slot.convert_index().unwrap_or_default()) + .map(SlotIndex::from) + .unwrap_or(SlotIndex { + area: Area::Hotbar, + slot: 0, + }) + }); + + drop(accessor); + (window, slots) + }; + world.add(entity, window).unwrap(); + world + .add(entity, HeldItem(info.data.held_item as usize)) + .unwrap(); + + world.add(entity, MessageReceiver::default()).unwrap(); + + world.add(entity, Player).unwrap(); + + world.add(entity, CanRespawn).unwrap(); + world.add(entity, MaxHealth(20)).unwrap(); + world + .add(entity, Health(info.data.animal.health as u32)) + .unwrap(); + world.add(entity, BlocksFallen::default()).unwrap(); + + game.player_count.fetch_add(1, Ordering::SeqCst); + game.handle(world, EntitySpawnEvent { entity }); + game.handle(world, PlayerPreJoinEvent { player: entity }); + game.handle(world, PlayerJoinEvent { player: entity }); + game.handle( + world, + InventoryUpdateEvent { + slots: slots.collect(), + entity, + }, + ); + game.handle( + world, + HealthUpdateEvent { + old: 0, + new: info.data.animal.health as u32, + entity, + }, + ); + + entity +} + +fn add_gamemode_comps(world: &mut World, gamemode: Gamemode, entity: Entity) { + world.add(entity, gamemode).unwrap(); + + // Remove old gamemode comps + let _ = world.remove::<CanTakeDamage>(entity); + let _ = world.remove::<CanInstaBreak>(entity); + let _ = world.remove::<CanBreak>(entity); + + match gamemode { + Gamemode::Survival | Gamemode::Adventure => world.add(entity, CanTakeDamage).unwrap(), + Gamemode::Creative => world.add(entity, CanInstaBreak).unwrap(), + _ => (), + } + + if gamemode == Gamemode::Survival || gamemode == Gamemode::Creative { + world.add(entity, CanBreak).unwrap(); + } +} + +/// When a player's gamemode is updated, updates their capability +/// marker components (`CanBreak`, `CanTakeDamage`, etc) +#[fecs::event_handler] +pub fn on_gamemode_update_update_capabilities(event: &GamemodeUpdateEvent, world: &mut World) { + if world.is_alive(event.player) { + add_gamemode_comps(world, event.new, event.player); + } +} + +/// Function to create a `SpawnPlayer` packet to spawn the player. +fn create_spawn_packet(accessor: &EntityRef) -> Box<dyn Packet> { + let entity_id = accessor.get::<NetworkId>().0; + let player_uuid = *accessor.get::<Uuid>(); + let pos = *accessor.get::<Position>(); + + let packet = SpawnPlayer { + entity_id, + player_uuid, + x: pos.x, + y: pos.y, + z: pos.z, + yaw: degrees_to_stops(pos.yaw), + pitch: degrees_to_stops(pos.pitch), + metadata: Default::default(), + }; + Box::new(packet) +} + +/// Function to create a `PlayerInfo` packet to broadcast when the player joins. +fn create_initialization_packet(accessor: &EntityRef) -> Box<dyn Packet> { + let name = accessor.get::<Name>(); + let props = accessor.get::<ProfileProperties>(); + let uuid = *accessor.get::<Uuid>(); + + let props = props + .0 + .iter() + .map(|prop| { + ( + prop.name.clone(), + prop.value.clone(), + prop.signature.clone(), + ) + }) + .collect::<Vec<_>>(); + + let display_name = Text::of(name.0.clone()).into(); + + let action = + PlayerInfoAction::AddPlayer(name.0.clone(), props, Gamemode::Creative, 50, display_name); + + let packet = PlayerInfo { action, uuid }; + Box::new(packet) +} diff --git a/feather/old/server/player/src/packet_handlers.rs b/feather/old/server/player/src/packet_handlers.rs new file mode 100644 index 000000000..0ae5fbf33 --- /dev/null +++ b/feather/old/server/player/src/packet_handlers.rs @@ -0,0 +1,42 @@ +//! Systems which handle packets. + +mod animation; +mod chat; +mod client_status; +mod digging; +mod inventory; +mod movement; +mod placement; +mod use_item; +mod window; + +pub use self::inventory::*; +pub use animation::handle_animation; +pub use chat::handle_chat; +pub use client_status::handle_client_status; +pub use digging::*; +use fecs::{Entity, World}; +pub use movement::handle_movement_packets; +pub use placement::handle_player_block_placement; +pub use use_item::handle_player_use_item; +pub use window::handle_close_window; + +/// Iterator filter to ensure players have not been removed from the world. +pub trait IteratorExt: Iterator { + fn for_each_valid(self, world: &mut World, f: impl FnMut(&mut World, Self::Item)); +} + +impl<T, P> IteratorExt for T +where + T: Iterator<Item = (Entity, P)>, +{ + fn for_each_valid(self, world: &mut World, mut f: impl FnMut(&mut World, Self::Item)) { + self.for_each(move |(entity, packet)| { + if !world.is_alive(entity) { + return; + } + + f(world, (entity, packet)); + }) + } +} diff --git a/feather/old/server/player/src/packet_handlers/animation.rs b/feather/old/server/player/src/packet_handlers/animation.rs new file mode 100644 index 000000000..e0a0e448d --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/animation.rs @@ -0,0 +1,21 @@ +use crate::IteratorExt; +use feather_core::network::packets::AnimationServerbound; +use feather_core::util::{ClientboundAnimation, Hand}; +use feather_server_types::{Game, PacketBuffers, PlayerAnimationEvent}; +use fecs::World; +use std::sync::Arc; + +/// Handles animation packets. +#[fecs::system] +pub fn handle_animation(game: &mut Game, world: &mut World, packet_buffers: &Arc<PacketBuffers>) { + packet_buffers + .received::<AnimationServerbound>() + .for_each_valid(world, |world, (player, packet)| { + let animation = match packet.hand { + Hand::Main => ClientboundAnimation::SwingMainArm, + Hand::Off => ClientboundAnimation::SwingOffhand, + }; + + game.handle(world, PlayerAnimationEvent { player, animation }); + }); +} diff --git a/feather/old/server/player/src/packet_handlers/chat.rs b/feather/old/server/player/src/packet_handlers/chat.rs new file mode 100644 index 000000000..a3cfffb4e --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/chat.rs @@ -0,0 +1,47 @@ +use crate::IteratorExt; +use feather_core::network::packets::ChatMessageServerbound; +use feather_core::text::{TextRoot, Translate}; +use feather_server_commands::CommandState; +use feather_server_types::{ChatEvent, ChatPosition, Game, Name, PacketBuffers}; +use fecs::World; +use std::sync::Arc; + +/// Handles chat packets. +#[fecs::system] +pub fn handle_chat( + game: &mut Game, + world: &mut World, + packet_buffers: &Arc<PacketBuffers>, + #[default] commands: &CommandState, +) { + packet_buffers + .received::<ChatMessageServerbound>() + .for_each_valid(world, |world, (player, packet)| { + if packet.message.starts_with('/') { + log::info!( + "Player `{}` executed command `{}`", + world.get::<Name>(player).0, + packet.message + ); + commands.dispatch(game, world, player, &packet.message[1..]); + } else { + let player_name = world.get::<Name>(player); + let message: String = TextRoot::from( + Translate::ChatTypeText + * vec![player_name.0.to_string(), packet.message.to_string()], + ) + .into(); + + log::info!("<{}> {}", player_name.0, packet.message); + drop(player_name); + + game.handle( + world, + ChatEvent { + message, + position: ChatPosition::Chat, + }, + ); + } + }); +} diff --git a/feather/old/server/player/src/packet_handlers/client_status.rs b/feather/old/server/player/src/packet_handlers/client_status.rs new file mode 100644 index 000000000..e1507c9e4 --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/client_status.rs @@ -0,0 +1,42 @@ +use crate::packet_handlers::IteratorExt; +use feather_core::network::packets::ClientStatus; +use feather_core::network::packets::Respawn; +use feather_core::util::{Gamemode, Position}; +use feather_server_types::{Dead, Health, Network, PacketBuffers, Teleported}; +use fecs::World; +use std::sync::Arc; + +/// Handles the Client Status packet, which is sent +/// when the user clicks the respawn button. +#[fecs::system] +pub fn handle_client_status(world: &mut World, packet_buffers: &Arc<PacketBuffers>) { + packet_buffers + .received::<ClientStatus>() + .for_each_valid(world, |world, (player, packet)| { + match packet.action_id { + 0 => { + // Perform respawn + let _ = world.remove::<Dead>(player); + + // TODO: support spawn positons + *world.get_mut::<Position>(player) = Position::default(); + + world.get_mut::<Health>(player).0 = 20; + + world.add(player, Teleported).unwrap(); + + let gamemode = *world.get::<Gamemode>(player); + + // Send Respawn packet + let packet = Respawn { + dimension: 0, + difficulty: 1, + gamemode: gamemode.id() as u8, + level_type: String::from("default"), + }; + world.get::<Network>(player).send(packet); + } + x => log::debug!("Unimplemented Client Status action ID {}", x), + } + }); +} diff --git a/feather/old/server/player/src/packet_handlers/digging.rs b/feather/old/server/player/src/packet_handlers/digging.rs new file mode 100644 index 000000000..93051f075 --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/digging.rs @@ -0,0 +1,561 @@ +//! This module handles the monolithic Player Digging packet. +//! +//! The packet's name is rather misleading, as it is also sent +//! for actions mostly unrelated to digging including eating, shooting bows, +//! swapping items out to the offhand, and dropping items. + +use crate::{ItemTimedUse, IteratorExt}; +use entity::InventoryExt; +use feather_core::blocks::{BlockId, HalfUpperLower, Part, SimplifiedBlockKind}; +use feather_core::inventory::{slot, Area, Inventory, Slot, SlotIndex}; +use feather_core::items::{Item, ItemStack}; +use feather_core::network::packets::{PlayerDigging, PlayerDiggingStatus}; +use feather_core::util::{BlockPosition, Gamemode, Position}; +use feather_definitions::Tool; +use feather_server_types::{ + BlockUpdateCause, CanBreak, CanInstaBreak, EntitySpawnEvent, Game, HeldItem, + InventoryUpdateEvent, ItemDamageEvent, ItemDropEvent, PacketBuffers, Velocity, + PLAYER_EYE_HEIGHT, TPS, +}; +use feather_server_util::{charge_from_ticks_held, compute_projectile_velocity}; +use fecs::{Entity, IntoQuery, Read, World, Write}; +use smallvec::smallvec; +use std::sync::Arc; + +/// Stores the "digging status" of a player. +/// +/// If this component exists for an entity, +/// then it is currently digging a block. The +/// corresponding animation must be displayed. +#[derive(Copy, Clone, Debug)] +pub struct Digging { + /// The position of the block being dug + pub pos: BlockPosition, + /// The total time (in seconds) of digging needed + pub time: f64, + /// Progress made, in seconds (better tools increase this + /// value faster) + pub progress: f64, +} + +/// System responsible for polling for PlayerDigging +/// packets and writing the corresponding events. +#[fecs::system] +pub fn handle_player_digging( + game: &mut Game, + world: &mut World, + packet_buffers: &Arc<PacketBuffers>, +) { + use PlayerDiggingStatus::*; + + packet_buffers + .received::<PlayerDigging>() + .for_each_valid(world, |world, (player, packet)| match packet.status { + StartedDigging | FinishedDigging | CancelledDigging => { + handle_digging(game, world, player, packet) + } + DropItem | DropItemStack => handle_drop_item_stack(game, world, player, packet), + ConsumeItem => handle_consume_item(game, world, player, packet), + status => log::warn!("Unhandled Player Digging status {:?}", status), + }); +} + +fn handle_digging(game: &mut Game, world: &mut World, player: Entity, packet: PlayerDigging) { + if !world.has::<CanBreak>(player) { + log::trace!( + "Player cannot break blocks but sent player digging status {:?}", + packet.status + ); + return; + } + + match packet.status { + PlayerDiggingStatus::StartedDigging => handle_started_digging(game, world, player, packet), + PlayerDiggingStatus::CancelledDigging => handle_cancelled_digging(game, world, player), + PlayerDiggingStatus::FinishedDigging => { + handle_finished_digging(game, world, player, packet) + } + _ => unreachable!(), + } +} + +const MAX_DIG_RADIUS_SQUARED: f64 = 36.0; + +/// Event triggered when the `Digging` component is added to a player. +/// +/// Not triggered in the case of insta-breaks. +#[derive(Copy, Clone, Debug)] +pub struct StartDiggingEvent { + pub player: Entity, +} + +/// Event triggered when a player finished digging (the `Digging` component +/// is removed). This event is triggered event if digging was canceled. +#[derive(Copy, Clone, Debug)] +pub struct FinishDiggingEvent { + /// The player who finished digging + pub player: Entity, + /// The `Digging` component which was removed + pub digging: Digging, +} + +fn handle_started_digging( + game: &mut Game, + world: &mut World, + player: Entity, + packet: PlayerDigging, +) { + // Delete old `Digging`, if it exists + let _ = world.remove::<Digging>(player); + + // Check the distance isn't too far. + if packet + .location + .position() + .distance_squared_to(*world.get::<Position>(player)) + > MAX_DIG_RADIUS_SQUARED + { + // Ignore the packet. + log::trace!("player {:?} tried to dig too far", player); + return; + } + + // If the player can insta-break, or the block has hardness 0, then they can already break the block. + if world.has::<CanInstaBreak>(player) + || game + .block_at(packet.location) + .unwrap_or_default() + .kind() + .hardness() + < 0.01 + { + dig(game, world, player, packet.location); + } else { + // Insert new `Digging`. + let block = game.block_at(packet.location).unwrap_or_default(); + let hardness = block.kind().hardness(); + + world + .add( + player, + Digging { + pos: packet.location, + time: hardness, + progress: 0.0, + }, + ) + .unwrap(); + game.handle(world, StartDiggingEvent { player }); + } +} + +/// System to advance the digging progress. +#[fecs::system] +pub fn advance_dig_progress(game: &mut Game, world: &mut World) { + <(Write<Digging>, Read<Inventory>, Read<HeldItem>)>::query().par_for_each_mut( + world.inner_mut(), + |(mut digging, inventory, held_item)| { + // Advance progress depends on tool and the + // block kind: https://minecraft.gamepedia.com/Breaking#Speed + // * If the block requires some tool to harvest (i.e. it requires a tool to get the item after it breaks), + // then if that tool is not held, progress is hindered by a factor of 5. Otherwise, the hindrance + // is only a factor of 1.5. + // * If the player's tool helps dig the block (e.g. shovel => dirt, pickaxe => cobblestone), + // then a constant mutliplier is applied to the dig speed depending on the tool's material. + // This is retrieved through the `dig_multiplier` property on `ToolMaterial`. + let block = game.block_at(digging.pos).unwrap_or_default(); + let best_tool = block.kind().best_tool(); + let best_tool_required = block.kind().best_tool_required(); + + let item_in_main_hand: Slot = inventory + .item_at(Area::Hotbar, held_item.0) + .expect("held item out of bounds"); + let held_tool = item_in_main_hand.map(|item| item.ty.tool()).flatten(); + + let multiplier = if best_tool == held_tool && best_tool.is_some() { + let dig_multiplier = item_in_main_hand + .unwrap() + .ty + .tool_material() + .map(|mat| mat.dig_multiplier()) + .unwrap_or_else(|| { + // Missing data in feather-definitions; + // panic. (TODO: maybe this should just be a log message) + panic!( + "no tool material for item {:?}, even though it has a tool", + item_in_main_hand + ) + }); + + (1.0 / 1.5) * dig_multiplier + } else if best_tool_required { + 1.0 / 5.0 + } else { + 1.0 / 1.5 + }; + + digging.progress += (1.0 / TPS as f64) * multiplier; + }, + ); +} + +fn handle_cancelled_digging(game: &mut Game, world: &mut World, player: Entity) { + let digging = world.try_get::<Digging>(player).map(|d| *d); + let _ = world.remove::<Digging>(player); + + if let Some(digging) = digging { + game.handle(world, FinishDiggingEvent { player, digging }); + } +} + +fn handle_finished_digging( + game: &mut Game, + world: &mut World, + player: Entity, + packet: PlayerDigging, +) { + let digging = match world.try_get::<Digging>(player) { + Some(digging) => *digging, + None => { + if world.has::<CanInstaBreak>(player) { + // Can insta-break - no `StartedDigging` needed + Digging { + pos: packet.location, + time: 0.0, + progress: 0.0, + } + } else { + // Player can't insta-break and has + // not sent StartedDigging. + // They cannot finish. + return; + } + } + }; + + let _ = world.remove::<Digging>(player); + + if digging.pos != packet.location { + return; + } + + // Attempt to break the block + dig(game, world, player, digging.pos); + + // Finished + game.handle(world, FinishDiggingEvent { player, digging }); +} + +fn dig(game: &mut Game, world: &mut World, player: Entity, pos: BlockPosition) { + let block = match game.block_at(pos) { + Some(block) => block, + None => { + game.disconnect( + player, + world, + format!( + "Attempted to break block in unloaded chunk (position: {:?})", + pos + ), + ); + + return; + } + }; + + damage_tool(player, block, game, world); + + // Handle multi-block destruction (i.e. doors and beds) + if let Some(other_pos) = match block.simplified_kind() { + SimplifiedBlockKind::Bed => { + let direction = block.facing_cardinal().unwrap(); + Some(match block.part().unwrap() { + Part::Head => pos - direction.offset(), + Part::Foot => pos + direction.offset(), + }) + } + SimplifiedBlockKind::WoodenDoor | SimplifiedBlockKind::IronDoor => { + Some(match block.half_upper_lower().unwrap() { + HalfUpperLower::Upper => pos.down(), + HalfUpperLower::Lower => pos.up(), + }) + } + _ => None, + } { + if game.block_at(other_pos).unwrap().kind() == block.kind() { + game.set_block_at( + world, + other_pos, + BlockId::air(), + BlockUpdateCause::Entity(player), + ); + }; + } + + game.set_block_at(world, pos, BlockId::air(), BlockUpdateCause::Entity(player)); +} + +fn damage_tool(player: Entity, block: BlockId, game: &mut Game, world: &mut World) { + if block.kind().hardness() == 0.0 || world.has::<CanInstaBreak>(player) { + return; // Instant break should not cause damage + } + + let held_item = world.get::<HeldItem>(player).0; + let inventory = world.get::<Inventory>(player); + + let item_in_main_hand: Slot = inventory + .item_at(Area::Hotbar, held_item) + .expect("held item out of bounds"); + + if let Some(item) = item_in_main_hand { + let damage_taken = if item.ty == Item::Trident { + 2 + } else { + match item.ty.tool() { + // Note: it looks like hoes do not take damage when breaking blocks in 1.13.2 + // but in some later version this was changed so that they take 1 damage. + None | Some(Tool::Hoe) => return, + Some(Tool::Sword) => 2, + Some(_) => 1, + } + }; + + drop(inventory); + let damage_event = ItemDamageEvent { + player, + slot: slot(Area::Hotbar, held_item), + damage_taken, + }; + game.handle(world, damage_event); + } +} + +fn handle_drop_item_stack( + game: &mut Game, + world: &mut World, + player: Entity, + packet: PlayerDigging, +) { + assert!( + packet.status == PlayerDiggingStatus::DropItem + || packet.status == PlayerDiggingStatus::DropItemStack + ); + + let held_item = world.get::<HeldItem>(player).0; + let inventory = world.get::<Inventory>(player); + + let stack = { + if let Some(item) = inventory.item_at(Area::Hotbar, held_item).unwrap() { + item + } else { + // Silently fail - no item stack to drop + return; + } + }; + + let amnt = match packet.status { + PlayerDiggingStatus::DropItem => { + if stack.amount == 0 { + inventory.remove_item_at(Area::Hotbar, held_item).unwrap(); + 0 + } else if stack.amount == 1 { + inventory.remove_item_at(Area::Hotbar, held_item).unwrap(); + 1 + } else { + inventory + .set_item_at(Area::Hotbar, held_item, stack.of_amount(stack.amount - 1)) + .unwrap(); + 1 + } + } + PlayerDiggingStatus::DropItemStack => { + inventory.remove_item_at(Area::Hotbar, held_item).unwrap(); + stack.amount + } + _ => unreachable!(), // Assertion above + }; + + drop(inventory); + + let idx = SlotIndex { + area: Area::Hotbar, + slot: held_item, + }; + let inv_update = InventoryUpdateEvent { + slots: smallvec![idx], + entity: player, + }; + game.handle(world, inv_update); + + if amnt != 0 { + let item_drop = ItemDropEvent { + slot: Some(idx), + stack: stack.of_amount(amnt), + player, + }; + game.handle(world, item_drop); + } +} + +/// Handles food consumption and shooting arrows. +fn handle_consume_item(game: &mut Game, world: &mut World, player: Entity, packet: PlayerDigging) { + assert_eq!(packet.status, PlayerDiggingStatus::ConsumeItem); + + // TODO: Fallback to off-hand if main-hand is not a consumable + let inventory = world.get::<Inventory>(player); + let used_item = inventory.item_in_main_hand(player, world); + + if let Some(item) = used_item { + if item.ty == Item::Bow { + drop(inventory); + handle_shoot_bow(game, world, player); + } + // TODO: Food, potions + } +} + +fn handle_shoot_bow(game: &mut Game, world: &mut World, player: Entity) { +<<<<<<< HEAD + let inventory = world.get::<Inventory>(player); + let arrow_to_consume: Option<(SlotIndex, ItemStack)> = find_arrow(&inventory); + + if player.gamemode == Gamemode::Survival || player.gamemode == Gamemode::Adventure { + // If no arrow was found, don't shoot + let arrow_to_consume = arrow_to_consume.clone(); + if arrow_to_consume.is_none() { + return; + } +======= + let gamemode = *world.get::<Gamemode>(player); +>>>>>>> develop + + { + let inventory = world.get::<Inventory>(player); + let arrow_to_consume: Option<(SlotIndex, ItemStack)> = find_arrow(&inventory); + +<<<<<<< HEAD + inventory.set_item_at(arrow_slot, arrow_stack); + game.handle( + world, + InventoryUpdateEvent { + slots: smallvec![arrow_slot], + entity: player, + }, + ); + } +======= + if gamemode == Gamemode::Survival || gamemode == Gamemode::Adventure { + // If no arrow was found, don't shoot + if arrow_to_consume.is_none() { + return; + } +>>>>>>> develop + + // Consume arrow + let (arrow_slot, arrow_stack) = arrow_to_consume.unwrap(); + let mut arrow_stack: ItemStack = arrow_stack; + arrow_stack.amount -= 1; + + inventory + .set_item_at(arrow_slot.area, arrow_slot.slot, arrow_stack) + .unwrap(); + drop(inventory); + game.handle( + world, + InventoryUpdateEvent { + slots: smallvec![arrow_slot], + entity: player, + }, + ); + } + + let _arrow_type: Item = match arrow_to_consume { + None => Item::Arrow, // Default to generic arrow in creative mode with none in inventory + Some((_, arrow_stack)) => arrow_stack.ty, + }; + } + + let timed_use = world.try_get::<ItemTimedUse>(player); + + // Spam clicking can lead to a scenario where this system is called before the UseItem system adds the component + // In that case just return. + if timed_use.is_none() { + return; + } + + let timed_use = timed_use.unwrap(); + + let mut time_held = game.tick_count - timed_use.tick_start; + + // if bow not held for at least 4 ticks, don't shoot at all + // to avoid extreme bowspamming + if time_held < 4 { + return; + } + + if time_held > 20 { + time_held = 20; + } + + let charge_force = charge_from_ticks_held(time_held as u32); + log::trace!("Held for {} ticks. Force of {}", time_held, charge_force); + + let init_position = *world.get::<Position>(player) + glm::vec3(0.0, PLAYER_EYE_HEIGHT, 0.0); + + let direction = init_position.direction(); + + let arrow_velocity = compute_projectile_velocity( + glm::vec3(direction.x, direction.y, direction.z), + charge_force as f64, + 0.0, + &mut *game.rng(), + ); + log::trace!( + "Computed exit velocity: {}. Velocity is norm {}", + arrow_velocity, + arrow_velocity.norm() + ); + + drop(timed_use); + + world.remove::<ItemTimedUse>(player).unwrap(); + + log::trace!("Spawning arrow entity."); + let entity = entity::arrow::create() + .with(init_position) + .with(Velocity(arrow_velocity)) + .build() + .spawn_in(world); + game.handle(world, EntitySpawnEvent { entity }); +} + +fn find_arrow(inventory: &Inventory) -> Option<(SlotIndex, ItemStack)> { + // Order of priority is: off-hand, hotbar (0 to 8), rest of inventory + + if let Some(offhand) = inventory.item_at(Area::Hotbar, 0).unwrap() { + if is_arrow_item(offhand.ty) { + return Some((slot(Area::Offhand, 0), offhand)); + } + } + + for hotbar_slot in 0..9 { + if let Some(hotbar_stack) = inventory.item_at(Area::Hotbar, hotbar_slot).unwrap() { + if is_arrow_item(hotbar_stack.ty) { + return Some((slot(Area::Hotbar, hotbar_slot), hotbar_stack)); + } + } + } + + for inv_slot in 0..27 { + if let Some(inv_stack) = inventory.item_at(Area::Main, inv_slot).unwrap() { + if is_arrow_item(inv_stack.ty) { + return Some((slot(Area::Main, inv_slot), inv_stack)); + } + } + } + None +} + +fn is_arrow_item(item: Item) -> bool { + matches!(item, Item::Arrow | Item::SpectralArrow | Item::TippedArrow) +} diff --git a/feather/old/server/player/src/packet_handlers/inventory.rs b/feather/old/server/player/src/packet_handlers/inventory.rs new file mode 100644 index 000000000..4f8dec7c6 --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/inventory.rs @@ -0,0 +1,632 @@ +//! Handling of inventory update packets. +//! This currently includes Creative Inventory Action, Held Item +//! Change, and the venerable Click Window. + +use crate::IteratorExt; +use feather_core::inventory::{Area, Inventory, SlotIndex, Window}; +use feather_core::items::ItemStack; +use feather_core::network::packets::{ + ClickWindow, ConfirmTransactionClientbound, CreativeInventoryAction, HeldItemChangeServerbound, +}; +use feather_core::util::Gamemode; +use feather_server_types::{ + Game, HeldItem, InventoryUpdateEvent, ItemDropEvent, Network, PacketBuffers, +}; +use fecs::{Entity, World}; +use smallvec::smallvec; +use std::convert::TryFrom; +use std::sync::Arc; +use thiserror::Error; + +/// System for handling Creative Inventory Action packets. +#[fecs::system] +pub fn handle_creative_inventory_action( + game: &mut Game, + world: &mut World, + packet_buffers: &Arc<PacketBuffers>, +) { + packet_buffers + .received::<CreativeInventoryAction>() + .for_each_valid(world, |world, (player, packet)| { + // Creative Inventory Action can only be used in creative + // mode. + let gamemode = *world.get::<Gamemode>(player); + if gamemode != Gamemode::Creative { + game.disconnect( + player, + world, + "attempted to use Creative Inventory Action outside of creative mode", + ); + return; + } + + // Slot -1 means that the user clicked outside the window, + // dropping the item. + if packet.slot == -1 { + match &packet.clicked_item { + Some(stack) => { + // Cause item to be dropped + let event = ItemDropEvent { + slot: None, + stack: *stack, + player, + }; + game.handle(world, event); + + // No need to update inventory + return; + } + None => (), + } + } + + let inventory = world.get::<Inventory>(player); + let window = world.get::<Window>(player); + + let accessor = match window.accessor(world) { + Ok(a) => a, + Err(_) => return, // silently fail + }; + + let slot = packet.clicked_item; + + if let Err(e) = accessor.set_slot_at(packet.slot as usize, slot) { + drop(inventory); + drop(accessor); + drop(window); + game.disconnect(player, world, format!("Slot index out of bounds: {}", e)); + return; + } + + // Trigger inventory update event + let index = window.convert_network(packet.slot as usize).unwrap(); // already checked above + let event = InventoryUpdateEvent { + slots: smallvec![index.into()], + entity: player, + }; + drop(inventory); + drop(accessor); + drop(window); + game.handle(world, event); + }); +} + +/// System for handling Held Item Change packets. +#[fecs::system] +pub fn handle_held_item_change( + game: &mut Game, + world: &mut World, + packet_buffers: &Arc<PacketBuffers>, +) { + packet_buffers + .received::<HeldItemChangeServerbound>() + .for_each_valid(world, |world, (player, packet)| { + if packet.slot as usize >= 9 { + game.disconnect(player, world, "Hotbar index out of bounds"); + return; + } + + let mut held_item = world.get_mut::<HeldItem>(player); + held_item.0 = packet.slot as usize; + + // Trigger event + let event = InventoryUpdateEvent { + slots: smallvec![SlotIndex { + area: Area::Hotbar, + slot: held_item.0 + }], + entity: player, + }; + drop(held_item); + game.handle(world, event); + }); +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum MouseButton { + Left, + Right, +} + +/// Mode of a Click Window packet. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum Mode { + /// Simple left or right mouse click + SingleClick(MouseButton), + /// Shift + either left or right click + /// + /// Both clicks perform the same action + ShiftClick, + /// Number key on interval `[1, 9]` + NumberKey(u8), + MiddleClick, + ItemDrop { + /// Whether the full stack should be dropped + /// (this is the case for CTRL+Q) + /// + /// If `false`, only one item should be dropped. + full_stack: bool, + }, + + /// A paint mode action, where the user + /// drags their cursor over multiple + /// slots and "paints" items into their + /// inventory. + Paint(PaintAction), + + /// A double click on a slot. + DoubleClick, +} + +#[derive(Debug, Error)] +enum ModeParseError { + #[error("invalid mode ID {0}")] + InvalidModeId(i32), + #[error("invalid button ID {0}")] + InvalidButtonId(u8), + #[error("number key ID {0} is outside of the interval [0, 8]")] + InvalidNumberKeyId(u8), + #[error("invalid paint action ID {0}")] + InvalidPaintActionId(u8), + #[error("unhandled parse mode; should skip")] + Unhandled, +} + +// https://wiki.vg/index.php?title=Protocol&diff=14889&oldid=14881#Click_Window +impl<'a> TryFrom<&'a ClickWindow> for Mode { + type Error = ModeParseError; + + fn try_from(value: &'a ClickWindow) -> Result<Self, Self::Error> { + match value.mode { + 0 => { + let button = parse_button(value.button)?; + + // Slot -999 means that the user clicked outside the window, + // dropping the item. + if value.slot == -999 { + match button { + MouseButton::Left => return Ok(Mode::ItemDrop { full_stack: true }), + MouseButton::Right => return Ok(Mode::ItemDrop { full_stack: false }), + } + } + + Ok(Mode::SingleClick(button)) + } + 1 => { + // ensure button is valid + let _button = parse_button(value.button)?; + + Ok(Mode::ShiftClick) + } + 2 => { + if value.button > 8 { + return Err(ModeParseError::InvalidNumberKeyId(value.button)); + } + + Ok(Mode::NumberKey(value.button + 1)) + } + 3 => { + if value.button != 2 { + return Err(ModeParseError::InvalidNumberKeyId(value.button)); + } + Ok(Mode::MiddleClick) + } + 4 => { + if value.slot == -999 { + return Err(ModeParseError::Unhandled); + } + + let full_stack = value.button == 1; + + Ok(Mode::ItemDrop { full_stack }) + } + 5 => { + let action = match value.button { + 0 => PaintAction::Start(MouseButton::Left), + 4 => PaintAction::Start(MouseButton::Right), + 8 => return Err(ModeParseError::Unhandled), + 1 | 5 | 9 => PaintAction::AddSlot, + 2 | 6 | 10 => PaintAction::Finish, + x => return Err(ModeParseError::InvalidPaintActionId(x)), + }; + + Ok(Mode::Paint(action)) + } + 6 => Ok(Mode::DoubleClick), + x => Err(ModeParseError::InvalidModeId(x)), + } + } +} + +fn parse_button(x: u8) -> Result<MouseButton, ModeParseError> { + match x { + 0 => Ok(MouseButton::Left), + 1 => Ok(MouseButton::Right), + x => Err(ModeParseError::InvalidButtonId(x)), + } +} + +/// Action for `Mode::Paint` +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum PaintAction { + /// Start dragging with some mouse + Start(MouseButton), + /// Add slot for the current drag + AddSlot, + /// Finish dragging + Finish, +} + +/// System for handling Click Window packets. +/// +/// This is a bulky one +#[fecs::system] +pub fn handle_click_windows( + game: &mut Game, + world: &mut World, + packet_buffers: &Arc<PacketBuffers>, +) { + packet_buffers + .received::<ClickWindow>() + .for_each_valid(world, |world, (player, packet)| { + let action_number = packet.action_number; + // Packet format is documented at https://wiki.vg/index.php?title=Protocol&diff=14889&oldid=14881#Click_Window. + // In effect, the `mode` field determines + // the action to take, and the `button` field + // then indicates what type of action. + let mode = match Mode::try_from(&packet) { + Ok(mode) => mode, + Err(e) => match e { + ModeParseError::Unhandled => return, // ignore the error - this packet doesn't need to be handled + e => { + game.disconnect( + player, + world, + format!("error parsing Click Window packet: {}", e), + ); + return; + } + }, + }; + + if let Err(e) = handle_click_window(game, world, player, packet, mode) { + game.disconnect( + player, + world, + format!("error handling Click Window packet: {}", e), + ); + return; + } + + // Send Confirm Transaction to verify success + let packet = ConfirmTransactionClientbound { + window_id: 0, + action_number, + accepted: true, // TODO: correctly account for lag + }; + world.get::<Network>(player).send(packet); + }); +} + +fn handle_click_window( + game: &mut Game, + world: &mut World, + player: Entity, + packet: ClickWindow, + mode: Mode, +) -> anyhow::Result<()> { + match mode { + Mode::SingleClick(button) => handle_single_click(game, world, player, packet, button), + Mode::DoubleClick => handle_double_click(game, world, player, packet), + Mode::ShiftClick => handle_shift_click(game, world, player, packet), + Mode::NumberKey(key) => handle_number_key(game, world, player, packet, key), + Mode::MiddleClick => handle_middle_click(game, world, player, packet), + Mode::ItemDrop { full_stack } => handle_item_drop(game, world, player, packet, full_stack), + Mode::Paint(action) => handle_paint(game, world, player, packet, action), + } +} + +/// Stores an item currently picked by +/// a player's cursor. +#[derive(Copy, Clone, Debug)] +struct PickedItem(ItemStack); + +fn handle_single_click( + game: &mut Game, + world: &mut World, + player: Entity, + packet: ClickWindow, + button: MouseButton, +) -> anyhow::Result<()> { + if let Some(picked) = world.try_get::<PickedItem>(player).map(|i| *i) { + // Put down the item on the clicked slot. Based on the mouse button: + // * left => whole stack + // * right => single item + // + // But if there already exists an item of a different + // type in the slot, then the picked up item and + // the item in the slot are swapped. + + let window = world.get::<Window>(player); + let accessor = window.accessor(world)?; + let current_item = accessor.item_at(packet.slot as usize)?; + + if let Some(current_item) = current_item.and_then(|item| { + if item.eq_ignore_amount(picked.0) { + None + } else { + Some(item) + } + }) { + // Different items - swap + accessor.set_item_at(packet.slot as usize, picked.0)?; + drop(accessor); + drop(window); + world.get_mut::<PickedItem>(player).0 = current_item; + } else { + // Place item on slot + let count = match button { + MouseButton::Left => picked.0.amount, + MouseButton::Right => 1, + }; + + let current_count = current_item.map(|stack| stack.amount).unwrap_or(0); + let new_count = (count + current_count).min(picked.0.ty.stack_size() as u8); + + accessor.set_item_at(packet.slot as usize, picked.0.of_amount(new_count))?; + + drop(accessor); + drop(window); + + world.get_mut::<PickedItem>(player).0.amount -= new_count - current_count; + + if world.get::<PickedItem>(player).0.amount == 0 { + world.remove::<PickedItem>(player).unwrap(); + } + } + } else { + let window = world.get::<Window>(player); + let accessor = window.accessor(world)?; + + // Pick up the item in the slot + let picked_up = accessor.item_at(packet.slot as usize)?; + let mut count = picked_up.map(|item| item.amount).unwrap_or(0); + if button == MouseButton::Right { + count = (count + 1) / 2; + } + if let Some(item) = picked_up { + accessor.set_item_at(packet.slot as usize, item.of_amount(item.amount - count))?; + + drop(accessor); + drop(window); + world + .add(player, PickedItem(item.of_amount(count))) + .unwrap(); + } + } + + let window = world.get::<Window>(player); + let slots = smallvec![window + .convert_network(packet.slot as usize) + .ok_or_else(|| anyhow::anyhow!("invalid slot index"))? + .into()]; + let affected_entity = window.corresponding_entity(packet.slot as usize).unwrap(); + drop(window); + game.handle( + world, + InventoryUpdateEvent { + entity: affected_entity, + slots, + }, + ); + + Ok(()) +} + +fn handle_double_click( + game: &mut Game, + world: &mut World, + player: Entity, + _packet: ClickWindow, +) -> anyhow::Result<()> { + // Double click gathers items into the picked stack until it hits the max stack size, or it has picked up all possible items + + // Keep track of what slots are modified so the client can be informed + let mut modified_slots: smallvec::SmallVec<[SlotIndex; 2]> = smallvec![]; + + let stack_size; + + let new_picked_count = { + let mut current_count; + + // Get information about the currently picked item (if nothing is picked, return) + let picked = match world.try_get_mut::<PickedItem>(player) { + Some(picked) => picked.0, + None => return Ok(()), + }; + stack_size = picked.ty.stack_size() as u8; + current_count = picked.amount; + + // Get the current inventory + let inventory = world.get::<Inventory>(player); + + // Iterate through all inventory slots, picking up items of the same type + for (index, slot) in inventory.enumerate() { + if let Some(slot) = slot { + // Remove items from the inventory until the player's PickedItem has reached its max stack size + if picked.eq_ignore_amount(slot) && slot.amount != stack_size { + if let Some(mut item_stack) = + inventory.remove_item_at(index.area, index.slot)? + { + // Push the slot that was modified so it will be updated on the client + modified_slots.push(index); + + current_count += item_stack.amount; + + if current_count >= stack_size { + // Put the extra items back into the slot that had its items removed and break + + item_stack.amount = current_count - stack_size; + current_count = stack_size; + + if item_stack.amount > 0 { + inventory.set_item_at(index.area, index.slot, item_stack)?; + } + + break; + } + } + } + } + } + + // Return how many items the picked stack should now have + current_count + }; + + // Ensure there are no situations where new items are created and the PickedItem stack size is larger than the maximum + assert!(new_picked_count <= stack_size); + + // Update the picked item + world.get_mut::<PickedItem>(player).0.amount = new_picked_count; + + game.handle( + world, + InventoryUpdateEvent { + entity: player, + slots: modified_slots, + }, + ); + + Ok(()) +} + +fn handle_shift_click( + _game: &mut Game, + _world: &mut World, + _player: Entity, + _packet: ClickWindow, +) -> anyhow::Result<()> { + // TODO + Ok(()) +} + +fn handle_number_key( + game: &mut Game, + world: &mut World, + player: Entity, + packet: ClickWindow, + key: u8, +) -> anyhow::Result<()> { + let slot: usize = packet.slot as usize; + let hotbar_slot_index = (key - 1) as usize; + + let window = world.get::<Window>(player); + let accessor = window.accessor(world)?; + + let inventory = world.get::<Inventory>(player); + + // The slot index of the target hotbar slot + let hotbar_slot = SlotIndex { + area: Area::Hotbar, + slot: hotbar_slot_index, + }; + + // Perform the swap + if let Some(hotbar_slot_stack) = inventory.remove_item_at(Area::Hotbar, hotbar_slot_index)? { + // Handles the case where there is an item in both target slots + + let stack_under_cursor = accessor.remove_item_at(slot)?; + + accessor.set_item_at(slot, hotbar_slot_stack)?; + + if let Some(stack) = stack_under_cursor { + inventory.set_item_at(Area::Hotbar, hotbar_slot_index, stack)?; + }; + } else { + // Handles the case where there is an item in only the slot below the cursor + + let stack_under_cursor = accessor.remove_item_at(slot)?; + + if let Some(stack) = stack_under_cursor { + inventory.set_item_at(Area::Hotbar, hotbar_slot_index, stack)?; + }; + }; + + drop(inventory); + drop(accessor); + + // Trigger inventory update events for the two updated slots. + // Note that the two slots may belong to different entities, e.g. + // if the player moves an item from a chest to their hotbar. + let event1 = InventoryUpdateEvent { + entity: player, + slots: smallvec![hotbar_slot], + }; + let event2 = InventoryUpdateEvent { + entity: window.corresponding_entity(slot as usize).unwrap(), + slots: smallvec![window + .convert_network(slot) + .ok_or_else(|| anyhow::anyhow!("invalid slot index"))? + .into()], + }; + + drop(window); + + game.handle(world, event1); + game.handle(world, event2); + + Ok(()) +} + +fn handle_middle_click( + _game: &mut Game, + world: &mut World, + player: Entity, + packet: ClickWindow, +) -> anyhow::Result<()> { + let gamemode = *world.get::<Gamemode>(player); + if Gamemode::Creative == gamemode { + if world.try_get::<PickedItem>(player).is_some() { + // Player already has something in its hand. + return Ok(()); + } + let window = world.get::<Window>(player); + let accessor = window.accessor(world)?; + + // Pick the item in the slot + let picked = accessor.item_at(packet.slot as usize)?; + if let Some(item) = picked { + let count = item.ty.stack_size(); + drop(accessor); + drop(window); + world + .add(player, PickedItem(item.of_amount(count as u8))) + .unwrap(); + } + } + + Ok(()) +} + +fn handle_item_drop( + _game: &mut Game, + _world: &mut World, + _player: Entity, + _packet: ClickWindow, + _full_stack: bool, +) -> anyhow::Result<()> { + // TODO + Ok(()) +} + +fn handle_paint( + _game: &mut Game, + _world: &mut World, + _player: Entity, + _packet: ClickWindow, + _action: PaintAction, +) -> anyhow::Result<()> { + // TODO + Ok(()) +} diff --git a/feather/old/server/player/src/packet_handlers/movement.rs b/feather/old/server/player/src/packet_handlers/movement.rs new file mode 100644 index 000000000..1ce913a95 --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/movement.rs @@ -0,0 +1,40 @@ +use feather_core::network::packets::{ + PlayerLook, PlayerPosition, PlayerPositionAndLookServerbound, +}; +use feather_core::util::Position; +use feather_server_types::{Network, PacketBuffers}; +use fecs::{component, IntoQuery, World, Write}; +use std::sync::Arc; + +/// System to handle player movement updates. +#[fecs::system] +pub fn handle_movement_packets(world: &mut World, packet_buffers: &Arc<PacketBuffers>) { + <Write<Position>>::query() + .filter(component::<Network>()) + .par_entities_for_each_mut(world.inner_mut(), |(player, mut position)| { + let mut position: &mut Position = &mut *position; + for position_and_look in + packet_buffers.received_for::<PlayerPositionAndLookServerbound>(player) + { + position.x = position_and_look.x; + position.y = position_and_look.feet_y; + position.z = position_and_look.z; + position.pitch = position_and_look.pitch; + position.yaw = position_and_look.yaw; + position.on_ground = position_and_look.on_ground; + } + + for position_update in packet_buffers.received_for::<PlayerPosition>(player) { + position.x = position_update.x; + position.y = position_update.feet_y; + position.z = position_update.z; + position.on_ground = position_update.on_ground; + } + + for look in packet_buffers.received_for::<PlayerLook>(player) { + position.pitch = look.pitch; + position.yaw = look.yaw; + position.on_ground = look.on_ground; + } + }); +} diff --git a/feather/old/server/player/src/packet_handlers/placement.rs b/feather/old/server/player/src/packet_handlers/placement.rs new file mode 100644 index 000000000..e7160702f --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/placement.rs @@ -0,0 +1,539 @@ +//! Handling of player block placement packets. + +use crate::IteratorExt; +use entity::InventoryExt; +use feather_core::blocks::categories::PlacementType; +use feather_core::blocks::{ + BlockId, BlockKind, Face, FacingCardinal, FacingCardinalAndDown, FacingCubic, HalfTopBottom, + HalfUpperLower, Hinge, Part, SimplifiedBlockKind, SlabKind, StairsShape, +}; +use feather_core::inventory::{slot, Area, Inventory}; +use feather_core::item_block::ItemToBlock; +use feather_core::network::packets::PlayerBlockPlacement; +use feather_core::util::{BlockPosition, Gamemode, Position, Vec3d}; +use feather_server_types::{ + BlockUpdateCause, Game, HeldItem, InteractionHandler, InventoryUpdateEvent, OpenWindowCount, + PacketBuffers, +}; +use feather_server_util::is_block_supported_at; +use fecs::{Entity, World}; +use once_cell::sync::Lazy; +use smallvec::smallvec; +use std::boxed::Box; +use std::collections::HashMap; +use std::sync::Arc; + +type PacketFace = feather_core::network::packets::Face; + +#[allow(dead_code)] +static INTERACTION_HANDLERS: Lazy<HashMap<BlockKind, &'static dyn InteractionHandler>> = + Lazy::new(|| { + let mut handlers_hashmap: HashMap<BlockKind, &'static dyn InteractionHandler> = + HashMap::new(); + + for handler in inventory::iter::<Box<dyn InteractionHandler>> { + let kind = handler.block_kind(); + handlers_hashmap.insert(kind, &**handler); + } + + handlers_hashmap + }); + +/// System for handling Player Block Placement packets +/// and updating the world accordingly. +/// +/// Also handles block interactions because they are handled with the same packet. +#[fecs::system] +pub fn handle_player_block_placement( + game: &mut Game, + world: &mut World, + packet_buffers: &Arc<PacketBuffers>, +) { + packet_buffers + .received::<PlayerBlockPlacement>() + .for_each_valid(world, |world, (player, packet)| { + let target_block = match game.block_at(packet.location) { + Some(block) => block, + None => { + game.disconnect( + player, + world, + "Attempted to interact with block in unloaded chunk", + ); + return; + } + }; + + // Decide whether the player should place a block or interact with the block they are targeting + // TODO: Maybe player shifting may need to be taken into account (shift click on interactable block) + if let Some(interaction_handler) = INTERACTION_HANDLERS.get(&target_block.kind()) { + let window_id = { + if let Some(mut window_count) = world.try_get_mut::<OpenWindowCount>(player) { + window_count.get_increment() + } else { + panic!("Unable to get OpenWindowCount for player {}", player); + } + }; + + // Interact with the block + interaction_handler.handle_interaction( + game, + world, + packet.location, + player, + window_id, + ); + } else { + // Try to place a block + handle_block_placement(game, world, player, target_block, packet); + } + }); +} + +pub fn handle_block_placement( + game: &mut Game, + world: &mut World, + player: Entity, + target_block: BlockId, + packet: PlayerBlockPlacement, +) { + let gamemode = *world.get::<Gamemode>(player); + + let item = { + let inventory = world.get::<Inventory>(player); + match inventory.item_in_main_hand(player, world) { + Some(item) => item, + // Offhand? + None => return, // No block to place + } + }; + + let block = match item.ty.to_block() { + Some(block) => block, + None => return, // Item is not a block + }; + + if !handle_slab_placement(game, world, block, packet.location, packet.face) { + // TODO: waterlogged blocks, more + let pos = if target_block.is_replaceable() { + packet.location + } else { + packet.location + packet.face.placement_offset() + }; + + let current_block = match game.block_at(pos) { + Some(block) => block, + None => return, + }; + + if !current_block.is_replaceable() { + return; + } + + // Deny replacing grass with grass for example + if current_block.is_replaceable() + && !current_block.is_air() + && !current_block.is_fluid() + && block.is_replaceable() + { + return; + } + + let block = update_block_state_for_placement( + game, + block, + pos, + *world.get::<Position>(player), + &packet, + ); + + // Abort if block that needs support wouldn't have the needed support blocks + if !is_block_supported_at(block, game, pos) { + return; + } + + // handle multi-block placements (i.e. doors and beds) + if let Some((other_pos, other_block)) = match block.simplified_kind() { + SimplifiedBlockKind::Bed => { + let mut head = block; + head.set_part(Part::Head); + Some((pos + block.facing_cardinal().unwrap().offset(), head)) + } + SimplifiedBlockKind::IronDoor | SimplifiedBlockKind::WoodenDoor => { + let mut upper = block; + upper.set_half_upper_lower(HalfUpperLower::Upper); + Some((pos.up(), upper)) + } + _ => None, + } { + game.set_block_at( + world, + other_pos, + other_block, + BlockUpdateCause::Entity(player), + ); + } + + game.set_block_at(world, pos, block, BlockUpdateCause::Entity(player)); + } + + // Update player's inventory if in survival + let event = { + if gamemode != Gamemode::Creative { + if item.amount == 0 { + game.disconnect( + player, + world, + "Attempted to place block with zero-sized item stack.", + ); + return; + } + + let held_item = world.get::<HeldItem>(player).0; + let inventory = world.get::<Inventory>(player); + + let item = item.of_amount(item.amount - 1); + inventory + .set_item_at(Area::Hotbar, held_item, item) + .unwrap(); + + Some(InventoryUpdateEvent { + slots: smallvec![slot(Area::Hotbar, held_item)], + entity: player, + }) + } else { + None + } + }; + + if let Some(event) = event { + // Only send the event to decrement the held stack if the player's gamemode is survival + game.handle(world, event); + } +} + +// returns true if placement handling should stop +fn handle_slab_placement( + game: &mut Game, + world: &mut World, + block_to_place: BlockId, + mut target_block_pos: BlockPosition, + placement_face: PacketFace, +) -> bool { + if block_to_place.simplified_kind() != SimplifiedBlockKind::Slab { + return false; + } + + let mut target_block = game.block_at(target_block_pos).unwrap(); + if target_block.simplified_kind() == SimplifiedBlockKind::Slab + && target_block.slab_kind().unwrap() != SlabKind::Double + && matches!(placement_face, PacketFace::Bottom | PacketFace::Top) + { + let target_block_slab_kind = target_block.slab_kind().unwrap(); + if (target_block_slab_kind == SlabKind::Bottom && placement_face == PacketFace::Bottom) + || (target_block_slab_kind == SlabKind::Top && placement_face == PacketFace::Top) + { + return false; + } + } else { + target_block_pos = target_block_pos + placement_face.placement_offset(); + if let Some(block) = game.block_at(target_block_pos) { + target_block = block; + } else { + return false; + } + + if target_block.simplified_kind() != SimplifiedBlockKind::Slab { + return false; + } + } + + if target_block.kind() != block_to_place.kind() { + return false; + } + + target_block.set_slab_kind(SlabKind::Double); + + game.set_block_at( + world, + target_block_pos, + target_block, + BlockUpdateCause::Unknown, + ); + + true +} + +fn update_block_state_for_placement( + game: &Game, + mut block: BlockId, + block_pos: BlockPosition, + player_pos: Position, + packet: &PlayerBlockPlacement, +) -> BlockId { + let face = packet.face.face(); + if face == Face::Wall { + if let Some(wall_block) = block.to_wall_block() { + block = wall_block + } + } + + if block.has_face() { + block.set_face(face); + } + + if block.has_facing_cardinal() { + let player_direction = facing_directions(player_pos.direction()) + .iter() + .find(|dir| dir.is_horizontal()) + .unwrap() + .to_facing_cardinal() + .unwrap(); + + block.set_facing_cardinal(match block.placement_type() { + Some(PlacementType::TargetedFace) => { + if face == Face::Wall { + packet.face.facing_cardinal() + } else { + FacingCardinal::North + } + } + Some(PlacementType::PlayerDirection) => player_direction, + Some(PlacementType::PlayerDirectionRightAngle) => player_direction.right(), + None => player_direction.opposite(), + }); + } + + if block.has_facing_cardinal_and_down() { + block.set_facing_cardinal_and_down(match face { + Face::Wall => packet.face.facing_cardinal_and_down().opposite().unwrap(), + _ => FacingCardinalAndDown::Down, + }); + } + + if block.has_facing_cubic() { + let player_direction = facing_directions(player_pos.direction())[0]; + + block.set_facing_cubic(match block.placement_type() { + Some(PlacementType::TargetedFace) => packet.face.facing_cubic(), + Some(PlacementType::PlayerDirection) => player_direction, + None => player_direction.opposite(), + _ => unreachable!(), + }); + } + + if block.has_slab_kind() { + block.set_slab_kind(if is_placed_top(face, packet.cursor_position_y) { + SlabKind::Top + } else { + SlabKind::Bottom + }); + } + + if block.has_half_top_bottom() { + block.set_half_top_bottom(if is_placed_top(face, packet.cursor_position_y) { + HalfTopBottom::Top + } else { + HalfTopBottom::Bottom + }); + } + + if block.has_stairs_shape() { + block.set_stairs_shape(get_stairs_shape( + game, + block_pos, + block.facing_cardinal().unwrap(), + block.half_top_bottom().unwrap(), + )); + } + + if block.has_axis_xyz() { + block.set_axis_xyz(packet.face.facing_cubic().axis()); + } + + if block.has_hinge() { + block.set_hinge(get_hinge_side( + game, + block.kind(), + block_pos, + block.facing_cardinal().unwrap(), + packet.cursor_position_x, + packet.cursor_position_z, + )); + } + + block +} + +fn is_placed_top(face: Face, cursor_position_y: f32) -> bool { + face == Face::Ceiling || (face == Face::Wall && cursor_position_y > 0.5) +} + +fn get_hinge_side( + game: &Game, + block_kind: BlockKind, + block_pos: BlockPosition, + block_facing_cardinal: FacingCardinal, + cursor_position_x: f32, + cursor_position_z: f32, +) -> Hinge { + let right_pos = block_pos + block_facing_cardinal.right().offset(); + let left_pos = block_pos + block_facing_cardinal.left().offset(); + + let score = ( + // check right side + game.block_at(right_pos).unwrap().is_opaque() as i8 + + game.block_at(right_pos.up()).unwrap().is_opaque() as i8 + ) - ( + // check left side + game.block_at(left_pos).unwrap().is_opaque() as i8 + + game.block_at(left_pos.up()).unwrap().is_opaque() as i8 + ); + + let (door_on_right, door_on_left) = { + let is_door = |pos: BlockPosition| { + game.block_at(pos).and_then(|block| { + if block.kind() == block_kind { + block.half_upper_lower() + } else { + None + } + }) == Some(HalfUpperLower::Lower) + }; + + (is_door(right_pos), is_door(left_pos)) + }; + + if (door_on_left && !door_on_right) || score > 0 { + return Hinge::Right; + } + + if (door_on_right && !door_on_left) || score < 0 { + return Hinge::Left; + } + + if (block_facing_cardinal == FacingCardinal::West && cursor_position_z < 0.5) + || (block_facing_cardinal == FacingCardinal::East && cursor_position_z > 0.5) + || (block_facing_cardinal == FacingCardinal::South && cursor_position_x > 0.5) + || (block_facing_cardinal == FacingCardinal::North && cursor_position_x < 0.5) + { + return Hinge::Right; + } + + Hinge::Left +} + +fn get_stairs_shape( + game: &Game, + block_pos: BlockPosition, + block_facing_cardinal: FacingCardinal, + block_half_top_bottom: HalfTopBottom, +) -> StairsShape { + if let Some(adjacent_block) = game.block_at(block_pos + block_facing_cardinal.offset()) { + if adjacent_block.simplified_kind() == SimplifiedBlockKind::Stairs + && adjacent_block.half_top_bottom().unwrap() == block_half_top_bottom + { + let adjacent_block_facing_cardinal = adjacent_block.facing_cardinal().unwrap(); + if adjacent_block_facing_cardinal.axis() != block_facing_cardinal.axis() + && is_different_stairs( + block_facing_cardinal, + block_half_top_bottom, + game.block_at(block_pos + adjacent_block_facing_cardinal.opposite().offset()), + ) + { + if adjacent_block_facing_cardinal == block_facing_cardinal.left() { + return StairsShape::OuterLeft; + } + + return StairsShape::OuterRight; + } + } + } + + if let Some(adjacent_block) = game.block_at(block_pos + block_facing_cardinal.offset()) { + if adjacent_block.simplified_kind() == SimplifiedBlockKind::Stairs + && adjacent_block.half_top_bottom().unwrap() == block_half_top_bottom + { + let adjacent_block_facing_cardinal = adjacent_block.facing_cardinal().unwrap(); + if adjacent_block_facing_cardinal.axis() != block_facing_cardinal.axis() + && is_different_stairs( + block_facing_cardinal, + block_half_top_bottom, + game.block_at(block_pos + adjacent_block_facing_cardinal.offset()), + ) + { + if adjacent_block_facing_cardinal == block_facing_cardinal.left() { + return StairsShape::InnerLeft; + } + + return StairsShape::InnerRight; + } + } + } + + StairsShape::Straight +} + +fn is_different_stairs( + block_facing_cardinal: FacingCardinal, + block_half_top_bottom: HalfTopBottom, + test_block: Option<BlockId>, +) -> bool { + match test_block { + Some(test_block) => { + test_block.simplified_kind() != SimplifiedBlockKind::Stairs + || block_facing_cardinal != test_block.facing_cardinal().unwrap() + || block_half_top_bottom != test_block.half_top_bottom().unwrap() + } + None => true, + } +} + +fn facing_directions(d: Vec3d) -> [FacingCubic; 6] { + let x_dir = if d.x > 0.0 { + FacingCubic::East + } else { + FacingCubic::West + }; + + let y_dir = if d.y > 0.0 { + FacingCubic::Up + } else { + FacingCubic::Down + }; + + let z_dir = if d.z > 0.0 { + FacingCubic::South + } else { + FacingCubic::North + }; + + let x = d.x.abs(); + let y = d.y.abs(); + let z = d.z.abs(); + + let dirs = if x > z { + if y > x { + [y_dir, x_dir, z_dir] + } else if z > y { + [x_dir, z_dir, y_dir] + } else { + [x_dir, y_dir, z_dir] + } + } else if y > z { + [y_dir, z_dir, x_dir] + } else if x > y { + [z_dir, x_dir, y_dir] + } else { + [z_dir, y_dir, x_dir] + }; + + [ + dirs[0], + dirs[1], + dirs[2], + dirs[2].opposite(), + dirs[1].opposite(), + dirs[0].opposite(), + ] +} diff --git a/feather/old/server/player/src/packet_handlers/use_item.rs b/feather/old/server/player/src/packet_handlers/use_item.rs new file mode 100644 index 000000000..0b7e3e248 --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/use_item.rs @@ -0,0 +1,54 @@ +use crate::{ItemTimedUse, IteratorExt}; +use entity::InventoryExt; +use feather_core::inventory::Inventory; +use feather_core::items::Item; +use feather_core::network::packets::UseItem; +use feather_core::util::Hand; +use feather_server_types::{Game, Name, PacketBuffers}; +use fecs::{Entity, World}; +use std::sync::Arc; + +#[fecs::system] +pub fn handle_player_use_item( + game: &mut Game, + world: &mut World, + packet_buffers: &Arc<PacketBuffers>, +) { + packet_buffers + .received::<UseItem>() + .for_each_valid(world, |world, (player, packet)| { + handle_use_item(game, world, player, packet) + }); +} + +fn handle_use_item(game: &mut Game, world: &mut World, player: Entity, packet: UseItem) { + let hand = match packet.hand { + 0 => Hand::Main, + _ => Hand::Off, + }; + + if hand != Hand::Main { + return; + } + + let item_in_main_hand = world + .get::<Inventory>(player) + .item_in_main_hand(player, world); + + if let Some(item_in_main_hand) = item_in_main_hand { + if item_in_main_hand.ty != Item::Bow { + //TODO: Handle other used items + return; + } + world + .add( + player, + ItemTimedUse { + tick_start: game.tick_count, + }, + ) + .unwrap(); + let player_name = world.get::<Name>(player); + log::trace!("Added ItemTimedUse to player {}.", player_name.0); + } +} diff --git a/feather/old/server/player/src/packet_handlers/window.rs b/feather/old/server/player/src/packet_handlers/window.rs new file mode 100644 index 000000000..afb60498f --- /dev/null +++ b/feather/old/server/player/src/packet_handlers/window.rs @@ -0,0 +1,32 @@ +use crate::IteratorExt; +use feather_core::{inventory::Window, network::packets::CloseWindowServerbound}; +use feather_server_types::{Game, PacketBuffers, WindowCloseEvent}; +use fecs::{Entity, World}; +use smallvec::SmallVec; +use std::sync::Arc; + +/// When a client sends Close Window, resets their `Window` +/// to the normal player window. +#[fecs::system] +pub fn handle_close_window( + game: &mut Game, + world: &mut World, + packet_buffers: &Arc<PacketBuffers>, +) { + packet_buffers + .received::<CloseWindowServerbound>() + .for_each_valid(world, |world, (player, _packet)| { + // TODO: at some point, there should be a more rigorous window ID/window handling system + + let windows_closed: SmallVec<[Entity; 2]> = { + let mut window = world.get_mut::<Window>(player); + let windows_closed = window.wrapped_entities().into(); + *window = Window::player(player); + windows_closed + }; + + for closed in windows_closed { + game.handle(world, WindowCloseEvent { player, closed }); + } + }); +} diff --git a/feather/old/server/player/src/view.rs b/feather/old/server/player/src/view.rs new file mode 100644 index 000000000..d39bac190 --- /dev/null +++ b/feather/old/server/player/src/view.rs @@ -0,0 +1,361 @@ +//! Handling of a player's "view." +//! +//! This module includes systems and components +//! which handle sending new data as +//! a player moves through the world. +//! +//! When a player crosses a chunk boundary, its +//! view has changed: some chunks are no longer visible, +//! while others now are. To account for this, we +//! must send the new chunks, unload the old +//! chunks on the client, send new entities, and +//! delete old ones. +//! +//! This is handled as follows: +//! * A system queries all position components which have changed +//! and adds a `CrossedChunk` component to these entities. +//! * Other systems query for added `CrossedChunk` components +//! and perform updates on these players' views. + +use crate::Player; +use ahash::AHashMap; +use feather_core::chunk::Chunk; +use feather_core::network::packets::{ChunkData, DestroyEntities, UnloadChunk}; +use feather_core::util::{ChunkPosition, Position}; +use feather_server_types::{ + BumpVec, ChunkCrossEvent, ChunkLoadEvent, ChunkSendEvent, EntityClientRemoveEvent, + EntitySendEvent, Game, HoldChunkRequest, LoadChunkRequest, Network, NetworkId, PlayerJoinEvent, + PreviousPosition, ReleaseChunkRequest, SpawnPacketCreator, +}; +use fecs::{Entity, IntoQuery, Read, World}; +use itertools::Either; +use parking_lot::RwLock; +use smallvec::SmallVec; +use std::iter; +use std::ops::Add; +use std::sync::Arc; + +/// System which polls for updated positions and +/// calls `Game::on_chunk_cross()` accordingly. +#[fecs::system] +pub fn check_crossed_chunks(world: &mut World, game: &mut Game) { + let mut crossed = BumpVec::new_in(game.bump()); + for (entity, (pos, prev_pos)) in + <(Read<Position>, Read<PreviousPosition>)>::query().iter_entities(world.inner()) + { + if let Some(prev_pos) = prev_pos.0 { + if pos.chunk() != prev_pos.chunk() { + crossed.push((entity, pos.chunk(), prev_pos.chunk())); + } + } + } + + for (entity, new, old) in crossed { + game.handle( + world, + ChunkCrossEvent { + entity, + old: Some(old), + new, + }, + ); + } +} + +/// Triggers a chunk cross when a new player joins. +#[fecs::event_handler] +pub fn on_player_join_trigger_chunk_cross( + event: &PlayerJoinEvent, + game: &mut Game, + world: &mut World, +) { + let chunk = world.get::<Position>(event.player).chunk(); + game.handle( + world, + ChunkCrossEvent { + old: None, + new: chunk, + entity: event.player, + }, + ); +} + +/// System which sends new chunks and unloads old chunks on the client +/// when the view is updated. +#[fecs::event_handler] +pub fn on_chunk_cross_update_chunks( + event: &ChunkCrossEvent, + game: &mut Game, + #[default] chunks_to_send: &mut ChunksToSend, + world: &mut World, +) { + if world.try_get::<Player>(event.entity).is_none() { + return; + } + + // The client likes it if we send closer chunks first, + // so we'll sort by the Manhattan distance to the player. + let mut pending_send = BumpVec::new_in(game.bump()); + pending_send.extend(find_new_chunks( + event.old, + event.new, + game.config.server.view_distance, + )); + pending_send.sort_unstable_by_key(|chunk| chunk.manhattan_distance_to(event.new)); + + for chunk in pending_send { + send_chunk_to_player(game, world, chunks_to_send, event.entity, chunk); + } + + for chunk in find_old_chunks(event.old, event.new, game.config.server.view_distance) { + unload_chunk_for_player(game, world, chunk, event.entity); + } +} + +/// System which sends new entities and removes old entities +/// when a player crosses into a new view. +#[fecs::event_handler] +pub fn on_chunk_cross_update_entities(event: &ChunkCrossEvent, game: &mut Game, world: &mut World) { + let network = match world.try_get::<Network>(event.entity) { + Some(net) => net, + None => return, // not a player + }; + + // Send newly visible entities. + let mut sends_to_trigger = vec![]; + for other in find_new_chunks(event.old, event.new, game.config.server.view_distance) + .flat_map(|chunk| game.chunk_entities.entities_in_chunk(chunk)) + .filter(|other| **other != event.entity) + // don't send player to themselves! + { + if let Some(creator) = world.try_get::<SpawnPacketCreator>(*other) { + let accessor = world + .entity(*other) + .expect("entity in chunk entities does not exist"); + let packet = creator.get(&accessor); + + network.send_boxed(packet); + sends_to_trigger.push((*other, event.entity)); + } + + // if this `other` is a player, also send `entity` to other + if let Some(network) = world.try_get::<Network>(*other) { + if let Some(creator) = world.try_get::<SpawnPacketCreator>(event.entity) { + let accessor = world.entity(event.entity).expect("entity does not exist"); + let packet = creator.get(&accessor); + + network.send_boxed(packet); + sends_to_trigger.push((event.entity, *other)); + } + } + } + + // Tell the client to despawn entities which are no longer visible. + let mut to_client_remove_trigger = vec![]; + to_client_remove_trigger.extend( + find_old_chunks(event.old, event.new, game.config.server.view_distance) + .flat_map(|chunk| game.chunk_entities.entities_in_chunk(chunk)) + .map(|other| (*other, event.entity)), + ); + + // Despawn this entity on other visible clients. + find_old_chunks(event.old, event.new, game.config.server.view_distance) + .flat_map(|chunk| game.chunk_entities.entities_in_chunk(chunk)) + .filter_map(|entity| world.try_get::<Network>(*entity).map(|net| (*entity, net))) + .for_each(|(other, network)| { + let packet = DestroyEntities { + entity_ids: vec![world.get::<NetworkId>(event.entity).0], + }; + network.send(packet); + to_client_remove_trigger.push((event.entity, other)); + }); + + let to_destroy = to_client_remove_trigger + .iter() + .filter_map(|(other, _)| world.try_get::<NetworkId>(*other).map(|id| id.0)) + .collect::<Vec<_>>(); + + if !to_destroy.is_empty() { + let packet = DestroyEntities { + entity_ids: to_destroy, + }; + network.send(packet); + } + + drop(network); + + // Trigger on_entity_send + for (entity, client) in sends_to_trigger { + game.handle(world, EntitySendEvent { entity, client }); + } + + // Trigger on_entity_client_remove + for (other, to) in to_client_remove_trigger { + game.handle( + world, + EntityClientRemoveEvent { + entity: other, + client: to, + }, + ); + } +} + +/// Returns new chunks visible from a new chunk position. +fn find_new_chunks( + old: Option<ChunkPosition>, + new: ChunkPosition, + view_distance: u8, +) -> impl Iterator<Item = ChunkPosition> { + let within_view_distance = chunks_within_view_distance(new, view_distance); + if let Some(old) = old { + Either::Left(within_view_distance.filter(move |chunk| { + (chunk.x - old.x).abs() >= view_distance as i32 + || (chunk.z - old.z).abs() >= view_distance as i32 + })) + } else { + Either::Right(within_view_distance) + } +} + +/// Returns chunks which are no longer visible from a new chunk position. +fn find_old_chunks( + old: Option<ChunkPosition>, + new: ChunkPosition, + view_distance: u8, +) -> impl Iterator<Item = ChunkPosition> { + if let Some(old) = old { + Either::Left( + chunks_within_view_distance(old, view_distance).filter(move |chunk| { + (chunk.x - new.x).abs() >= view_distance as i32 + || (chunk.z - new.z).abs() >= view_distance as i32 + }), + ) + } else { + Either::Right(iter::empty()) + } +} + +/// Finds all chunks within the view distance of a given chunk. +fn chunks_within_view_distance( + chunk: ChunkPosition, + view_distance: u8, +) -> impl Iterator<Item = ChunkPosition> { + let view_distance = i32::from(view_distance); + + (-view_distance..=view_distance).flat_map(move |x| { + (-view_distance..=view_distance).map(move |z| chunk.add(ChunkPosition::new(x, z))) + }) +} + +/// Resource containing a mapping from chunks -> sets of players indicating +/// which chunks are pending to send to a given player. +#[derive(Default)] +pub struct ChunksToSend(AHashMap<ChunkPosition, SmallVec<[Entity; 2]>>); + +/// Asynchronously sends a chunk to a player. +fn send_chunk_to_player( + game: &mut Game, + world: &mut World, + chunks_to_send: &mut ChunksToSend, + player: Entity, + chunk_pos: ChunkPosition, +) { + if !world.is_alive(player) { + return; + } + + // Ensure that the chunk isn't unloaded while the player has it loaded. + game.handle( + world, + HoldChunkRequest { + player, + chunk: chunk_pos, + }, + ); + + // If the chunk is already loaded, send it. Otherwise, we need to + // queue it for loading. + if let Some(chunk) = game.chunk_map.chunk_handle_at(chunk_pos) { + world.get::<Network>(player).send(create_chunk_data(chunk)); + game.handle( + world, + ChunkSendEvent { + player, + chunk: chunk_pos, + }, + ); + } else { + let contains = chunks_to_send.0.contains_key(&chunk_pos); + + let vec = match chunks_to_send.0.get_mut(&chunk_pos) { + Some(vec) => vec, + None => { + chunks_to_send.0.insert(chunk_pos, SmallVec::new()); + chunks_to_send.0.get_mut(&chunk_pos).unwrap() + } + }; + vec.push(player); + + if !contains { + // Queue chunk for loading if it isn't already. + game.handle(world, LoadChunkRequest { chunk: chunk_pos }); + } + } +} + +/// Unloads a chunk on a client. +fn unload_chunk_for_player( + game: &mut Game, + world: &mut World, + chunk: ChunkPosition, + player: Entity, +) { + // Release hold on chunk so it can be unloaded on the server + game.handle(world, ReleaseChunkRequest { player, chunk }); + + // Send Unload Chunk packet. + world.get::<Network>(player).send(UnloadChunk { + chunk_x: chunk.x, + chunk_z: chunk.z, + }); +} + +/// System which sends chunks to pending players when a chunk is loaded. +#[fecs::event_handler] +pub fn on_chunk_load_send_to_clients( + event: &ChunkLoadEvent, + game: &mut Game, + world: &mut World, + chunks_to_send: &mut ChunksToSend, +) { + if let Some(players) = chunks_to_send.0.get(&event.chunk) { + let chunk = game + .chunk_map + .chunk_handle_at(event.chunk) + .expect("chunk not loaded, but load event was triggered"); + for player in players { + if !world.is_alive(*player) { + continue; + } + + world + .get::<Network>(*player) + .send(create_chunk_data(Arc::clone(&chunk))); + game.handle( + world, + ChunkSendEvent { + chunk: event.chunk, + player: *player, + }, + ); + } + } + + chunks_to_send.0.remove(&event.chunk); +} + +/// Creates a chunk data packet for the given chunk. +fn create_chunk_data(chunk: ChunkHandle) -> ChunkData { + ChunkData { chunk } +} diff --git a/feather/old/server/src/event_handlers.rs b/feather/old/server/src/event_handlers.rs new file mode 100644 index 000000000..65ece9724 --- /dev/null +++ b/feather/old/server/src/event_handlers.rs @@ -0,0 +1,110 @@ +//! Defines the event handlers. +use feather_server_block::*; +use feather_server_chunk::*; +use feather_server_entity::*; +use feather_server_lighting::*; +use feather_server_player::*; +use feather_server_util::*; +use feather_server_weather::*; +use fecs::EventHandlers; + +macro_rules! event_handlers { + ($($handler:path,)*) => { + { + let handlers = EventHandlers::new() + $(.with($handler))*; + handlers + } + } +} + +pub fn build_event_handlers() -> EventHandlers { + event_handlers! { + on_block_update_notify_adjacent, + on_block_break_broadcast_effect, + on_block_update_broadcast, + on_block_update_notify_lighting_worker, + on_block_break_drop_loot, + on_chest_break_drop_contents, + on_block_update_create_block_entity, + on_chest_create_try_connect, + on_chest_break_try_disconnect, + + on_entity_despawn_remove_chunk_holder, + on_entity_despawn_update_chunk_entities, + on_entity_despawn_broadcast_despawn, + + on_block_entity_create_insert_to_map, + on_entity_spawn_update_chunk_entities, + on_entity_spawn_send_to_clients, + + on_entity_send_update_last_known_positions, + on_entity_send_send_equipment, + on_entity_send_send_metadata, + + on_entity_client_remove_update_last_known_positions, + + on_player_join_send_join_packets, + on_player_join_send_existing_entities, + on_player_join_send_time, + on_player_join_trigger_chunk_cross, + on_player_join_send_weather, + on_player_join_broadcast_join_message, + + on_player_leave_save_data, + + on_chunk_load_notify_lighting_worker, + on_chunk_load_send_to_clients, + on_chunk_load_queue_for_saving, + + on_chunk_holder_release_unload_chunk, + + on_chunk_cross_mark_modified, + on_chunk_cross_update_chunks, + on_chunk_cross_update_chunk_entities, + on_chunk_cross_update_entities, + + on_chunk_send_join_player, + + on_damage_item, + + on_inventory_update_send_set_slot, + on_inventory_update_broadcast_equipment_update, + + on_player_animation_broadcast_animation, + + on_item_drop_spawn_item_entity, + + on_item_collect_broadcast, + + on_weather_change_broadcast_weather, + + on_chat_broadcast, + + on_entity_land_remove_falling_block, + + load_chunk_request, + + release_chunk_request, + + hold_chunk_request, + + on_finish_digging_remove_animation, + + on_start_digging_init_stage, + + on_gamemode_update_update_capabilities, + on_gamemode_update_send, + + on_health_update_send, + + on_player_death_scatter_inventory, + on_player_death_mark_dead, + + on_chest_open_increment_viewers, + + on_chest_close_decrement_viewers, + + on_time_update, + } +} diff --git a/feather/old/server/src/init.rs b/feather/old/server/src/init.rs new file mode 100644 index 000000000..ecc7cf5fb --- /dev/null +++ b/feather/old/server/src/init.rs @@ -0,0 +1,347 @@ +//! Startup logic. + +use crate::{event_handlers, systems}; +use anyhow::Context; +use feather_core::anvil::level::{LevelData, LevelGeneratorType}; +use feather_core::util::ChunkPosition; +use feather_server_chunk::{chunk_worker, ChunkWorkerHandle}; +use feather_server_config::DEFAULT_CONFIG_STR; +use feather_server_network::NetworkIoManager; +use feather_server_packet_buffer::PacketBuffers; +use feather_server_types::{task, BanInfo, Config, Game, Shared, ShutdownChannels}; +use feather_server_worldgen::{ + ComposableGenerator, EmptyWorldGenerator, SuperflatWorldGenerator, WorldGenerator, +}; +use fecs::{EntityBuilder, Executor, OwnedResources, ResourcesProvider, World}; +use fxhash::FxHasher; +use rand::Rng; +use std::hash::{Hash, Hasher}; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, RwLock}; +use tokio::fs::File; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::TcpListener; +use tokio::{io, runtime}; + +/// Intializes the server. +pub async fn init( + runtime: runtime::Handle, +) -> anyhow::Result<(Executor, Arc<OwnedResources>, World)> { + let mut executor = systems::build_executor(); + let mut event_handlers = event_handlers::build_event_handlers(); + + let mut world = World::new(); + let mut resources = OwnedResources::new(); + executor.set_up(&mut resources, &mut world); + event_handlers.set_up(&mut resources, &mut world); + + println!("Loading configuration"); + let config = load_config() + .await + .context("Failed to load configuration file `feather.toml`")?; + set_up_logging(&config).context("Failed to initialize logging")?; + + log::info!("Loading ban list"); + let ban_info = load_ban_info() + .await + .context("Failed to load ban list `bans.toml`")?; + + log::info!("Loading world save"); + let level = load_level(&config) + .await + .context("Failed to load level file (is your world directory corrupted?)")?; + + let cworker_handle = create_cworker_handle(&config, &level); + + let mut game = Game { + shared: Arc::new(Shared { + config: Arc::clone(&config), + rng: Default::default(), + player_count: Arc::new(Default::default()), + }), + chunk_map: Default::default(), + tick_count: 0, + chunk_holders: Default::default(), + block_entities: Default::default(), + level, + chunk_entities: Default::default(), + time: Default::default(), + event_handlers: Arc::new(event_handlers), + resources: Arc::new(Default::default()), // we override this momentarily + bump: Default::default(), + game_rules: Default::default(), + }; + task::init(runtime); + let packet_buffers = Arc::new(PacketBuffers::new()); + + log::info!("Queueing spawn chunks for loading"); + load_spawn_chunks(&mut game, &mut world, &cworker_handle); + + log::info!("Creating RSA keypair"); + feather_server_network::init(); + + log::info!("Initializing block ID mappings"); + feather_core::blocks::init(); + + log::info!("Starting networking task"); + let networking_handle = create_networking_handle( + Arc::clone(&config), + Arc::clone(&ban_info), + &game, + Arc::clone(&packet_buffers), + ) + .await + .context("Failed to start the networking task")?; + + let resources = create_resources( + resources, + game, + cworker_handle, + networking_handle, + packet_buffers, + ban_info, + ); + + Ok((executor, resources, world)) +} + +async fn load_config() -> anyhow::Result<Arc<Config>> { + const PATH: &str = "feather.toml"; + + match File::open(PATH).await { + Ok(mut file) => Config::load_from_file(&mut file).await, + Err(e) if e.kind() == io::ErrorKind::NotFound => { + println!("Missing configuration file; creating a default one for you."); + + let mut file = File::create(PATH).await?; + file.write_all(DEFAULT_CONFIG_STR.as_bytes()).await?; + + let config = Config::default(); + Ok(config) + } + Err(e) => Err(e.into()), + } + .map(Arc::new) +} + +async fn load_ban_info() -> anyhow::Result<Arc<RwLock<BanInfo>>> { + const PATH: &str = "bans.toml"; + + match File::open(PATH).await { + Ok(mut file) => BanInfo::load_from_file(&mut file).await, + Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(BanInfo::default()), + Err(e) => Err(e.into()), + } + .map(RwLock::new) + .map(Arc::new) +} + +fn set_up_logging(config: &Config) -> anyhow::Result<()> { + use log::Level::*; + let level = match config.log.level.as_str() { + "error" => Error, + "warn" => Warn, + "info" => Info, + "debug" => Debug, + "trace" => Trace, + x => anyhow::bail!( + "invalid logging level {} (please check your config file)", + x + ), + }; + + simple_logger::init_with_level(level).map_err(Into::into) +} + +async fn load_level(config: &Config) -> anyhow::Result<LevelData> { + const LEVEL_FILE_NAME: &str = "level.dat"; + let world_dir = Path::new(&config.world.name); + + // Create world directory (silently fail if it already exists) + let _ = tokio::fs::create_dir(world_dir).await; + + let mut level_path = PathBuf::new(); + level_path.push(world_dir); + level_path.push(LEVEL_FILE_NAME); + + match File::open(&level_path).await { + Ok(mut file) => LevelData::load_from_file(&mut file).await, + Err(e) if e.kind() == io::ErrorKind::NotFound => { + log::info!("World save not found; creating it"); + let level = generate_level(config); + let mut file = File::create(&level_path).await?; + level.save_to_file(&mut file).await?; + + Ok(level) + } + Err(e) => Err(e.into()), + } +} + +fn generate_level(config: &Config) -> LevelData { + let seed = seed_for_config(config); + let world_name = &config.world.name; + log::info!("Using seed {} for world '{}'", seed, world_name); + + // TODO: Generate spawn position properly + LevelData { + allow_commands: false, + border_center_x: 0.0, + border_center_z: 0.0, + border_damage_per_block: 0.0, + border_safe_zone: 0.0, + border_size: 0.0, + clear_weather_time: 0, + data_version: 0, + day_time: 0, + difficulty: 0, + difficulty_locked: 0, + game_type: 0, + hardcore: false, + initialized: false, + last_played: 0, + raining: false, + rain_time: 0, + seed, + spawn_x: 0, + spawn_y: 100, + spawn_z: 0, + thundering: false, + thunder_time: 0, + time: 0, + version: Default::default(), + generator_name: config.world.generator.to_string(), + generator_options: None, + } +} + +fn seed_for_config(config: &Config) -> i64 { + let seed_raw = &config.world.seed; + // Empty seed: random + // Seed is valid i64: parse + // Seed is something else: hash + if seed_raw.is_empty() { + rand::thread_rng().gen() + } else { + match seed_raw.parse::<i64>() { + Ok(seed_int) => seed_int, + Err(_) => hash_seed(seed_raw.as_str()), + } + } +} + +fn hash_seed(seed_raw: &str) -> i64 { + // use FxHash instead of DefaultHasher because + // it's deterministic + let mut hasher = FxHasher::default(); + seed_raw.hash(&mut hasher); + hasher.finish() as i64 +} + +fn create_cworker_handle(config: &Config, level: &LevelData) -> ChunkWorkerHandle { + let generator: Arc<dyn WorldGenerator> = match level.generator_type() { + LevelGeneratorType::Flat => Arc::new(SuperflatWorldGenerator { + options: level.clone().generator_options.unwrap_or_default(), + }), + LevelGeneratorType::Default => { + Arc::new(ComposableGenerator::default_with_seed(level.seed as u64)) + } + _ => Arc::new(EmptyWorldGenerator {}), + }; + + let (tx, rx) = chunk_worker::start(Path::new(&config.world.name), generator); + ChunkWorkerHandle { + sender: tx, + receiver: rx, + } +} + +async fn create_networking_handle( + config: Arc<Config>, + ban_info: Arc<RwLock<BanInfo>>, + game: &Game, + packet_buffers: Arc<PacketBuffers>, +) -> anyhow::Result<NetworkIoManager> { + let server_icon = load_server_icon() + .await + .context("failed to load server icon `server-icon.png` (is it corrupted?)")?; + + let addr = format!("{}:{}", config.server.address, config.server.port); + let socket = TcpListener::bind(&addr) + .await + .context("failed to bind to port (is another server instance already running?)")?; + + log::info!("Listening on {}", addr); + + Ok(NetworkIoManager::start( + socket, + config, + ban_info, + Arc::clone(&game.player_count), + Arc::new(server_icon), + packet_buffers, + )) +} + +async fn load_server_icon() -> anyhow::Result<Option<String>> { + match File::open("server-icon.png").await { + Ok(mut file) => { + let mut buf = vec![]; + file.read_to_end(&mut buf).await?; + + let encoded = base64::encode(&buf); + Ok(Some(format!("data:image/png;base64,{}", encoded))) + } + Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(None), + Err(e) => Err(e.into()), + } +} + +/// Loads the chunks around the spawn area and creates +/// a chunk hold on those chunks to prevent them from +/// being unloaded. +/// +/// Note that these chunks are loaded asynchronously, +/// and this function will return before loading is complete. +fn load_spawn_chunks(game: &mut Game, world: &mut World, cworker_handle: &ChunkWorkerHandle) { + let view_distance = i32::from(game.config.server.view_distance); + + // Create an entity for the server and + // add chunk holders using it. + let server_entity = EntityBuilder::new().build().spawn_in(world); + + let offset_x = game.level.spawn_x / 16; + let offset_z = game.level.spawn_z / 16; + for x in -view_distance..=view_distance { + for z in -view_distance..=view_distance { + let chunk = ChunkPosition::new(x + offset_x, z + offset_z); + + feather_server_chunk::load_chunk(cworker_handle, chunk); + game.chunk_holders.insert_holder(chunk, server_entity); + } + } +} + +fn create_resources( + resources: OwnedResources, + game: Game, + cworker_handle: ChunkWorkerHandle, + networking_handle: NetworkIoManager, + packet_buffers: Arc<PacketBuffers>, + ban_info: Arc<RwLock<BanInfo>>, +) -> Arc<OwnedResources> { + let resources = { + let resources = resources + .with(game) + .with(cworker_handle) + .with(networking_handle) + .with(packet_buffers) + .with(ban_info) + .with(ShutdownChannels::new()); + Arc::new(resources) + }; + + resources.get_mut::<Game>().resources = Arc::clone(&resources); + + resources +} diff --git a/feather/old/server/src/lib.rs b/feather/old/server/src/lib.rs new file mode 100644 index 000000000..0ac3b0023 --- /dev/null +++ b/feather/old/server/src/lib.rs @@ -0,0 +1,144 @@ +//! Feather, a Minecraft server implementation in Rust. +//! +//! For extensive developer documentation, please see [the book](https://feather-rs.github.io/book). + +use feather_server_chunk::ChunkWorkerHandle; +use feather_server_lighting::LightingWorkerHandle; +use feather_server_types::{BanInfo, Game, ShutdownChannels, TPS}; +use fecs::{Executor, OwnedResources, ResourcesProvider, World}; +use spin_sleep::LoopHelper; +use std::ops::Deref; +use std::panic::AssertUnwindSafe; +use std::process::exit; +use std::sync::{Arc, RwLock}; +use tokio::runtime; + +mod event_handlers; +mod init; +mod shutdown; +mod systems; + +struct FullState { + resources: Arc<OwnedResources>, + world: World, + executor: Executor, + shutdown_rx: crossbeam::Receiver<()>, +} + +pub async fn main(runtime: runtime::Handle) { + log::info!("Starting Feather; please wait"); + let (executor, resources, world) = match init::init(runtime).await { + Ok(res) => res, + Err(e) => { + // Logging might not have been initialized yet - init it and ignore errors + let _ = simple_logger::init(); + log::error!("Failed to start server: {:?}", e); + log::error!("Exiting"); + exit(1); + } + }; + + // Shutdown channels from wrapper resource are used to notify server thread of shutdown + let (shutdown_tx, shutdown_rx) = { + let channels = resources.get::<ShutdownChannels>(); + (channels.tx.clone(), channels.rx.clone()) + }; + shutdown::init(shutdown_tx); + + let state = FullState { + resources, + executor, + world, + shutdown_rx, + }; + + log::info!("Server started"); + let mut state = run_ticking_thread(state).await; + + log::info!("Shutting down"); + if let Err(e) = shut_down(&state.resources, &mut state.world).await { + log::error!("An error occurred while shutting down: {:?}", e); + log::error!("Exiting."); + exit(1); + } + + log::info!("Goodbye"); +} + +/// Starts the ticking thread. The returned future will complete +/// once the thread has terminated (i.e. the shutdown signal +/// has been received.) +async fn run_ticking_thread(mut state: FullState) -> FullState { + use std::thread; + use tokio::sync::oneshot; + let (tx, rx) = oneshot::channel(); + + thread::Builder::new() + .name(String::from("feather")) + .spawn(move || { + match std::panic::catch_unwind(AssertUnwindSafe(|| { + run_loop(&mut state); + })) { + Ok(_) => (), + Err(_) => { + log::error!("The server crashed. This is a bug."); + log::error!( + "Please report this at https://github.com/feather-rs/feather/issues" + ); + } + } + + tx.send(state).ok().expect("failed to exit server thread"); + }) + .expect("failed to spawn ticking thread"); + + rx.await.unwrap() +} + +/// Runs the main game loop. +fn run_loop(state: &mut FullState) { + let mut loop_helper = LoopHelper::builder().build_with_target_rate(TPS as f64); + loop { + if state.shutdown_rx.try_recv().is_ok() { + // Shut down + return; + } + + loop_helper.loop_start(); + + // Execute all systems + state + .executor + .execute(state.resources.deref(), &mut state.world); + // Clean up world + state.world.defrag(Some(256)); // should this be done at an interval rate? + + loop_helper.loop_sleep(); + } +} + +async fn shut_down(resources: &OwnedResources, world: &mut World) -> anyhow::Result<()> { + log::info!("Disconnecting players"); + shutdown::disconnect_players(&world)?; + log::info!("Shutting down workers"); + shutdown::shut_down_workers( + &*resources.get::<Game>(), + &*resources.get::<LightingWorkerHandle>(), + )?; + log::info!("Saving chunks"); + shutdown::save_chunks( + &*resources.get::<Game>(), + &*resources.get::<ChunkWorkerHandle>(), + &world, + )?; + log::info!("Saving level.dat"); + shutdown::save_level(&mut *resources.get_mut::<Game>()).await?; + log::info!("Saving player data"); + shutdown::save_player_data(&*resources.get::<Game>(), &world)?; + log::info!("Saving ban list"); + shutdown::save_ban_list(&resources.get::<Arc<RwLock<BanInfo>>>()).await?; + log::info!("Waiting for tasks to finish"); + shutdown::wait_for_task_completion().await?; + + Ok(()) +} diff --git a/feather/old/server/src/main.rs b/feather/old/server/src/main.rs new file mode 100644 index 000000000..97135c877 --- /dev/null +++ b/feather/old/server/src/main.rs @@ -0,0 +1,16 @@ +use tokio::runtime; + +fn main() { + // Start Tokio runtime, then call lib::main(). + let mut runtime = runtime::Builder::new() + .threaded_scheduler() + .enable_all() + .build() + .expect("failed to start Tokio runtime"); + + let handle = runtime.handle().clone(); + + runtime.block_on(async move { + feather_server::main(handle).await; + }); +} diff --git a/feather/old/server/src/shutdown.rs b/feather/old/server/src/shutdown.rs new file mode 100644 index 000000000..04c9ea2cd --- /dev/null +++ b/feather/old/server/src/shutdown.rs @@ -0,0 +1,99 @@ +//! Shutdown behavior. +use anyhow::Context; +use feather_core::network::packets::DisconnectPlay; +use feather_core::text::{TextRoot, TextValue}; +use feather_server_chunk::chunk_worker::Request; +use feather_server_chunk::{save_chunk_at, ChunkWorkerHandle}; +use feather_server_lighting::LightingWorkerHandle; +use feather_server_types::{tasks, BanInfo, Game, Network, Player}; +use fecs::{IntoQuery, Read, World}; +use std::sync::{Arc, RwLock}; +use tokio::fs::File; +use tokio::io::AsyncWriteExt; + +pub fn init(tx: crossbeam::Sender<()>) { + ctrlc::set_handler(move || tx.try_send(()).unwrap()).unwrap(); +} + +pub fn disconnect_players(world: &World) -> anyhow::Result<()> { + <Read<Network>>::query().for_each(world.inner(), |network| { + let packet = DisconnectPlay { + reason: TextRoot::from(TextValue::translate( + "multiplayer.disconnect.server_shutdown", + )) + .into(), + }; + + network.send(packet); + }); + + Ok(()) +} + +pub fn save_chunks( + game: &Game, + cworker_handle: &ChunkWorkerHandle, + world: &World, +) -> anyhow::Result<()> { + for chunk in game.chunk_map.iter_chunks() { + let pos = chunk.read().position(); + save_chunk_at(game, world, pos, cworker_handle); + } + + // Wait for chunk worker to shut down + let _ = cworker_handle.sender.send(Request::ShutDown); + + while cworker_handle.receiver.recv().is_ok() {} + + Ok(()) +} + +pub async fn save_level(game: &mut Game) -> anyhow::Result<()> { + // Sync world time + level time + let time = game.time.world_age() as i64; + game.level.time = time; + + let level_path = format!("{}/{}", game.config.world.name, "level.dat"); + + let mut file = File::create(&level_path).await?; + game.level + .save_to_file(&mut file) + .await + .context("failed to save level file")?; + + file.flush().await?; + + Ok(()) +} + +pub fn save_player_data(game: &Game, world: &World) -> anyhow::Result<()> { + <Read<Player>>::query().for_each_entities(&world.inner(), |(player, _)| { + feather_server_chunk::save_player_data(game, world, player); + }); + + Ok(()) +} + +pub async fn wait_for_task_completion() -> anyhow::Result<()> { + tasks().wait().await; + Ok(()) +} + +pub fn shut_down_workers(_game: &Game, light_handle: &LightingWorkerHandle) -> anyhow::Result<()> { + let _ = light_handle + .tx + .send(feather_server_lighting::Request::ShutDown); + + // wait for disconnect + let _ = light_handle.shutdown_rx.recv(); + Ok(()) +} + +pub async fn save_ban_list(ban_info: &Arc<RwLock<BanInfo>>) -> anyhow::Result<()> { + const PATH: &str = "bans.toml"; + + match File::create(PATH).await { + Ok(mut file) => ban_info.read().unwrap().save_to_file(&mut file).await, + Err(e) => Err(e.into()), + } +} diff --git a/feather/old/server/src/systems.rs b/feather/old/server/src/systems.rs new file mode 100644 index 000000000..61d83ac68 --- /dev/null +++ b/feather/old/server/src/systems.rs @@ -0,0 +1,51 @@ +//! Defines all systems and the order in which they are executed. + +use fecs::Executor; + +use feather_server_chunk as chunk_logic; +use feather_server_entity as entity; +use feather_server_physics as physics; +use feather_server_player as player; +use feather_server_types as game; +use feather_server_util as util; +use feather_server_weather as weather; + +pub fn build_executor() -> Executor { + Executor::new() + .with(player::poll_player_disconnect) + .with(player::poll_new_clients) + .with(physics::entity_physics) + .with(player::handle_movement_packets) + .with(player::handle_close_window) + .with(player::handle_creative_inventory_action) + .with(player::handle_click_windows) + .with(player::handle_held_item_change) + .with(player::handle_animation) + .with(player::handle_player_block_placement) + .with(player::handle_player_use_item) + .with(player::handle_player_digging) + .with(player::advance_dig_progress) + .with(player::broadcast_block_break_animation) + .with(player::handle_client_status) + .with(player::handle_chat) + .with(player::flush_player_message_receiver) + .with(game::task::run_sync_tasks) + .with(player::send_teleported) + .with(weather::update_weather) + .with(entity::item::item_collect) + .with(chunk_logic::handle_chunk_worker_replies) + .with(chunk_logic::chunk_unload) + .with(chunk_logic::chunk_optimize) + .with(player::check_crossed_chunks) + .with(player::broadcast_keepalive) + .with(entity::broadcast_movement) + .with(entity::update_blocks_fallen) + .with(entity::broadcast_velocity) + .with(entity::falling_block::spawn_falling_blocks) + .with(entity::supported_blocks::break_unsupported_blocks) + .with(chunk_logic::chunk_save) + .with(game::reset_bump_allocators) + .with(game::increment_tick_count) + .with(util::increment_time) + .with(entity::previous_position_velocity_reset) // should be at end +} diff --git a/feather/old/server/template/Cargo.toml b/feather/old/server/template/Cargo.toml new file mode 100644 index 000000000..029c17f6f --- /dev/null +++ b/feather/old/server/template/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "feather-server-template" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } diff --git a/feather/old/server/template/src/lib.rs b/feather/old/server/template/src/lib.rs new file mode 100644 index 000000000..45278f224 --- /dev/null +++ b/feather/old/server/template/src/lib.rs @@ -0,0 +1 @@ +#![forbid(unsafe_code)] diff --git a/feather/old/server/test/Cargo.toml b/feather/old/server/test/Cargo.toml new file mode 100644 index 000000000..59c1cf457 --- /dev/null +++ b/feather/old/server/test/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "feather-test-framework" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } +feather-server-chunk = { path = "../chunk" } +feather-server-player = { path = "../player" } +feather-server-network = { path = "../network" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +crossbeam = "0.7" +flume = "0.7" +tokio = { version = "0.2", features = ["full"] } diff --git a/feather/old/server/test/src/lib.rs b/feather/old/server/test/src/lib.rs new file mode 100644 index 000000000..e498bc052 --- /dev/null +++ b/feather/old/server/test/src/lib.rs @@ -0,0 +1,8 @@ +//! A testing framework for `feather-server`. Provides +//! functions for both unit and integration testing. + +#![forbid(unsafe_code)] + +mod unit; + +pub use unit::Test; diff --git a/feather/old/server/test/src/unit.rs b/feather/old/server/test/src/unit.rs new file mode 100644 index 000000000..2ecf7d811 --- /dev/null +++ b/feather/old/server/test/src/unit.rs @@ -0,0 +1,371 @@ +//! Unit testing framework. + +use feather_core::anvil::entity::{AnimalData, BaseEntityData}; +use feather_core::anvil::player::PlayerData; +use feather_core::network::{cast_packet, Packet}; +use feather_core::{ + chunk::Chunk, + chunk_map::ChunkMap, + util::{vec3, ChunkPosition, Position}, +}; +use feather_server_chunk::{ + chunk_worker, hold_chunk_request, release_chunk_request, ChunkWorkerHandle, +}; +use feather_server_network::NewClientInfo; +use feather_server_player::on_chunk_cross_update_chunks; +use feather_server_types::{ + ChunkCrossEvent, ChunkHolder, Game, Name, NetworkId, ServerToWorkerMessage, Shared, Uuid, + WorkerToServerMessage, +}; +use feather_server_util::on_chunk_cross_update_chunk_entities; +use fecs::{ + Entity, EntityBuilder, Event, EventHandlers, Executor, OwnedResources, RawEventHandler, + RawSystem, RefResources, ResourcesEnum, ResourcesProvider, World, +}; +use std::any::Any; +use std::borrow::Cow; +use std::collections::HashMap; +use std::net::{IpAddr, SocketAddr}; +use std::ops::Deref; +use std::sync::{Arc, Mutex}; + +struct TrackedPlayer { + /// IO worker-side receiver + worker_rx: Mutex<flume::Receiver<ServerToWorkerMessage>>, + _worker_tx: flume::Sender<WorkerToServerMessage>, + + buffered_sent_packets: Vec<Box<dyn Packet>>, + disconnected: bool, +} + +pub struct Test { + pub game: Game, + pub world: World, + pub cworker_tester: ChunkWorkerTester, + players: HashMap<Entity, TrackedPlayer>, +} + +impl Default for Test { + fn default() -> Self { + Self::new() + } +} + +impl Test { + /// Starts a new `Test`. + pub fn new() -> Self { + let (cworker_tester, cworker_handle) = ChunkWorkerTester::new(); + let mut world = World::new(); + let game = Self::create_game(cworker_handle, &mut world); + + Self { + game, + world, + cworker_tester, + players: HashMap::new(), + } + } + + fn create_game(cworker_handle: ChunkWorkerHandle, world: &mut World) -> Game { + let mut resources = OwnedResources::new(); + + let mut event_handlers = EventHandlers::new() + .with(hold_chunk_request) + .with(release_chunk_request); + event_handlers.set_up(&mut resources, world); + + let mut chunk_map = ChunkMap::new(); + for x in -1..=1 { + for z in -1..=1 { + chunk_map.insert(Chunk::new(ChunkPosition::new(x, z))); + } + } + + let mut game = Game { + chunk_map, + tick_count: 0, + chunk_holders: Default::default(), + level: Default::default(), + chunk_entities: Default::default(), + block_entities: Default::default(), + time: Default::default(), + event_handlers: Arc::new(event_handlers), + resources: Arc::new(Default::default()), + bump: Default::default(), + shared: Arc::new(Shared { + config: Arc::new(Default::default()), + rng: Default::default(), + player_count: Arc::new(Default::default()), + }), + game_rules: Default::default(), + }; + resources.insert(cworker_handle); + + let resources = Arc::new(resources); + game.resources = resources; + game + } + + /// Adds a resource into the resource set. + pub fn with_resource(mut self, resource: impl Any + Send + Sync) -> Self { + let resources = Arc::get_mut(&mut self.game.resources).expect("resources already borrowed"); + resources.insert(resource); + + self + } + + /// Runs a system for this `Test`. + pub fn run(&mut self, mut system: impl RawSystem) -> &mut Self { + system.set_up( + Arc::get_mut(&mut self.game.resources).expect("resources already borrowed"), + &mut self.world, + ); + self.exec_with_resources(move |world, resources| { + system.run(resources, world, &Executor::new()) + }); + self + } + + /// Handles an event with the given handler. + pub fn handle<E>(&mut self, event: E, mut handler: impl RawEventHandler<Event = E>) -> &mut Self + where + E: Event, + { + handler.set_up( + Arc::get_mut(&mut self.game.resources).expect("resources already borrowed"), + &mut self.world, + ); + self.exec_with_resources(move |world, resources| handler.handle(resources, world, &event)); + self + } + + fn exec_with_resources(&mut self, f: impl FnOnce(&mut World, &ResourcesEnum)) { + f( + &mut self.world, + &RefResources::new(Arc::clone(&self.game.resources).deref(), (&mut self.game,)) + .as_resources_ref(), + ); + } + + /// Executes a closure with access to `self`. + pub fn exec(&mut self, f: impl FnOnce(&mut Self)) -> &mut Self { + f(self); + self + } + + /// Runs a broadcast test routine. This: + /// * Creates three players, two of whom are able to see each other + /// * Calls `event` to trigger an event for the first player + /// * Asserts that no packet was sent to the third player, who is too far away + /// * Asserts that packet of type `P` was sent to the second player, returning it + pub fn broadcast_routine<P, E, F, H>( + &mut self, + event: F, + handler: H, + send_to_self: bool, + ) -> (P, Entity) + where + E: Event, + P: Packet, + F: FnOnce(&mut Self, Entity, Entity) -> E, + H: RawEventHandler<Event = E>, + { + use feather_core::position; + let player1 = self.player("", position!(0.0, 64.0, 0.0)); + let player2 = self.player("", position!(45.0, 1000.0, -37.9)); + let player3 = self.player("", position!(1000.0, -450.0, 100.0)); + + let event = event(self, player1, player2); + self.handle(event, handler); + + if !send_to_self { + assert!(self.sent::<P>(player1).is_none()); + } + assert!(self.sent::<P>(player3).is_none()); + + (self.sent::<P>(player2).unwrap(), player1) + } + + /// Creates a dummy player with the given name. + pub fn player(&mut self, name: impl Into<Cow<'static, str>>, position: Position) -> Entity { + let mut name = name.into(); + + let (server_tx, worker_rx) = flume::unbounded(); + let (worker_tx, server_rx) = flume::unbounded(); + + let entity = EntityBuilder::new().build().spawn_in(&mut self.world); + + let info = NewClientInfo { + ip: SocketAddr::new(IpAddr::from([0, 0, 0, 1]), 25565), + username: name.to_mut().to_owned(), + profile: vec![], + uuid: Uuid::new_v4(), + data: PlayerData { + animal: AnimalData::new(BaseEntityData::new(position, vec3(0.0, 0.0, 0.0)), 20.0), + gamemode: 1, + inventory: vec![], + held_item: 0, + }, + position, + sender: server_tx, + receiver: server_rx, + entity, + }; + feather_server_player::create(&mut self.game, &mut self.world, info); + + self.players.insert( + entity, + TrackedPlayer { + worker_rx: Mutex::new(worker_rx), + _worker_tx: worker_tx, + buffered_sent_packets: vec![], + disconnected: false, + }, + ); + self.update_structures(entity, None, position); + entity + } + + /// Adds an entity with the given name and components. + pub fn entity(&mut self, builder: EntityBuilder) -> Entity { + let entity = builder.build().spawn_in(&mut self.world); + + if let Some(pos) = self.world.try_get::<Position>(entity).map(|r| *r) { + self.update_structures(entity, None, pos); + } + + entity + } + + /// Sets the position of an entity. + pub fn position(&mut self, entity: Entity, pos: Position) -> &mut Self { + let old = *self.world.get::<Position>(entity); + *self.world.get_mut::<Position>(entity) = pos; + + self.update_structures(entity, Some(old), pos); + + self + } + + /// Returns the network ID of an entity. + pub fn id(&self, entity: Entity) -> i32 { + self.world.get::<NetworkId>(entity).0 + } + + /// Returns the UUID of an entity. + pub fn uuid(&self, entity: Entity) -> Uuid { + *self.world.get::<Uuid>(entity) + } + + /// Returns the packet of type `P` sent to `player`. + pub fn sent<P>(&mut self, player: Entity) -> Option<P> + where + P: Packet, + { + let tracked = self.tracked_player(player); + + Self::update_player(tracked); + + Self::remove_player_buffered_packet(tracked) + } + + fn remove_player_buffered_packet<P>(player: &mut TrackedPlayer) -> Option<P> + where + P: Packet, + { + let index = player + .buffered_sent_packets + .iter() + .position(|p| Box::deref(p).as_any().downcast_ref::<P>().is_some()); + + index.map(|index| cast_packet(player.buffered_sent_packets.remove(index))) + } + + /// Verifies that the player with the given name was disconnected. + pub fn assert_disconnected(&mut self, player: Entity) -> &mut Self { + let tracked = self.tracked_player(player); + Self::update_player(tracked); + + assert!( + tracked.disconnected, + "player `{}` not disconnected", + self.world.get::<Name>(player).0 + ); + + self + } + + fn tracked_player(&mut self, player: Entity) -> &mut TrackedPlayer { + self.players + .get_mut(&player) + .unwrap_or_else(|| panic!("player `{}` does not exist", player)) + } + + fn update_player(player: &mut TrackedPlayer) { + for msg in player.worker_rx.lock().unwrap().try_iter() { + match msg { + ServerToWorkerMessage::SendPacket(packet) => { + player.buffered_sent_packets.push(packet) + } + ServerToWorkerMessage::Disconnect => player.disconnected = true, + } + } + } + + /// Updates acceleration structures required for tests to pass. + fn update_structures(&mut self, entity: Entity, old: Option<Position>, new: Position) { + let cross = ChunkCrossEvent { + old: old.map(Position::chunk), + new: new.chunk(), + entity, + }; + self.handle(cross, on_chunk_cross_update_chunk_entities); + + if self.world.has::<ChunkHolder>(entity) { + self.handle(cross, on_chunk_cross_update_chunks); + } + } + + /// Verifies that an entity is alive. + pub fn assert_alive(&mut self, entity: Entity) -> &mut Self { + assert!( + self.world.is_alive(entity), + "expected entity {:?} to be alive, but it was not", + entity + ); + self + } + + /// Verifies that en entity is dead. + pub fn assert_dead(&mut self, entity: Entity) -> &mut Self { + assert!( + !self.world.is_alive(entity), + "expected entity {:?} to be dead, but it was not", + entity + ); + self + } +} + +pub struct ChunkWorkerTester { + pub cworker_tx: crossbeam::Sender<chunk_worker::Reply>, + pub cworker_rx: crossbeam::Receiver<chunk_worker::Request>, +} + +impl ChunkWorkerTester { + fn new() -> (Self, ChunkWorkerHandle) { + let (cworker_tx, rx) = crossbeam::unbounded(); + let (tx, cworker_rx) = crossbeam::unbounded(); + + ( + Self { + cworker_rx, + cworker_tx, + }, + ChunkWorkerHandle { + receiver: rx, + sender: tx, + }, + ) + } +} diff --git a/feather/old/server/types/Cargo.toml b/feather/old/server/types/Cargo.toml new file mode 100644 index 000000000..45316cd3c --- /dev/null +++ b/feather/old/server/types/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "feather-server-types" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-config = { path = "../config" } +feather-server-packet-buffer = { path = "../packet_buffer" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +uuid = { version = "0.8", features = ["v4", "v3"] } +nalgebra-glm = "0.6" +ncollide3d = "0.22" +ahash = "0.3" +smallvec = "1.4" +rand = { version = "0.7", features = ["small_rng"] } +thread_local = "1.0" +bumpalo = { version = "3.2", features = ["collections"] } +log = "0.4" +flume = "0.7" +parking_lot = "0.10" +anyhow = "1.0" +inventory = "0.1" +dashmap = "3.11" +futures = "0.3" +tokio = { version = "0.2", features = ["full"] } +mojang-api = "0.6" +once_cell = "1.3" +crossbeam = "0.7" diff --git a/feather/old/server/types/src/components.rs b/feather/old/server/types/src/components.rs new file mode 100644 index 000000000..f06a29986 --- /dev/null +++ b/feather/old/server/types/src/components.rs @@ -0,0 +1,132 @@ +mod marker; +mod network; +mod physics; +mod serialize; + +pub use marker::*; +pub use serialize::*; + +pub use feather_core::inventory::Inventory; +pub use network::{Network, ServerToWorkerMessage, WorkerToServerMessage}; +pub use physics::{AABBExt, Physics, PhysicsBuilder}; +pub use uuid::Uuid; + +use ahash::AHashSet; +use dashmap::DashMap; +use feather_core::text::Text; +use feather_core::util::{ChunkPosition, Position}; +use fecs::Entity; + +/// The item an entity is currently holding. +/// +/// This is the index inside the `Hotbar` area +/// of the inventory. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct HeldItem(pub usize); + +/// An entity's name. +#[derive(Debug, Clone, Default)] +pub struct Name(pub String); + +/// Position of an entity on the previous tick. +#[derive(Copy, Clone, Debug, Default)] +pub struct PreviousPosition(pub Option<Position>); + +/// An entity's velocity. +#[derive(Copy, Clone, Debug)] +pub struct Velocity(pub glm::DVec3); + +impl Default for Velocity { + fn default() -> Self { + Velocity(glm::vec3(0.0, 0.0, 0.0)) + } +} + +/// Velocity of an entity on the previous tick. +#[derive(Copy, Clone, Debug, Default)] +pub struct PreviousVelocity(pub Option<glm::DVec3>); + +/// Network ID of an entity. +#[derive(Copy, Clone, Debug)] +pub struct NetworkId(pub i32); + +/// Component which stores which +/// chunks a given entity has a holder +/// on. +/// +/// Although this information is also +/// stored in the `ChunkHolders` resource, +/// using this component allows for efficiently +/// finding which chunks a given entity has +/// a hold on, rather than having +/// to linear search all chunks (obviously ridiculous). +#[derive(Default)] +pub struct ChunkHolder { + pub holds: AHashSet<ChunkPosition>, +} + +/// Component containing the last sent positions of all entities for a given client. +/// This component is used to determine +/// the relative movement for an entity. +#[derive(Default, Debug)] +pub struct LastKnownPositions(pub DashMap<Entity, Position>); + +/// Profile properties of a player. +#[derive(Debug, Clone)] +pub struct ProfileProperties(pub Vec<mojang_api::ProfileProperty>); + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(transparent)] +pub struct ParticleCount(pub u32); + +/// Component added to entities to which messages can be sent. +#[derive(Default, Debug)] +pub struct MessageReceiver { + /// Internal buffer of messages to send + buffer: Vec<Text>, +} + +impl MessageReceiver { + /// Sends a message to the entity. + pub fn send(&mut self, message: impl Into<Text>) { + self.buffer.push(message.into()); + } + + /// Flushes the message buffer, returning an iterator + /// over messages. + pub fn flush<'a>(&'a mut self) -> impl Iterator<Item = Text> + 'a { + self.buffer.drain(..) + } +} + +/// Component which stores a number which used for OpenWindow packets, incremented on every access +#[derive(Debug)] +pub struct OpenWindowCount { + count: u8, +} + +impl OpenWindowCount { + pub fn get_increment(&mut self) -> u8 { + self.count += 1; + self.count - 1 + } +} + +impl Default for OpenWindowCount { + fn default() -> Self { + OpenWindowCount { count: 1 } + } +} +/// Health of an entity. Measured in "half-hearts." +#[derive(Copy, Clone, Debug)] +pub struct Health(pub u32); + +/// Maximum health of an entity under normal conditions (i.e. excluding potion effects +/// such as absorption.) +#[derive(Copy, Clone, Debug)] +pub struct MaxHealth(pub u32); + +/// Stores the number of blocks fallen by an entity +/// since the last time they were on_ground. +#[derive(Default, Copy, Clone, Debug)] +pub struct BlocksFallen(pub f64); diff --git a/feather/old/server/types/src/components/marker.rs b/feather/old/server/types/src/components/marker.rs new file mode 100644 index 000000000..9810f1457 --- /dev/null +++ b/feather/old/server/types/src/components/marker.rs @@ -0,0 +1,37 @@ +//! "Marker" components: zero-sized structs which +//! can be used to filter for specific entities +//! in queries. + +/// Marks an entity as a block entity (sometimes called a "tile entity") +pub struct BlockEntity; + +/// Zero-sized marker component used to mark players. +pub struct Player; + +/// A player is in a gamemode where they may take damage. +pub struct CanTakeDamage; + +/// A player is in a gamemode where they may instantly break blocks. +pub struct CanInstaBreak; + +/// A player is allowed to break blocks. +pub struct CanBreak; + +/// Marks that a player has teleported and +/// we should force-update the client's +/// position. +/// +/// Only necessary for players. +pub struct Teleported; + +/// Whether an entity is able to respawn. +/// +/// If this component is added, then the entity +/// will not be removed from the `World` when it dies. +pub struct CanRespawn; + +/// Component for players who are currently on the respawn screen. +/// +/// Players with this component _should not be affected by gameplay actions_. +/// They should not collect items, take damage, etc. +pub struct Dead; diff --git a/feather/old/server/types/src/components/network.rs b/feather/old/server/types/src/components/network.rs new file mode 100644 index 000000000..595e0a182 --- /dev/null +++ b/feather/old/server/types/src/components/network.rs @@ -0,0 +1,42 @@ +use feather_core::network::Packet; +use parking_lot::Mutex; + +/// Network component containing channels to send and receive packets. +/// +/// Systems should call `Network::send` to send a packet to this entity (player). +pub struct Network { + pub tx: flume::Sender<ServerToWorkerMessage>, + pub rx: Mutex<flume::Receiver<WorkerToServerMessage>>, +} + +impl Network { + /// Sends a packet to this player. + pub fn send(&self, packet: impl Packet) { + self.send_boxed(Box::new(packet)); + } + + /// Sends a boxed packet to this player. + pub fn send_boxed(&self, packet: Box<dyn Packet>) { + // Discard error in case the channel was disconnected + // (e.g. if the player disconnected and its worker task + // shut down, and the disconnect was not yet registered + // by the server) + let _ = self.tx.try_send(ServerToWorkerMessage::SendPacket(packet)); + } +} + +/// Message sent from the server threads to a player's +/// IO task. +pub enum ServerToWorkerMessage { + /// Requests that a packet be sent to the client. + SendPacket(Box<dyn Packet>), + /// Requests that the client be disconnected. + Disconnect, +} + +/// Message sent from a player's IO task to the server threads. +#[derive(Debug)] +pub enum WorkerToServerMessage { + /// Notifies the server thread that the player disconnected. + NotifyDisconnected { reason: String }, +} diff --git a/server/src/physics/component.rs b/feather/old/server/types/src/components/physics.rs similarity index 91% rename from server/src/physics/component.rs rename to feather/old/server/types/src/components/physics.rs index f10a707ec..979991bde 100644 --- a/server/src/physics/component.rs +++ b/feather/old/server/types/src/components/physics.rs @@ -3,7 +3,6 @@ use glm::DVec3; use ncollide3d::bounding_volume::AABB; -use specs::{Component, VecStorage}; pub const DEFAULT_SLIP_MULTIPLIER: f64 = 0.6; @@ -13,7 +12,7 @@ pub const DEFAULT_SLIP_MULTIPLIER: f64 = 0.6; /// /// Typically, this component should be constructed using `PhysicsBuilder`. #[derive(Debug)] -pub struct PhysicsComponent { +pub struct Physics { /// This entity's bounding box. pub bbox: AABB<f64>, /// The drag coefficient for this entity. Each tick, @@ -33,18 +32,14 @@ pub struct PhysicsComponent { pub slip_multiplier: f64, } -impl Component for PhysicsComponent { - type Storage = VecStorage<Self>; -} - /// Builder for physics components. pub struct PhysicsBuilder { - comp: PhysicsComponent, + comp: Physics, } impl Default for PhysicsBuilder { fn default() -> Self { - let comp = PhysicsComponent { + let comp = Physics { bbox: bbox(0.5, 0.5, 0.5), drag: 0.98, gravity: -0.08, @@ -85,7 +80,7 @@ impl PhysicsBuilder { self } - pub fn build(self) -> PhysicsComponent { + pub fn build(self) -> Physics { self.comp } } diff --git a/feather/old/server/types/src/components/serialize.rs b/feather/old/server/types/src/components/serialize.rs new file mode 100644 index 000000000..27cd26d17 --- /dev/null +++ b/feather/old/server/types/src/components/serialize.rs @@ -0,0 +1,91 @@ +//! Components which involve serializing entities, +//! be it over the network or onto the disk. + +use crate::Game; +use feather_core::anvil::{block_entity::BlockEntityData, entity::EntityData}; +use feather_core::network::Packet; +use fecs::EntityRef; + +pub trait PacketCreatorFn: Fn(&EntityRef) -> Box<dyn Packet> + Send + Sync + 'static {} +impl<F> PacketCreatorFn for F where F: Fn(&EntityRef) -> Box<dyn Packet> + Send + Sync + 'static {} + +/// Component which defines a function returning a packet to send +/// to clients when the entity comes within range. This packet +/// spawns the entity on the client. +pub struct SpawnPacketCreator(pub &'static dyn PacketCreatorFn); + +impl SpawnPacketCreator { + /// Returns the packet to send to clients when the entity is to be + /// sent to the client. + pub fn get(&self, accessor: &EntityRef) -> Box<dyn Packet> { + let f = self.0; + + f(accessor) + } +} + +/// Component which defines a function returning a packet to send +/// to _all_ clients when the entity is created or the client joins. +/// This packet is sent before that returned by `SpawnPacketCreator`, +/// and it differs in that the packet is broadcasted globally +/// rather than to nearby clients. +/// +/// Another difference is that the packet from `SpawnPacketCreator` is not sent +/// to its own entity, while that from `CreationPacketCreator` is. +/// +/// An example of a use case for this packet is the `PlayerInfo` packet +/// sent when a player joins—it is sent to all players, not just those +/// that are able to see the player. +pub struct CreationPacketCreator(pub &'static dyn PacketCreatorFn); + +impl CreationPacketCreator { + /// Returns the packet to send to clients when the entity is created. + pub fn get(&self, accessor: &EntityRef) -> Box<dyn Packet> { + let f = self.0; + + f(accessor) + } +} + +pub trait ComponentSerializerFn: + Fn(&Game, &EntityRef) -> EntityData + Send + Sync + 'static +{ +} + +impl<F> ComponentSerializerFn for F where + F: Fn(&Game, &EntityRef) -> EntityData + Send + Sync + 'static +{ +} + +pub trait BlockSerializerFn: + Fn(&Game, &EntityRef) -> BlockEntityData + Send + Sync + 'static +{ +} + +impl<F> BlockSerializerFn for F where + F: Fn(&Game, &EntityRef) -> BlockEntityData + Send + Sync + 'static +{ +} + +/// Component which stores a function needed to convert an entity's +/// components to the serializable `EntityData`. +pub struct ComponentSerializer(pub &'static dyn ComponentSerializerFn); + +impl ComponentSerializer { + pub fn serialize(&self, game: &Game, accessor: &EntityRef) -> EntityData { + let f = self.0; + + f(game, accessor) + } +} + +/// Similar to `ComponentSerializer`, but for block entities (e.g. chests). +pub struct BlockSerializer(pub &'static dyn BlockSerializerFn); + +impl BlockSerializer { + pub fn serialize(&self, game: &Game, accessor: &EntityRef) -> BlockEntityData { + let f = self.0; + + f(game, accessor) + } +} diff --git a/feather/old/server/types/src/events.rs b/feather/old/server/types/src/events.rs new file mode 100644 index 000000000..66dc37aa7 --- /dev/null +++ b/feather/old/server/types/src/events.rs @@ -0,0 +1,315 @@ +use crate::Weather; +use feather_core::blocks::BlockId; +use feather_core::inventory::SlotIndex; +use feather_core::items::ItemStack; +use feather_core::util::{BlockPosition, ChunkPosition, ClientboundAnimation, Gamemode, Position}; +use fecs::Entity; +use smallvec::SmallVec; + +#[derive(Copy, Clone, Debug)] +pub struct BlockUpdateEvent { + /// Position of the updated block + pub pos: BlockPosition, + /// Old block + pub old: BlockId, + /// New block + pub new: BlockId, + /// Cause of the block update. + pub cause: BlockUpdateCause, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum BlockUpdateCause { + /// The update was caused by an entity performing + /// a block break/placement. Usually a player. + Entity(Entity), + /// So far only when a block that needs to be + /// supported loses it's support. + Unsupported, + /// Unknown cause. + Unknown, +} + +/// Triggered directly _before_ an entity is removed from the world. +/// +/// As such, components can still be accessed. +#[derive(Copy, Clone, Debug)] +pub struct EntityDespawnEvent { + pub entity: Entity, +} + +/// Triggered when an entity is killed. +/// +/// Always triggered _before_ `EntityDespawnEvent` +/// if the entity is despawned as well. +#[derive(Copy, Clone, Debug)] +pub struct EntityDeathEvent { + pub entity: Entity, +} + +/// Triggered when a chunk is sent to a player. +#[derive(Copy, Clone, Debug)] +pub struct ChunkSendEvent { + pub chunk: ChunkPosition, + pub player: Entity, +} + +/// Triggered right before a player joins the server. +#[derive(Copy, Clone, Debug)] +pub struct PlayerPreJoinEvent { + pub player: Entity, +} + +/// Triggered when a player joins the server. +#[derive(Copy, Clone, Debug)] +pub struct PlayerJoinEvent { + pub player: Entity, +} + +/// Triggered when a player leaves. +#[derive(Copy, Clone, Debug)] +pub struct PlayerLeaveEvent { + pub player: Entity, +} + +/// Triggered when an entity lands on the ground. +#[derive(Copy, Clone, Debug)] +pub struct EntityLandEvent { + pub entity: Entity, + /// Position where the entity landed. + pub pos: Position, +} + +/// Event triggered when an item is dropped. +/// +/// Before this event is triggered, the item +/// is removed from the player's inventory. +#[derive(Debug, Clone)] +pub struct ItemDropEvent { + /// The slot from which the item was dropped, + /// if known. + pub slot: Option<SlotIndex>, + /// The item stack which was dropped. + pub stack: ItemStack, + /// The player who dropped the item. + pub player: Entity, +} + +/// Event triggered when an item is collected into an entity's +/// inventory. +/// +/// Triggered before the item is deleted from the world. +#[derive(Debug, Clone)] +pub struct ItemCollectEvent { + /// The item which was collected. + pub item: Entity, + /// The entity which collected the item. + pub collector: Entity, + /// Number of items which was collected. + pub amount: u8, +} + +/// Event which is triggered when an entity's inventory +/// is updated. +/// +/// This event could also be triggered when a player +/// changes their held item. +/// +/// Note that the associated entity is not necessarily a player. +/// For example, a chest block entity has an `Inventory` component, +/// and `InventoryUpdateEvent`s may be triggered for it. +#[derive(Debug, Clone)] +pub struct InventoryUpdateEvent { + /// The slot(s) affected by the update. + /// + /// Multiple slots could be affected when, for + /// example, a player uses the "drag" inventory interaction. + pub slots: SmallVec<[SlotIndex; 2]>, + /// The entity owning the updated inventory. + pub entity: Entity, +} + +/// Event triggered to reduce an items durability. For example, +/// when an item has been used, a tool breaks a block, +/// or armor has been hit. +#[derive(Debug, Clone)] +pub struct ItemDamageEvent { + /// The player whose item is being damaged + pub player: Entity, + /// Which inventory slot is being damaged + pub slot: SlotIndex, + /// How many points of damage the item is taking + pub damage_taken: u32, +} + +/// Event triggered when a player opens a window. For example, +/// opening a chest will trigger this event. +#[derive(Copy, Clone, Debug)] +pub struct WindowOpenEvent { + /// The player who opened the window + pub player: Entity, + /// The entity whose inventory was opened. + /// For example, when a chest is opened, + /// this will be the chest's block entity. + pub opened: Entity, +} + +/// Event triggered when a player closes a window. +#[derive(Copy, Clone, Debug)] +pub struct WindowCloseEvent { + /// The player who closed the window + pub player: Entity, + /// The entity whose inventory was closed + pub closed: Entity, +} + +/// Event triggered when an entity is created. +#[derive(Copy, Clone, Debug)] +pub struct EntitySpawnEvent { + pub entity: Entity, +} + +/// Event triggered when an entity's health is updated. +#[derive(Copy, Clone, Debug)] +pub struct HealthUpdateEvent { + /// The old health. + pub old: u32, + /// The new health. + pub new: u32, + /// The entity whose health was updated. + pub entity: Entity, +} + +/// Event triggered when a player performs an animation (hits with their hand). +#[derive(Copy, Clone, Debug)] +pub struct PlayerAnimationEvent { + pub player: Entity, + pub animation: ClientboundAnimation, +} + +/// Event triggered when a chat message is sent out +#[derive(Debug, Clone)] +pub struct ChatEvent { + /// The JSON-formatted message + pub message: String, + /// The position of the message + pub position: ChatPosition, +} + +/// Different positions a chat message can be displayed +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ChatPosition { + /// Simple message displayed in the chat box + Chat, + /// System message displayed in the chat box + SystemMessage, + /// A text displayed above the hotbar + GameInfo, +} + +/// Event triggered when an entity crosses into a new chunk. +#[derive(Copy, Clone, Debug)] +pub struct ChunkCrossEvent { + pub entity: Entity, + pub old: Option<ChunkPosition>, + pub new: ChunkPosition, +} + +/// Event triggered when an entity is sent to a client. +/// +/// This can be used to send additional packets along with the Spawn * +/// packet, such as entity metadata. +#[derive(Copy, Clone, Debug)] +pub struct EntitySendEvent { + /// The entity which was sent. + pub entity: Entity, + /// The client to which the entity was sent. + pub client: Entity, +} + +/// Event triggered when an entity is destroyed on a client. +/// +/// This can be used to clean up data. For example, the movement +/// broadcast system stores the last known position of all visible +/// entities for each client. It uses this event to remove +/// entries in that map. +#[derive(Copy, Clone, Debug)] +pub struct EntityClientRemoveEvent { + /// The entity which was destroyed on the client. + pub entity: Entity, + /// The client on which the entity was destroyed. + pub client: Entity, +} + +/// Event triggered when a chunk is loaded. +#[derive(Copy, Clone, Debug)] +pub struct ChunkLoadEvent { + pub chunk: ChunkPosition, +} + +/// Event which is triggered when a chunk fails to load. +#[derive(Debug)] +pub struct ChunkLoadFailEvent { + pub pos: ChunkPosition, + pub error: anyhow::Error, +} + +/// Event triggeered when a chunk is unloaded. +#[derive(Copy, Clone, Debug)] +pub struct ChunkUnloadEvent { + pub chunk: ChunkPosition, +} + +/// Event triggered when a chunk holder releases their hold on a chunk. +#[derive(Copy, Clone, Debug)] +pub struct ChunkHolderReleaseEvent { + /// Entity which released their hold. + pub entity: Entity, + /// The chunk which was released. + pub chunk: ChunkPosition, +} + +/// Triggered when the weather changes. +#[derive(Copy, Clone, Debug)] +pub struct WeatherChangeEvent { + pub from: Weather, + pub to: Weather, + pub duration: i32, +} + +/// Triggered when a player's gamemode is updated. +#[derive(Copy, Clone, Debug)] +pub struct GamemodeUpdateEvent { + pub player: Entity, + pub old: Gamemode, + pub new: Gamemode, +} + +/// Requests that a chunk be held for the given client. +/// +/// This is a "request"-type event: it has one handler defined +/// in the `chunk` crate which executes the request. +#[derive(Copy, Clone, Debug)] +pub struct HoldChunkRequest { + pub player: Entity, + pub chunk: ChunkPosition, +} + +/// Requests that a chunk hold be removed for the given client. +#[derive(Copy, Clone, Debug)] +pub struct ReleaseChunkRequest { + pub player: Entity, + pub chunk: ChunkPosition, +} + +/// Requests that a chunk be queued for loading. +#[derive(Copy, Clone, Debug)] +pub struct LoadChunkRequest { + pub chunk: ChunkPosition, +} + +/// Updates day time changes. +#[derive(Copy, Clone, Debug)] +pub struct TimeUpdateEvent { + pub new_time: u64, +} diff --git a/feather/old/server/types/src/game.rs b/feather/old/server/types/src/game.rs new file mode 100644 index 000000000..7eaae3ad3 --- /dev/null +++ b/feather/old/server/types/src/game.rs @@ -0,0 +1,417 @@ +use crate::{BlockUpdateCause, Network, ServerToWorkerMessage}; +use crate::{ + BlockUpdateEvent, CanRespawn, Dead, EntityDeathEvent, EntityDespawnEvent, Health, + HealthUpdateEvent, Name, PlayerLeaveEvent, +}; +use ahash::AHashMap; +use bumpalo::Bump; +use feather_core::anvil::level::LevelData; +use feather_core::blocks::BlockId; +use feather_core::chunk_map::ChunkMap; +use feather_core::game_rules::GameRules; +use feather_core::network::{packets::DisconnectPlay, Packet}; +use feather_core::text::Text; +use feather_core::util::{BlockPosition, ChunkPosition, Position}; +use feather_server_config::Config; +use fecs::{Entity, Event, EventHandlers, IntoQuery, OwnedResources, Read, RefResources, World}; +use rand::rngs::SmallRng; +use rand::{Rng, SeedableRng}; +use smallvec::SmallVec; +use std::cell::{RefCell, RefMut}; +use std::fmt::Display; +use std::ops::Deref; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::Arc; +use thread_local::CachedThreadLocal; + +/// Resources which can be _shared_ between threads. +/// These only require immutable access. +pub struct Shared { + /// The server configuration. + pub config: Arc<Config>, + /// General-purpose, non-cryptographic random number generator + pub rng: CachedThreadLocal<RefCell<SmallRng>>, + /// The server player count. + pub player_count: Arc<AtomicU32>, // fixme: double Arc +} + +/// The `Game` resource, which acts as a central bus to bind together +/// the feather-server-* crates. Resources which are accessed frequently, +/// such as the chunk map, are stored in here. +pub struct Game { + pub chunk_map: ChunkMap, + /// Number of ticks since the program started. Can be used + /// to make a system which only runs at a fixed interval. + pub tick_count: u64, + /// Stores entities which have a hold on chunks, + /// preventing the chunk from being unloaded. + pub chunk_holders: ChunkHolders, + /// Block entity map. Each `BlockPosition` may have a block + /// entity associated with it. + pub block_entities: AHashMap<BlockPosition, Entity>, + /// The level data. + pub level: LevelData, + /// Associates chunks with the entities that reside in them. Used + /// as an acceleration structure for spacial lookups. + pub chunk_entities: ChunkEntities, + /// World time, in the Minecraft way. + pub time: Time, + /// The event handler map. + pub event_handlers: Arc<EventHandlers>, + /// Resources other than `Game`, used to run event handlers. + pub resources: Arc<OwnedResources>, + /// Shared bump allocator, reset each tick. + pub bump: CachedThreadLocal<Bump>, + /// Values which can be shared between threads. + pub shared: Arc<Shared>, + /// Gamrules + pub game_rules: GameRules, +} + +impl Deref for Game { + type Target = Shared; + + fn deref(&self) -> &Self::Target { + &self.shared + } +} + +impl Game { + /// Handles an event or message. All handlers + /// for the given event will be run. + pub fn handle(&mut self, world: &mut World, event: impl Event) { + // TODO: optimize this by avoiding Rc clone. + let resources = Arc::clone(&self.resources); + let event_handlers = Arc::clone(&self.event_handlers); + let resources = RefResources::new(Arc::as_ref(&resources), (self,)); + event_handlers.trigger(&resources, world, event); + } + + /// Retrieves the block at the given position. + /// Returns `None` if the block's chunk is not loaded + /// or the coordinates are out of bounds. + pub fn block_at(&self, pos: BlockPosition) -> Option<BlockId> { + self.chunk_map.block_at(pos) + } + + /// Sets the block at the given position. + /// + /// Returns `false` if the block's chunk is not loaded + /// or the coordinates are out of bounds; + /// otherwise, returns `true`. + pub fn set_block_at( + &mut self, + world: &mut World, + pos: BlockPosition, + block: BlockId, + cause: BlockUpdateCause, + ) -> bool { + let old = match self.block_at(pos) { + Some(block) => block, + None => return false, + }; + + let result = self.chunk_map.set_block_at(pos, block); + + self.handle( + world, + BlockUpdateEvent { + pos, + old, + new: block, + cause, + }, + ); + + result + } + + /// Returns a bump allocator. + pub fn bump(&self) -> &Bump { + self.bump.get_or_default() + } + + /// Returns a random number generator. + pub fn rng(&self) -> RefMut<impl Rng> { + self.rng + .get_or(|| RefCell::new(SmallRng::from_entropy())) + .borrow_mut() + } + + /// Despawns an entity. This should be used instead of `World::despawn` + /// as it properly handles events. + pub fn despawn(&mut self, entity: Entity, world: &mut World) { + self.handle(world, EntityDespawnEvent { entity }); + world.despawn(entity); + } + + /// Disconnects a player. + pub fn disconnect(&mut self, player: Entity, world: &mut World, reason: impl Display) { + self.disconnect_player(player, world, &reason, &reason); + } + + /// Disconnects a player. + /// Sends disconnect packet with `reason_client` and logs `reason_console` to the server console. + pub fn disconnect_and_log( + &mut self, + player: Entity, + world: &mut World, + reason_client: &Text, + reason_console: impl Display, + ) { + self.disconnect_player(player, world, reason_client, reason_console); + } + + fn disconnect_player( + &mut self, + player: Entity, + world: &mut World, + reason_client: impl Display, + reason_console: impl Display, + ) { + let name = world.get::<Name>(player); + let network = world.get::<Network>(player); + + network.send(DisconnectPlay { + reason: reason_client.to_string(), + }); + let _ = network.tx.send(ServerToWorkerMessage::Disconnect); + + log::info!("{} disconnected: {}", name.0, reason_console); + + drop(name); + drop(network); + + self.player_count.fetch_sub(1, Ordering::AcqRel); + self.handle(world, PlayerLeaveEvent { player }); + self.despawn(player, world); + } + + /* BROADCAST FUNCTIONS */ + /// Broadcasts a packet to all online players. + pub fn broadcast_global(&self, world: &World, packet: impl Packet, neq: Option<Entity>) { + self.broadcast_global_boxed(world, Box::new(packet), neq); + } + + /// Broadcasts a boxed packet to all online players. + pub fn broadcast_global_boxed( + &self, + world: &World, + packet: Box<dyn Packet>, + neq: Option<Entity>, + ) { + for (entity, network) in <Read<Network>>::query().iter_entities(world.inner()) { + if neq.map(|neq| neq == entity).unwrap_or(false) { + continue; + } + + network.send_boxed(packet.box_clone()); + } + } + + /// Broadcasts a packet to all players able to see a given chunk. + pub fn broadcast_chunk_update( + &self, + world: &World, + packet: impl Packet, + chunk: ChunkPosition, + neq: Option<Entity>, + ) { + self.broadcast_chunk_update_boxed(world, Box::new(packet), chunk, neq); + } + + /// Broadcasts a boxed packet to all players able to see a given chunk. + pub fn broadcast_chunk_update_boxed( + &self, + world: &World, + packet: Box<dyn Packet>, + chunk: ChunkPosition, + neq: Option<Entity>, + ) { + // we can use the chunk holders structure to accelerate this + for entity in self.chunk_holders.holders_for(chunk) { + if neq.map(|neq| neq == *entity).unwrap_or(false) { + continue; + } + + if let Some(network) = world.try_get::<Network>(*entity) { + network.send_boxed(packet.box_clone()); + } + } + } + + /// Broadcasts a packet to all players able to see a given entity. + pub fn broadcast_entity_update( + &self, + world: &World, + packet: impl Packet, + entity: Entity, + neq: Option<Entity>, + ) { + self.broadcast_entity_update_boxed(world, Box::new(packet), entity, neq); + } + + /// Broadcasts a boxed packet to all players able to see a given entity. + pub fn broadcast_entity_update_boxed( + &self, + world: &World, + packet: Box<dyn Packet>, + entity: Entity, + neq: Option<Entity>, + ) { + // Send the packet to all players who have a hold on the entity's chunk. + let entity_chunk = world.get::<Position>(entity).chunk(); + self.broadcast_chunk_update_boxed(world, packet, entity_chunk, neq); + } + + /// Applies damage to the given entity. Handles all logic, + /// including killing the entity if its health drops below 1. + pub fn damage(&mut self, entity: Entity, damage: u32, world: &mut World) { + if world.has::<Dead>(entity) { + return; + } + + let (old_health, new_health) = if let Some(mut health) = world.try_get_mut::<Health>(entity) + { + let old_health = health.0; + let new_health = health.0.saturating_sub(damage); + health.0 = new_health; + (Some(old_health), new_health) + } else { + (None, 0) + }; + + if let Some(old_health) = old_health { + self.handle( + world, + HealthUpdateEvent { + old: old_health, + new: new_health, + entity, + }, + ); + + if new_health == 0 { + self.kill(entity, world); + } + } + } + + /// Kills an entity. + pub fn kill(&mut self, entity: Entity, world: &mut World) { + // Don't kill if already on respawn screen + if world.has::<Dead>(entity) { + return; + } + + self.handle(world, EntityDeathEvent { entity }); + if !world.has::<CanRespawn>(entity) { + self.despawn(entity, world); + } + } +} + +/// The chunk holder map contains a mapping +/// of chunk positions to any number of entities, called "holders." +/// When a chunk position has no holders, it will be queued +/// for unloading. +/// +/// In addition, the chunk holders map can be used to select +/// which players to broadcast an entity movement to: a player +/// who has a chunk hold on the entity's chunk would be able to see +/// the movement, while other players would be outside of the view +/// distance. This technique allows for higher performance and +/// avoids constant nearby entity queries. +#[derive(Default, Clone, Debug)] +pub struct ChunkHolders { + pub inner: AHashMap<ChunkPosition, SmallVec<[Entity; 4]>>, +} + +impl ChunkHolders { + pub fn holders_for(&self, chunk: ChunkPosition) -> &[Entity] { + self.inner + .get(&chunk) + .map(SmallVec::as_slice) + .unwrap_or(&[]) + } + + pub fn chunk_has_holders(&self, chunk: ChunkPosition) -> bool { + let holders = self.holders_for(chunk); + + !holders.is_empty() + } + + pub fn insert_holder(&mut self, chunk: ChunkPosition, holder: Entity) { + self.inner.entry(chunk).or_default().push(holder) + } +} + +/// Stores which entities belong to every given chunk. +/// +/// This data structure can be used to accelerate certain +/// operations, such as querying for entities +/// within some distance of a position. In addition, +/// it can be used to send all entities in a chunk +/// to a player. +/// +/// Do note that the information in this structure is not necessarily up to date, +/// although a best effort is made to update the data. +#[derive(Default)] +pub struct ChunkEntities(pub AHashMap<ChunkPosition, SmallVec<[Entity; 4]>>); + +impl ChunkEntities { + pub fn new() -> Self { + Self::default() + } + + /// Returns a slice of entities in the given chunk. + pub fn entities_in_chunk(&self, chunk: ChunkPosition) -> &[Entity] { + self.0.get(&chunk).map(|vec| vec.as_slice()).unwrap_or(&[]) + } +} + +/// The current time of the world. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct Time { + game_time: u64, + day_time: u64, +} + +impl Time { + /// Adds some time to the time of day. + pub fn set_time_of_day(&mut self, new_time: u64) { + self.day_time = new_time; + self.day_time %= 24_000; + } + + /// Adds some time to world age. + pub fn set_world_age(&mut self, new_time: u64) { + self.game_time = new_time; + } + + /// Returns the time of day. + pub fn time_of_day(self) -> u64 { + self.day_time + } + + /// Returns the days passed. This is calculated + /// as `time.0 / 24_000`. + pub fn days(self) -> u64 { + self.game_time / 24_000 + } + + /// Returns the age of the world in ticks. Equivalent to `time.0`. + pub fn world_age(self) -> u64 { + self.game_time + } +} + +#[fecs::system] +pub fn reset_bump_allocators(game: &mut Game) { + game.bump.iter_mut().for_each(Bump::reset); +} + +#[fecs::system] +pub fn increment_tick_count(game: &mut Game) { + game.tick_count += 1; +} diff --git a/feather/old/server/types/src/lib.rs b/feather/old/server/types/src/lib.rs new file mode 100644 index 000000000..0ab55f44d --- /dev/null +++ b/feather/old/server/types/src/lib.rs @@ -0,0 +1,25 @@ +//! Defines components and resources so that subcrates can interact +//! in some ways without depending on each other. + +extern crate nalgebra_glm as glm; + +mod components; +mod events; +mod game; +mod misc; +mod resources; +pub mod task; + +pub use components::*; +pub use events::*; +pub use misc::*; +pub use resources::*; + +// Constants +/// The number of ticks executed per second. +pub const TPS: u64 = 20; +/// The number of milliseconds per tick. +pub const TICK_LENGTH: u64 = 1000 / TPS; + +/// Height from a player's position where the camera lies. +pub const PLAYER_EYE_HEIGHT: f64 = 1.62; diff --git a/feather/old/server/types/src/misc.rs b/feather/old/server/types/src/misc.rs new file mode 100644 index 000000000..d0511d831 --- /dev/null +++ b/feather/old/server/types/src/misc.rs @@ -0,0 +1,103 @@ +use crate::Game; +use feather_core::anvil::block_entity::{BlockEntityData, BlockEntityVariant}; +use feather_core::{ + anvil::entity::{EntityData, EntityDataKind}, + blocks::BlockKind, + util::BlockPosition, +}; +use fecs::{Entity, EntityBuilder, World}; + +pub type BumpVec<'bump, T> = bumpalo::collections::Vec<'bump, T>; + +pub trait EntityLoaderFn: + Fn(EntityData) -> anyhow::Result<EntityBuilder> + Send + Sync + 'static +{ +} + +impl<F> EntityLoaderFn for F where + F: Fn(EntityData) -> anyhow::Result<EntityBuilder> + Send + Sync + 'static +{ +} + +pub trait BlockEntityLoaderFn: + Fn(BlockEntityData) -> anyhow::Result<EntityBuilder> + Send + Sync + 'static +{ +} + +impl<F> BlockEntityLoaderFn for F where + F: Fn(BlockEntityData) -> anyhow::Result<EntityBuilder> + Send + Sync + 'static +{ +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum Weather { + Clear, + Rain, + Thunder, +} + +/// A registration for a function to convert an `EntityData` +/// to an `EntityBuilder` for spawning into the world. The +/// registration must provide the `EntityDataKind` it handles +/// to determine which `EntityData`s to pass to this function. +pub struct EntityLoaderRegistration { + /// The loader function. + pub f: &'static dyn EntityLoaderFn, + /// The kind of `EntityData` which this loader + /// function will accept. + pub kind: EntityDataKind, +} + +impl EntityLoaderRegistration { + pub fn new(kind: EntityDataKind, f: &'static dyn EntityLoaderFn) -> Self { + Self { f, kind } + } +} + +inventory::collect!(EntityLoaderRegistration); + +/// Same as `EntityLoaderRegistration`, but for block entities. +pub struct BlockEntityLoaderRegistration { + pub f: &'static dyn BlockEntityLoaderFn, + pub kind: BlockEntityVariant, +} + +inventory::collect!(BlockEntityLoaderRegistration); + +/// Handles interactions (Use Item key) with a block. +pub trait InteractionHandler: Send + Sync { + /// Called whenever a player right clicks on the block + fn handle_interaction( + &self, + game: &mut Game, + world: &mut World, + pos: BlockPosition, + player: Entity, + window_id: u8, + ); + + /// Returns the kind of block handled by this handler. + fn block_kind(&self) -> BlockKind; +} + +inventory::collect!(Box<dyn InteractionHandler>); + +/// Wrapper around the send/receive channels which will be used to +/// notify server thread of shutdown due to ctrl+C or /stop command. +pub struct ShutdownChannels { + pub tx: crossbeam::channel::Sender<()>, + pub rx: crossbeam::channel::Receiver<()>, +} + +impl ShutdownChannels { + pub fn new() -> Self { + let (tx, rx) = crossbeam::bounded(1); + Self { tx, rx } + } +} + +impl Default for ShutdownChannels { + fn default() -> Self { + Self::new() + } +} diff --git a/feather/old/server/types/src/resources.rs b/feather/old/server/types/src/resources.rs new file mode 100644 index 000000000..e16837d74 --- /dev/null +++ b/feather/old/server/types/src/resources.rs @@ -0,0 +1,8 @@ +use std::sync::{Arc, RwLock}; + +pub use crate::game::*; +pub use crate::task::*; +pub use feather_server_config::{Ban, BanInfo, Config, ProxyMode}; +pub type WrappedBanInfo = Arc<RwLock<BanInfo>>; + +pub use feather_server_packet_buffer::{PacketBuffer, PacketBuffers}; diff --git a/feather/old/server/types/src/task.rs b/feather/old/server/types/src/task.rs new file mode 100644 index 000000000..b61a2e7f5 --- /dev/null +++ b/feather/old/server/types/src/task.rs @@ -0,0 +1,209 @@ +//! Implements a global task scheduler as a wrapper over Tokio. +//! +//! A few guarantees are made: +//! * The server will not shut down until all tasks complete. +//! * All scheduled tasks will complete at some point. + +use crate::Game; +use fecs::World; +use once_cell::sync::OnceCell; +use parking_lot::Mutex; +use std::future::Future; +use std::mem::{transmute, MaybeUninit}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use tokio::runtime; +use tokio::sync::{oneshot, Notify}; +use tokio::task::JoinHandle; + +/// TODO: reduce allocation +enum SyncFn { + Owned(Box<dyn FnOnce(&mut Game, &mut World) + Send + 'static>), + Scoped(*mut (dyn FnMut(&mut Game, &mut World))), +} + +unsafe impl Send for SyncFn {} + +/// Fake wrapper which causes a value to become `Send` and `Sync`. +struct UnsafeSendSync<T>(T); + +unsafe impl<T> Send for UnsafeSendSync<T> {} +unsafe impl<T> Sync for UnsafeSendSync<T> {} + +/// Global task manager. +static TASK_MANAGER: OnceCell<TaskManager> = OnceCell::new(); + +/// Returns a reference to the global task manager. +pub fn tasks() -> &'static TaskManager { + TASK_MANAGER + .get() + .expect("task manager not initialized (call task::init() first)") +} + +/// Intializes the global task manager. +pub fn init(runtime: runtime::Handle) { + TASK_MANAGER + .set(TaskManager::new(runtime)) + .ok() + .expect("task manager already initialized"); +} + +pub struct TaskManager { + /// Number of currently running tasks. + running: Arc<AtomicUsize>, + /// Notify handle, woken every time an _async_ task stops. + notify: Arc<Notify>, + /// Handle to the Tokio runtime. + runtime: runtime::Handle, + /// Queue of tasks to run on the ticking thread. + sync_tx: flume::Sender<SyncFn>, + sync_rx: Mutex<flume::Receiver<SyncFn>>, +} + +impl TaskManager { + fn new(runtime: runtime::Handle) -> Self { + let (sync_tx, sync_rx) = flume::bounded(16); + let sync_rx = Mutex::new(sync_rx); + Self { + running: Arc::new(AtomicUsize::new(0)), + notify: Arc::new(Notify::new()), + runtime, + sync_tx, + sync_rx, + } + } + + /// Spawns an asynchronous task. The task is guaranteed + /// to finish before the server shuts down. + pub fn spawn<F>(&self, f: F) -> JoinHandle<F::Output> + where + F: Future + Send + 'static, + F::Output: Send + 'static, + { + self.running.fetch_add(1, Ordering::AcqRel); + let notify = Arc::clone(&self.notify); + let running = Arc::clone(&self.running); + self.runtime.spawn(async move { + let ret = f.await; + running.fetch_sub(1, Ordering::AcqRel); + notify.notify(); + ret + }) + } + + /// Spawns a synchronous task with access to game state. The task + /// will run on the next tick cycle. + pub fn sync<F, R>(&self, f: F) -> oneshot::Receiver<R> + where + F: FnOnce(&mut Game, &mut World) -> R + Send + 'static, + R: Send + 'static, + { + let (tx, rx) = oneshot::channel(); + + self.sync_tx + .send(SyncFn::Owned(Box::new(move |game, world| { + let _ = tx.send(f(game, world)); + }))) + .ok() + .unwrap(); + + rx + } + + /// Runs a "scoped" synchronous task with access to game state. + /// + /// The task will run on the next tick cycle. Afterward, the + /// returned future will complete with the return value. + #[allow(clippy::let_and_return)] // weird rustc bug causes compile error + pub async fn scoped<'a, F, R>(&self, mut f: F) -> R + where + F: FnMut(&mut Game, &mut World) -> R + Send + 'a, + R: Send + 'a, + { + // EXTREMELY UNSAFE IMPLEMENTATION. + // Please audit. + let notify = Notify::new(); + let notify_ptr = UnsafeSendSync(¬ify as *const Notify); + + let mut return_value = MaybeUninit::<R>::uninit(); + + let return_value_ptr = UnsafeSendSync(return_value.as_mut_ptr()); + + // Dummy closure used to write the return value into `return_value`. + let mut dummy = move |game: &mut Game, world: &mut World| { + let ret = f(game, world); + unsafe { + return_value_ptr.0.write(ret); + (&*notify_ptr.0).notify(); + } + }; + + // Erase the lifetime of `dummy`. + // This is legal because we ensure it + // is not dropped until it completes, and any + // references remain valid because this stack + // frame remains intact. + let dummy = UnsafeSendSync((&mut dummy) as *mut (dyn FnMut(&mut Game, &mut World) + 'a)); + let dummy = unsafe { + transmute::< + UnsafeSendSync<*mut (dyn FnMut(&mut Game, &mut World) + 'a)>, + UnsafeSendSync<*mut (dyn FnMut(&mut Game, &mut World) + 'static)>, + >(dummy) + }; + + // Submit the dummy function to the queue. + self.sync_tx.send(SyncFn::Scoped(dummy.0)).ok().unwrap(); + + // Wait for the task to complete. + // This ensures that all the pointers above remain + // valid until `dummy` is called. + notify.notified().await; + + // Return value was written by `dummy`. + unsafe { return_value.assume_init() } + } + + /// Executes all queued sync tasks. + pub fn flush_sync(&self, game: &mut Game, world: &mut World) { + let sync_rx = self.sync_rx.lock(); + while let Ok(task) = sync_rx.try_recv() { + match task { + SyncFn::Owned(f) => f(game, world), + SyncFn::Scoped(f) => { + let f = unsafe { &mut *f }; + f(game, world); + } + } + } + } + + /// Waits until all tasks have completed. + pub async fn wait(&self) { + loop { + // TODO: less naive approach? + if self.running.load(Ordering::Acquire) == 0 { + return; + } + + self.notify.notified().await; + } + } +} + +/// System to run sync-queued tasks. +#[fecs::system] +pub fn run_sync_tasks(game: &mut Game, world: &mut World) { + tasks().flush_sync(game, world); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn task_spawning() { + init(runtime::Handle::current()); + + assert_eq!(tasks().spawn(async { 1 }).await.ok(), Some(1)); + } +} diff --git a/feather/old/server/util/Cargo.toml b/feather/old/server/util/Cargo.toml new file mode 100644 index 000000000..90e8201f1 --- /dev/null +++ b/feather/old/server/util/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "feather-server-util" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +nalgebra-glm = "0.6" +arrayvec = "0.5" +smallvec = "1.4" +rand = "0.7" +rand_distr = "0.2" +itertools = "0.9" +ahash = "0.3" +inventory = "0.1" +anyhow = "1.0" +uuid = { version = "0.8", features = ["v3"] } +md5 = "0.7" +reqwest = { version = "^0.10", features = ["json"] } +serde = { version = "1.0", features = ["derive"] } diff --git a/feather/old/server/util/src/block.rs b/feather/old/server/util/src/block.rs new file mode 100644 index 000000000..21816e1b4 --- /dev/null +++ b/feather/old/server/util/src/block.rs @@ -0,0 +1,308 @@ +//! Assorted functionality relating to blocks, including: +//! * The block notify system, where a block update "notifies" +//! adjacent blocks of the update. This is used for spawning +//! falling blocks, for example. +//! +//! The block notify system works as follows: when a block +//! is updated, `on_block_update_notify_adjacent` is called, +//! which checks the blocks adjacent to the updated block. +//! For each adjacent block, `notify_entity_for_block` is called +//! which returns an `Option<EntityBuilder>` containing the components +//! to create for the notify entity. For example, `Some(EntityBuilder::new().with(FallingBlockNotify)` +//! could be returned for `Sand` and `Gravel` variants. +//! +//! `on_block_update_notify_adjacent` then creates an entity with those components. +//! The "notify entity," in this case, +//! acts as a sort of event, as other systems can check for these entities +//! and perform actions based on their components. + +use crate::adjacent_blocks; +use feather_core::blocks::categories::SupportType; +use feather_core::blocks::{BlockId, BlockKind, Face}; +use feather_core::chunk_map::chunk_relative_pos; +use feather_core::util::BlockPosition; +use feather_server_types::{BlockUpdateEvent, Game}; +use fecs::{EntityBuilder, World}; +use std::cmp::max; +use std::iter; + +/// Marker component stating that an entity is a notify entity. +#[derive(Copy, Clone, Debug)] +pub struct BlockNotify; + +/// Component storing the position of a block for a block notify entity. +#[derive(Copy, Clone, Debug)] +pub struct BlockNotifyPosition(pub BlockPosition); + +/// Component storing the type of block notified. +#[derive(Copy, Clone, Debug)] +pub struct BlockNotifyBlock(pub BlockId); + +/// Marker component for block notify entities created for falling +/// blocks, such as sand and gravel. +#[derive(Copy, Clone, Debug)] +pub struct BlockNotifyFallingBlock; + +/// Marker component for block notify entities created for falling +/// blocks, such as sand and gravel. +#[derive(Copy, Clone, Debug)] +pub struct BlockNotifySupportedBlock; + +/// Returns an `EntityBuilder` to create the block notify entity for +/// the given block type. +fn notify_entity_for_block(block: BlockId, pos: BlockPosition) -> Option<EntityBuilder> { + let builder = EntityBuilder::new() + .with(BlockNotify) + .with(BlockNotifyPosition(pos)) + .with(BlockNotifyBlock(block)); + + if block.can_fall() { + Some(builder.with(BlockNotifyFallingBlock)) + } else if block.support_type().is_some() { + Some(builder.with(BlockNotifySupportedBlock)) + } else { + None + } +} + +/// When a block is updated, spawns notify entities +/// for adjacent blocks. +#[fecs::event_handler] +pub fn on_block_update_notify_adjacent( + event: &BlockUpdateEvent, + game: &mut Game, + world: &mut World, +) { + adjacent_blocks(event.pos) + .into_iter() + .chain(iter::once(event.pos)) + .filter_map(|adjacent_pos| { + if let Some(adjacent_block) = game.block_at(adjacent_pos) { + Some((adjacent_block, adjacent_pos)) + } else { + None + } + }) + .filter_map(|(adjacent_block, adjacent_pos)| { + notify_entity_for_block(adjacent_block, adjacent_pos) + }) + .for_each(|builder| { + builder.build().spawn_in(world); + }) +} + +/// This checks whether a block of a specific BlockId +/// can be placed at a specific position in the world. +/// For example blocks like torches, snow, grass need +/// supported blocks beneath/beside them. +pub fn is_block_supported_at(block_id: BlockId, game: &Game, pos: BlockPosition) -> bool { + // return value of None means tried to check a block in an unloaded chunk TODO how to handle? + check_block_support_at(block_id, game, pos).unwrap_or(false) +} + +const NORTH: BlockPosition = BlockPosition { x: 0, y: 0, z: -1 }; +const EAST: BlockPosition = BlockPosition { x: 1, y: 0, z: 0 }; +const SOUTH: BlockPosition = BlockPosition { x: 0, y: 0, z: 1 }; +const WEST: BlockPosition = BlockPosition { x: -1, y: 0, z: 0 }; +const UP: BlockPosition = BlockPosition { x: 0, y: 1, z: 0 }; +const DOWN: BlockPosition = BlockPosition { x: 0, y: -1, z: 0 }; + +fn face_facing_offset(id: BlockId) -> BlockPosition { + match id.face().unwrap() { + Face::Floor => DOWN, + Face::Ceiling => UP, + Face::Wall => id.facing_cardinal().unwrap().opposite().offset(), + } +} + +use feather_core::blocks::SimplifiedBlockKind::*; + +fn check_block_support_at(id: BlockId, game: &Game, pos: BlockPosition) -> Option<bool> { + // TODO leaves are technically a full block, but e.g. torches can't be placed on them https://minecraft.gamepedia.com/Opacity/Placement + let block_down = game.block_at(pos + DOWN); + let block_facing = if id.has_facing_cardinal() { + game.block_at(pos + id.facing_cardinal().unwrap().opposite().offset()) + } else { + None + }; + + match id.support_type() { + Some(support_type) => match support_type { + SupportType::OnSolid => Some(block_down?.is_full_block()), + SupportType::OnDirtBlocks => Some(matches!( + block_down?.simplified_kind(), + Dirt | GrassBlock | CoarseDirt | Podzol | Farmland + )), + SupportType::OnDesertBlocks => Some(matches!( + block_down?.simplified_kind(), + Sand | RedSand | Dirt | CoarseDirt | Podzol | Terracotta + )), + SupportType::OnFarmland => Some(block_down?.simplified_kind() == Farmland), + SupportType::OnSoulSand => Some(block_down?.simplified_kind() == SoulSand), + SupportType::OnWater => Some(matches!( + block_down?.simplified_kind(), + Water | Ice | FrostedIce + )), + + SupportType::FacingSolid => Some(block_facing?.is_full_block()), + SupportType::FacingJungleWood => Some(matches!( + block_facing?.kind(), + BlockKind::JungleLog + | BlockKind::StrippedJungleLog + | BlockKind::JungleWood + | BlockKind::StrippedJungleWood + )), + + SupportType::OnOrFacingSolid => { + let block_face_facing = game.block_at(pos + face_facing_offset(id))?; + + Some(block_face_facing.is_full_block()) + } + + SupportType::SnowLike => { + let is_supported = block_down?.is_full_block() + && !matches!(block_down?.simplified_kind(), Ice | PackedIce); + + Some(is_supported) + } + SupportType::TripwireHookLike => { + let is_supported = block_facing?.is_full_block() + && !matches!(block_facing?.simplified_kind(), RedstoneBlock | Observer); + + Some(is_supported) + } + + SupportType::CactusLike => block_support_cactus_like(game, pos), + SupportType::ChorusFlowerLike => block_support_chorus_flower_like(game, pos), + SupportType::ChorusPlantLike => block_support_chorus_plant_like(game, pos), + SupportType::MushroomLike => block_support_mushroom_like(game, pos), + SupportType::SugarCaneLike => block_support_sugar_cane_like(game, pos), + SupportType::VineLike => block_support_vine_like(game, pos), + }, + None => Some(true), + } +} + +fn block_support_cactus_like(game: &Game, pos: BlockPosition) -> Option<bool> { + let north = game.block_at(pos + NORTH)?; + let east = game.block_at(pos + EAST)?; + let south = game.block_at(pos + SOUTH)?; + let west = game.block_at(pos + WEST)?; + + let is_supported = matches!( + game.block_at(pos + DOWN)?.simplified_kind(), + Cactus | Sand | RedSand + ) && north.simplified_kind() != Cactus + && !north.is_full_block() + && east.simplified_kind() != Cactus + && !east.is_full_block() + && south.simplified_kind() != Cactus + && !south.is_full_block() + && west.simplified_kind() != Cactus + && !west.is_full_block(); + + Some(is_supported) +} + +fn block_support_chorus_flower_like(game: &Game, pos: BlockPosition) -> Option<bool> { + let north = game.block_at(pos + NORTH)?; + let east = game.block_at(pos + EAST)?; + let south = game.block_at(pos + SOUTH)?; + let west = game.block_at(pos + WEST)?; + + let neighbours = [north, east, south, west]; + let neighbouring_chorus = neighbours + .iter() + .filter(|&id| id.simplified_kind() == ChorusPlant) + .count(); + let neighbouring_air = neighbours.iter().filter(|&id| id.is_air()).count(); + + let is_supported = matches!( + game.block_at(pos + DOWN)?.simplified_kind(), + EndStone | ChorusPlant + ) || (neighbouring_chorus == 1 && neighbouring_air == 3); + + Some(is_supported) +} + +fn block_support_chorus_plant_like(game: &Game, pos: BlockPosition) -> Option<bool> { + let north = game.block_at(pos + NORTH)?; + let east = game.block_at(pos + EAST)?; + let south = game.block_at(pos + SOUTH)?; + let west = game.block_at(pos + WEST)?; + + let north_down = game.block_at(pos + NORTH + DOWN)?; + let east_down = game.block_at(pos + EAST + DOWN)?; + let south_down = game.block_at(pos + SOUTH + DOWN)?; + let west_down = game.block_at(pos + WEST + DOWN)?; + + let down = game.block_at(pos + DOWN)?; + let up = game.block_at(pos + UP)?; + + let horizontal = [north, east, south, west]; + let has_horizontal = horizontal + .iter() + .any(|&id| id.simplified_kind() == ChorusPlant); + let has_vertical = matches!(up.simplified_kind(), ChorusPlant | ChorusFlower); + + let horizontal_support = [north_down, east_down, south_down, west_down]; + let is_connected = matches!(down.simplified_kind(), ChorusPlant | EndStone) + || horizontal + .iter() + .zip(horizontal_support.iter()) + .any(|(&b, &b_down)| { + b.simplified_kind() == ChorusPlant + && matches!(b_down.simplified_kind(), ChorusPlant | EndStone) + }); + + let is_supported = is_connected && !(has_vertical && has_horizontal && !down.is_air()); + + Some(is_supported) +} + +fn block_support_mushroom_like(game: &Game, pos: BlockPosition) -> Option<bool> { + let chunk = game.chunk_map.chunk_at(pos.chunk())?; + let (x, y, z) = chunk_relative_pos(pos + DOWN); + + let is_supported = game.block_at(pos + DOWN)?.is_full_block() + && max(chunk.sky_light_at(x, y, z), chunk.block_light_at(x, y, z)) < 13; + + Some(is_supported) +} + +fn block_support_sugar_cane_like(game: &Game, pos: BlockPosition) -> Option<bool> { + let support = game.block_at(pos + DOWN)?.simplified_kind(); + + let is_supported = support == SugarCane + || (matches!( + support, + GrassBlock | Dirt | CoarseDirt | Podzol | Sand | RedSand + ) && (matches!( + game.block_at(pos + DOWN + NORTH)?.simplified_kind(), + Water | FrostedIce + ) || matches!( + game.block_at(pos + DOWN + EAST)?.simplified_kind(), + Water | FrostedIce + ) || matches!( + game.block_at(pos + DOWN + SOUTH)?.simplified_kind(), + Water | FrostedIce + ) || matches!( + game.block_at(pos + DOWN + WEST)?.simplified_kind(), + Water | FrostedIce + ))); + + Some(is_supported) +} + +fn block_support_vine_like(game: &Game, pos: BlockPosition) -> Option<bool> { + let up = game.block_at(pos + UP)?; + + let is_supported = up.is_full_block() + || up.simplified_kind() == Vine + || game.block_at(pos + NORTH)?.is_full_block() + || game.block_at(pos + EAST)?.is_full_block() + || game.block_at(pos + SOUTH)?.is_full_block() + || game.block_at(pos + WEST)?.is_full_block(); + + Some(is_supported) +} diff --git a/feather/old/server/util/src/chunk_entities.rs b/feather/old/server/util/src/chunk_entities.rs new file mode 100644 index 000000000..924884db3 --- /dev/null +++ b/feather/old/server/util/src/chunk_entities.rs @@ -0,0 +1,63 @@ +use feather_core::util::Position; +use feather_server_types::{ChunkCrossEvent, EntityDespawnEvent, EntitySpawnEvent, Game}; +use fecs::World; +use itertools::Itertools; + +/// System to update ChunkEntities when entities move into new chunks. +#[fecs::event_handler] +pub fn on_chunk_cross_update_chunk_entities(event: &ChunkCrossEvent, game: &mut Game) { + if let Some(old) = event.old { + if let Some(vec) = game.chunk_entities.0.get_mut(&old) { + let index = vec + .iter() + .find_position(|e| **e == event.entity) + .map(|(index, _)| index); + if let Some(index) = index { + vec.swap_remove(index); + } + } + + game.chunk_entities + .0 + .entry(event.new) + .or_default() + .push(event.entity); + } +} + +#[fecs::event_handler] +pub fn on_entity_despawn_update_chunk_entities( + event: &EntityDespawnEvent, + game: &mut Game, + world: &mut World, +) { + if let Some(pos) = world.try_get::<Position>(event.entity) { + if let Some(vec) = game.chunk_entities.0.get_mut(&pos.chunk()) { + let index = vec + .iter() + .find_position(|e| **e == event.entity) + .map(|(index, _)| index); + if let Some(index) = index { + vec.swap_remove(index); + } + } + } +} + +#[fecs::event_handler] +pub fn on_entity_spawn_update_chunk_entities( + event: &EntitySpawnEvent, + game: &mut Game, + world: &mut World, +) { + if let Some(chunk) = world + .try_get::<Position>(event.entity) + .map(|pos| pos.chunk()) + { + game.chunk_entities + .0 + .entry(chunk) + .or_default() + .push(event.entity); + } +} diff --git a/feather/old/server/util/src/lib.rs b/feather/old/server/util/src/lib.rs new file mode 100644 index 000000000..1db97963b --- /dev/null +++ b/feather/old/server/util/src/lib.rs @@ -0,0 +1,241 @@ +#![forbid(unsafe_code)] + +//! Assorted utility functions and trivial game logic. + +use arrayvec::ArrayVec; +use feather_core::util::{BlockPosition, ChunkPosition, Position}; +use nalgebra_glm::{vec3, DVec3}; + +mod block; +pub use block::*; +mod chunk_entities; +pub use chunk_entities::*; +mod time; +pub use time::*; +mod load; +pub use load::*; + +use feather_server_types::{Game, Uuid}; +use fecs::{Entity, World}; +use rand::Rng; +use rand_distr::{Distribution, StandardNormal}; +use serde::{Deserialize, Serialize}; +use smallvec::SmallVec; +use std::time::{SystemTime, UNIX_EPOCH}; + +/// Retrieves the current time in seconds +/// since the UNIX epoch. +pub fn current_time_in_secs() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() +} + +/// Retrieves the current time in milliseconds +/// since the UNIX epoch. +pub fn current_time_in_millis() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() as u64 +} + +/// Calculates the relative move fields +/// as used in the Entity Relative Move packets. +pub fn calculate_relative_move(old: Position, current: Position) -> (i16, i16, i16) { + let x = ((current.x * 32.0 - old.x * 32.0) * 128.0) as i16; + let y = ((current.y * 32.0 - old.y * 32.0) * 128.0) as i16; + let z = ((current.z * 32.0 - old.z * 32.0) * 128.0) as i16; + (x, y, z) +} + +/// Converts degrees to stops as used in the protocol. +pub fn degrees_to_stops(degs: f32) -> u8 { + ((degs / 360.0) * 256.0) as u8 +} + +/// Returns the set of block positions adjacent to a given position. +pub fn adjacent_blocks(pos: BlockPosition) -> ArrayVec<[BlockPosition; 6]> { + [ + pos + BlockPosition::new(1, 0, 0), + pos + BlockPosition::new(0, 1, 0), + pos + BlockPosition::new(0, 0, 1), + pos + BlockPosition::new(-1, 0, 0), + pos + BlockPosition::new(0, -1, 0), + pos + BlockPosition::new(0, 0, -1), + ] + .iter() + .filter(|pos| pos.y >= 0 && pos.y < 256) + .copied() + .collect() +} + +/// Converts float-based velocity in blocks per tick +/// to the format used by the protocol. +pub fn protocol_velocity(vel: DVec3) -> (i16, i16, i16) { + // These are in units of 1/8000 block per tick. + ( + (vel.x * 8000.0) as i16, + (vel.y * 8000.0) as i16, + (vel.z * 8000.0) as i16, + ) +} + +/// Returns all entities within the given distance of the given +/// position. +/// +/// # Panics +/// Panics if either coordinate of the radius is negative. +pub fn nearby_entities( + world: &World, + game: &Game, + pos: Position, + radius: DVec3, +) -> SmallVec<[Entity; 4]> { + assert!(radius.x >= 0.0); + assert!(radius.y >= 0.0); + assert!(radius.z >= 0.0); + + let mut result = SmallVec::new(); + + for chunk in chunks_within_distance(pos, radius) { + let entities = game.chunk_entities.entities_in_chunk(chunk); + entities + .iter() + .copied() + .filter(|e| { + let epos = world.try_get::<Position>(*e); + if let Some(epos) = epos { + (epos.x - pos.x).abs() <= radius.x + && (epos.y - pos.y).abs() <= radius.y + && (epos.z - pos.z).abs() <= radius.z + } else { + false + } + }) + .for_each(|e| result.push(e)); + } + + result +} + +/// Finds all chunks within a given distance (in blocks) +/// of a position. +/// +/// The Y coordinate of `distance` is ignored. +pub fn chunks_within_distance( + mut pos: Position, + mut distance: DVec3, +) -> SmallVec<[ChunkPosition; 9]> { + assert!(distance.x >= 0.0); + assert!(distance.z >= 0.0); + + let mut result = SmallVec::new(); + + let mut x_len = 0; + let mut z_len = 0; + + let center_chunk_pos = pos.chunk(); + + loop { + let needed = ((pos.x + 16.0) / 16.0).floor() * 16.0 - pos.x; + if needed > distance.x { + break; + } + + distance.x -= needed; + pos.x += needed; + x_len += 1; + } + + loop { + let needed = ((pos.z + 16.0) / 16.0).floor() * 16.0 - pos.z; + if needed > distance.z { + break; + } + + distance.z -= needed; + pos.z += needed; + z_len += 1; + } + + for x in -x_len..=x_len { + for z in -z_len..=z_len { + result.push(ChunkPosition::new( + x + center_chunk_pos.x, + z + center_chunk_pos.z, + )); + } + } + + result +} + +pub fn charge_from_ticks_held(ticks: u32) -> f32 { + let ticks = ticks as f32; + + let mut unbounded_force = (ticks * (ticks + 40.0)) / 400.0; + + if unbounded_force > 3.0 { + unbounded_force = 3.0 + } + + unbounded_force +} + +pub fn compute_projectile_velocity( + direction: DVec3, + charge: f64, + inaccuracy: f64, + rng: &mut impl Rng, +) -> DVec3 { + let gaussian = vec3( + StandardNormal.sample(rng), + StandardNormal.sample(rng), + StandardNormal.sample(rng), + ); + let inaccuracy = vec3(inaccuracy, inaccuracy, inaccuracy).component_mul(&gaussian) * 0.0075; + + (direction + inaccuracy) * charge +} + +/// Compute offline mode UUID +/// https://gist.github.com/games647/2b6a00a8fc21fd3b88375f03c9e2e603 +pub fn name_to_uuid_offline(username: &str) -> Uuid { + let mut context = md5::Context::new(); + context.consume(format!("OfflinePlayer:{}", username).as_bytes()); + let computed = context.compute(); + let bytes = computed.into(); + + let mut builder = uuid::Builder::from_bytes(bytes); + + builder + .set_variant(uuid::Variant::RFC4122) + .set_version(uuid::Version::Md5); + + builder.build() +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct ProfileResponse { + id: Uuid, + name: String, +} + +/// Gets the UUID of a username by requesting it from Mojang's API +pub async fn name_to_uuid_online(username: &str) -> Option<Uuid> { + let auth_result = reqwest::get(&format!( + "https://api.mojang.com/users/profiles/minecraft/{}", + username + )) + .await; + + match auth_result { + Ok(res) => match res.json::<ProfileResponse>().await { + Ok(json) => Some(json.id), + Err(_) => None, + }, + Err(_) => None, + } +} diff --git a/feather/old/server/util/src/load.rs b/feather/old/server/util/src/load.rs new file mode 100644 index 000000000..067fea459 --- /dev/null +++ b/feather/old/server/util/src/load.rs @@ -0,0 +1,59 @@ +use ahash::AHashMap; +use feather_core::anvil::{ + block_entity::{BlockEntityData, BlockEntityVariant}, + entity::{EntityData, EntityDataKind}, +}; +use feather_server_types::{ + BlockEntityLoaderFn, BlockEntityLoaderRegistration, EntityLoaderFn, EntityLoaderRegistration, +}; +use fecs::EntityBuilder; + +/// Stores state for loading entities. +pub struct EntityLoader { + /// Map from `EntityDataKind` to functions + /// to load entities of those kinds. + loaders: AHashMap<EntityDataKind, &'static dyn EntityLoaderFn>, + block_loaders: AHashMap<BlockEntityVariant, &'static dyn BlockEntityLoaderFn>, +} + +impl Default for EntityLoader { + fn default() -> Self { + Self::new() + } +} + +impl EntityLoader { + /// Initializes a new entity loader state. This function allocates. + pub fn new() -> Self { + let loaders = inventory::iter::<EntityLoaderRegistration> + .into_iter() + .map(|registration| (registration.kind, registration.f)) + .collect(); + let block_loaders = inventory::iter::<BlockEntityLoaderRegistration> + .into_iter() + .map(|registration| (registration.kind, registration.f)) + .collect(); + Self { + loaders, + block_loaders, + } + } +} + +impl EntityLoader { + /// Converts an `EntityData` into an `EntityBuilder` + /// ready for spawning in a `World`. + pub fn load(&self, data: EntityData) -> Option<anyhow::Result<EntityBuilder>> { + self.loaders + .get(&EntityDataKind::from(&data)) + .map(|loader| loader(data)) + } + + /// Converts a `BlockEntityData` into an `EntityBuilder` + /// ready for spawning in a `World`. + pub fn load_block(&self, data: BlockEntityData) -> Option<anyhow::Result<EntityBuilder>> { + self.block_loaders + .get(&data.kind.variant()) + .map(|loader| loader(data)) + } +} diff --git a/feather/old/server/util/src/time.rs b/feather/old/server/util/src/time.rs new file mode 100644 index 000000000..41506e3a8 --- /dev/null +++ b/feather/old/server/util/src/time.rs @@ -0,0 +1,39 @@ +//! Handles world time. + +use feather_core::network::packets::TimeUpdate; +use feather_server_types::{Game, Network, PlayerPreJoinEvent, TimeUpdateEvent}; +use fecs::World; + +/// System for incrementing time each tick. +#[fecs::system] +pub fn increment_time(game: &mut Game) { + game.time.set_world_age(game.time.world_age() + 1); + game.time.set_time_of_day(game.time.time_of_day() + 1); +} + +#[fecs::event_handler] +pub fn on_time_update(event: &TimeUpdateEvent, game: &mut Game, world: &mut World) { + game.time.set_time_of_day(event.new_time); + game.broadcast_global( + world, + TimeUpdate { + world_age: game.time.world_age() as i64, + time_of_day: game.time.time_of_day() as i64, + }, + None, + ) +} + +/// Event handler for sending world time to players. +#[fecs::event_handler] +pub fn on_player_join_send_time(event: &PlayerPreJoinEvent, game: &Game, world: &mut World) { + let network = world.get::<Network>(event.player); + + // Send time to player. + let packet = TimeUpdate { + world_age: game.time.world_age() as i64, + time_of_day: game.time.time_of_day() as i64, + }; + + network.send(packet); +} diff --git a/feather/old/server/weather/Cargo.toml b/feather/old/server/weather/Cargo.toml new file mode 100644 index 000000000..5cb5feda2 --- /dev/null +++ b/feather/old/server/weather/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "feather-server-weather" +version = "0.6.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +feather-core = { path = "../../core" } +feather-server-types = { path = "../types" } +feather-server-util = { path = "../util" } + +fecs = { git = "https://github.com/feather-rs/fecs", rev = "0c4838d65b41ca059012b6e9147eabf0c275a731" } +rand = "0.7" diff --git a/feather/old/server/weather/src/lib.rs b/feather/old/server/weather/src/lib.rs new file mode 100644 index 000000000..ff79114af --- /dev/null +++ b/feather/old/server/weather/src/lib.rs @@ -0,0 +1,129 @@ +use feather_core::network::packets::ChangeGameState; +use feather_server_types::{Game, Network, PlayerPreJoinEvent, Weather, WeatherChangeEvent}; +use fecs::{Entity, World}; +use rand::Rng; + +const TICKS_DAY: i32 = 24_000; +const TICKS_HALF_DAY: i32 = TICKS_DAY / 2; +const TICKS_WEEK: i32 = TICKS_DAY * 7; +// const THUNDER_FACTOR: i32 = 10; + +#[allow(unused)] +pub fn clear_weather(game: &mut Game) { + let duration = game + .rng() + .gen_range(TICKS_HALF_DAY, TICKS_WEEK + TICKS_HALF_DAY); + set_weather(game, Weather::Clear, duration); +} + +#[fecs::system] +pub fn update_weather(game: &mut Game, world: &mut World) { + if game.level.clear_weather_time >= 0 { + game.level.clear_weather_time -= 1; + return; + } + + let from = get_weather(game); + + game.level.rain_time -= 1; + let mut to = if game.level.rain_time <= 0 { + if game.level.raining { + Weather::Clear + } else { + Weather::Rain + } + } else { + from + }; + + game.level.thunder_time -= 1; + to = if game.level.thunder_time <= 0 { + if game.level.thundering { + Weather::Clear + } else { + Weather::Thunder + } + } else { + to + }; + + if from != to { + let duration = match to { + Weather::Clear => game + .rng() + .gen_range(TICKS_HALF_DAY, TICKS_WEEK + TICKS_HALF_DAY), + _ => game.rng().gen_range(TICKS_HALF_DAY, TICKS_DAY), + }; + let event = WeatherChangeEvent { from, to, duration }; + game.handle(world, event); + if event.to != from { + set_weather(game, event.to, event.duration); + } + } +} + +pub fn get_weather(game: &Game) -> Weather { + if game.level.clear_weather_time > 0 { + Weather::Clear + } else if game.level.thundering { + Weather::Thunder + } else if game.level.raining { + Weather::Rain + } else { + Weather::Clear + } +} + +pub fn set_weather(game: &mut Game, weather: Weather, duration: i32) -> Weather { + let from = get_weather(game); + match weather { + Weather::Rain => { + game.level.raining = true; + game.level.rain_time = duration; + } + Weather::Thunder => { + game.level.thundering = true; + game.level.thunder_time = duration; + } + Weather::Clear => { + game.level.raining = false; + game.level.rain_time = 0; + game.level.thundering = false; + game.level.thunder_time = 0; + game.level.clear_weather_time = duration; + } + }; + from +} + +#[fecs::event_handler] +pub fn on_player_join_send_weather(event: &PlayerPreJoinEvent, game: &Game, world: &mut World) { + send_weather(world, event.player, get_weather(game)); +} + +#[fecs::event_handler] +pub fn on_weather_change_broadcast_weather( + event: &WeatherChangeEvent, + game: &mut Game, + world: &mut World, +) { + game.broadcast_global(world, create_weather_packet(event.to), None); +} + +pub fn send_weather(world: &mut World, player: Entity, to: Weather) { + let network = world.get::<Network>(player); + + network.send(create_weather_packet(to)); +} + +fn create_weather_packet(to: Weather) -> ChangeGameState { + let reason = match to { + Weather::Rain | Weather::Thunder => 2, + Weather::Clear => 1, + }; + + ChangeGameState { + reason, + value: 0f32, + } +} diff --git a/feather/plugin-host/Cargo.toml b/feather/plugin-host/Cargo.toml new file mode 100644 index 000000000..b25394923 --- /dev/null +++ b/feather/plugin-host/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "feather-plugin-host" +version = "0.1.0" +authors = [ "caelunshun <caelunshun@gmail.com>" ] +edition = "2018" + +[dependencies] +ahash = "0.7" +anyhow = "1" +bincode = "1" +bumpalo = "3" +bytemuck = "1" +feather-base = { path = "../base" } +feather-common = { path = "../common" } +feather-ecs = { path = "../ecs" } +feather-plugin-host-macros = { path = "macros" } + +libloading = "0.7" +log = "0.4" +paste = "1" +quill-common = { path = "../../quill/common" } +quill-plugin-format = { path = "../../quill/plugin-format" } +serde = "1" +tempfile = "3" +vec-arena = "1" +wasmer = { version = "2", default-features = false, features = [ "jit" ] } +wasmer-wasi = { version = "2", default-features = false, features = [ "host-fs", "sys" ] } +serde_json = "1" + +[features] +llvm = [ "wasmer/llvm" ] +cranelift = [ "wasmer/cranelift" ] diff --git a/feather/plugin-host/macros/Cargo.toml b/feather/plugin-host/macros/Cargo.toml new file mode 100644 index 000000000..eb89aeb1d --- /dev/null +++ b/feather/plugin-host/macros/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "feather-plugin-host-macros" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1", features = ["full"] } +quote = "1" +proc-macro2 = "1" + +[dev-dependencies] +anyhow = "1" diff --git a/feather/plugin-host/macros/src/lib.rs b/feather/plugin-host/macros/src/lib.rs new file mode 100644 index 000000000..f342e9060 --- /dev/null +++ b/feather/plugin-host/macros/src/lib.rs @@ -0,0 +1,101 @@ +use quote::{format_ident, quote}; +use syn::{FnArg, GenericArgument, PathSegment}; + +/// Annotates a function so that it implements +/// the NativeHostFunction trait. +#[proc_macro_attribute] +pub fn host_function( + _args: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let input: syn::ItemFn = syn::parse_macro_input!(input); + + let ident = input.sig.ident.clone(); + let gateway_ident = format_ident!("{}_gateway", input.sig.ident); + let struct_ident = format_ident!("{}_struct", input.sig.ident); + + let args = input + .sig + .inputs + .iter() + .map(|arg| match arg { + FnArg::Receiver(_) => panic!("self functions are not supported"), + FnArg::Typed(arg) => arg.clone(), + }) + .collect::<Vec<_>>(); + let args_idents: Vec<_> = args.iter().map(|arg| arg.pat.clone()).collect(); + let args_idents_without_cx: Vec<_> = args_idents.iter().skip(1).cloned().collect(); + let args_without_cx: Vec<_> = args.iter().skip(1).cloned().collect(); + + // Extract the inner return type from anyhow::Result<T>. + let ret = match input.sig.output.clone() { + syn::ReturnType::Default => return_type_panic(), + syn::ReturnType::Type(_, ty) => match *ty { + syn::Type::Path(path) => { + let segments: Vec<PathSegment> = path.path.segments.into_iter().collect(); + if segments[0].ident != "anyhow" { + return_type_panic(); + } + if segments[1].ident != "Result" { + return_type_panic(); + } + + let arg = segments[1].arguments.clone(); + match arg { + syn::PathArguments::AngleBracketed(inner) => { + match inner.args.first().unwrap() { + GenericArgument::Type(typ) => typ.clone(), + _ => return_type_panic(), + } + } + _ => return_type_panic(), + } + } + _ => return_type_panic(), + }, + }; + + let result = quote! { + #input + + extern "C" fn #gateway_ident(#(#args),*) -> #ret { + #ident(#(#args_idents),*).expect("host function panicked") + } + + #[allow(non_camel_case_types)] + pub struct #struct_ident; + + impl crate::host_function::NativeHostFunction for #struct_ident { + fn to_function_pointer(self) -> usize { + // Safety: see the Nomicon: https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html#representation + // For all targets that Feather compiles to, function pointers + // have the same layout as a usize. + + unsafe { + std::mem::transmute(#gateway_ident as *const ()) + } + } + } + + impl crate::host_function::WasmHostFunction for #struct_ident { + fn to_wasm_function(self, store: &wasmer::Store, env: crate::env::PluginEnv) -> wasmer::Function { + wasmer::Function::new_native_with_env(store, env, |env: &crate::env::PluginEnv, #(#args_without_cx),*| { + let result: anyhow::Result<_> = #ident(&env.context, #(#args_idents_without_cx),*); + match result { + Ok(ret) => ret, + Err(e) => { + unsafe { + wasmer::raise_user_trap(e.into()) + } + } + } + }) + } + } + }; + result.into() +} + +fn return_type_panic() -> ! { + panic!("host functions must return an anyhow::Result<T>") +} diff --git a/feather/plugin-host/src/context.rs b/feather/plugin-host/src/context.rs new file mode 100644 index 000000000..3e014ddcd --- /dev/null +++ b/feather/plugin-host/src/context.rs @@ -0,0 +1,433 @@ +use std::{ + alloc::Layout, + cell::{Ref, RefMut}, + marker::PhantomData, + mem::size_of, + panic::AssertUnwindSafe, + ptr::NonNull, + sync::atomic::{AtomicBool, Ordering}, +}; + +use anyhow::anyhow; +use bytemuck::{Pod, Zeroable}; +use feather_common::Game; +use feather_ecs::EntityBuilder; +use quill_common::Component; +use serde::de::DeserializeOwned; +use vec_arena::Arena; +use wasmer::{FromToNativeWasmType, Instance}; + +use crate::{host_function::WasmHostFunction, thread_pinned::ThreadPinned, PluginId}; + +mod native; +mod wasm; + +/// Wraps a pointer into a plugin's memory space. +#[derive(Copy, Clone, PartialEq, Eq, Zeroable)] +#[repr(transparent)] +pub struct PluginPtr<T> { + pub ptr: u64, + pub _marker: PhantomData<*const T>, +} + +impl<T> PluginPtr<T> { + pub fn as_native(&self) -> *const T { + self.ptr as usize as *const T + } + + /// # Safety + /// Adding `n` to this pointer + /// must produce a pointer within the same allocated + /// object. + #[must_use = "PluginPtr::add returns a new pointer"] + pub unsafe fn add(self, n: usize) -> Self { + Self { + ptr: self.ptr + (n * size_of::<T>()) as u64, + _marker: self._marker, + } + } + + /// # Safety + /// The cast must be valid. + pub unsafe fn cast<U>(self) -> PluginPtr<U> { + PluginPtr { + ptr: self.ptr, + _marker: PhantomData, + } + } +} + +unsafe impl<T: Copy + 'static> Pod for PluginPtr<T> {} + +/// Wraps a pointer into a plugin's memory space. +#[derive(Copy, Clone, PartialEq, Eq, Zeroable)] +#[repr(transparent)] +pub struct PluginPtrMut<T> { + pub ptr: u64, + pub _marker: PhantomData<*mut T>, +} + +impl<T> PluginPtrMut<T> { + pub fn as_native(&self) -> *mut T { + self.ptr as usize as *mut T + } + + /// # Safety + /// A null pointer must be valid in the context it is used. + pub unsafe fn null() -> Self { + Self { + ptr: 0, + _marker: PhantomData, + } + } + + /// # Safety + /// Adding `n` to this pointer + /// must produce a pointer within the same allocated + /// object. + #[must_use = "PluginPtrMut::add returns a new pointer"] + pub unsafe fn add(self, n: usize) -> Self { + Self { + ptr: self.ptr + (n * size_of::<T>()) as u64, + _marker: self._marker, + } + } + + /// # Safety + /// The cast must be valid. + pub unsafe fn cast<U>(self) -> PluginPtrMut<U> { + PluginPtrMut { + ptr: self.ptr, + _marker: PhantomData, + } + } +} + +unsafe impl<T: Copy + 'static> Pod for PluginPtrMut<T> {} + +unsafe impl<T: Copy> FromToNativeWasmType for PluginPtr<T> { + type Native = i64; + + fn from_native(native: Self::Native) -> Self { + Self { + ptr: native as u64, + _marker: PhantomData, + } + } + + fn to_native(self) -> Self::Native { + self.ptr as i64 + } +} + +unsafe impl<T: Copy> FromToNativeWasmType for PluginPtrMut<T> { + type Native = i64; + + fn from_native(native: Self::Native) -> Self { + Self { + ptr: native as u64, + _marker: PhantomData, + } + } + + fn to_native(self) -> Self::Native { + self.ptr as i64 + } +} + +/// Context of a running plugin. +/// +/// Provides methods to access plugin memory, +/// invoke exported functions, and access the `Game`. +/// +/// This type abstracts over WASM or native plugins, +/// providing the same interface for both. +/// +/// # Safety +/// The `native` version of the plugin context +/// dereferences raw pointers. We assume pointers +/// passed by plugins are valid. Most functions +/// will cause undefined behavior if these constraints +/// are violated. +/// +/// We type-encode that a pointer originates from a plugin +/// using the `PluginPtr` structs. Methods that +/// dereference pointers take instances of these +/// structs. Since creating a `PluginPtr` is unsafe, +/// `PluginContext` methods don't have to be marked +/// unsafe. +/// +/// On WASM targets, the plugin is never trusted, +/// and pointer accesses are checked. Undefined behavior +/// can never occur as a result of malicious plugin input. +pub struct PluginContext { + inner: Inner, + + /// Whether the plugin is currently being invoked + /// on the main thread. + /// If this is `true`, then plugin functions are on the call stack. + invoking_on_main_thread: AtomicBool, + + /// The current `Game`. + /// + /// Set to `None` if `invoking_on_main_thread` is `false`. + /// Otherwise, must point to a valid game. The pointer + /// must be cleared after the plugin finishes executing + /// or we risk a dangling reference. + game: ThreadPinned<Option<NonNull<Game>>>, + + /// ID of the plugin. + id: PluginId, + + /// Active entity builders for the plugin. + pub entity_builders: ThreadPinned<Arena<EntityBuilder>>, +} + +impl PluginContext { + /// Creates a new WASM plugin context. + pub fn new_wasm(id: PluginId) -> Self { + Self { + inner: Inner::Wasm(ThreadPinned::new(wasm::WasmPluginContext::new())), + invoking_on_main_thread: AtomicBool::new(false), + game: ThreadPinned::new(None), + id, + entity_builders: ThreadPinned::new(Arena::new()), + } + } + + /// Creates a new native plugin context. + pub fn new_native(id: PluginId) -> Self { + Self { + inner: Inner::Native(native::NativePluginContext::new()), + invoking_on_main_thread: AtomicBool::new(false), + game: ThreadPinned::new(None), + id, + entity_builders: ThreadPinned::new(Arena::new()), + } + } + + pub fn init_with_instance(&self, instance: &Instance) -> anyhow::Result<()> { + match &self.inner { + Inner::Wasm(w) => w.borrow_mut().init_with_instance(instance), + Inner::Native(_) => panic!("cannot initialize native plugin context"), + } + } + + /// Enters the plugin context, invoking a function inside the plugin. + /// + /// # Panics + /// Panics if we are already inside the plugin context. + /// Panics if not called on the main thread. + pub fn enter<R>(&self, game: &mut Game, callback: impl FnOnce() -> R) -> R { + let was_already_entered = self.invoking_on_main_thread.swap(true, Ordering::SeqCst); + assert!(!was_already_entered, "cannot recursively invoke a plugin"); + + *self.game.borrow_mut() = Some(NonNull::from(game)); + + // If a panic occurs, we need to catch it so + // we clear `self.game`. Otherwise, we get + // a dangling pointer. + let result = std::panic::catch_unwind(AssertUnwindSafe(callback)); + + self.invoking_on_main_thread.store(false, Ordering::SeqCst); + *self.game.borrow_mut() = None; + + self.bump_reset(); + + result.unwrap() + } + + /// Gets a mutable reference to the `Game`. + /// + /// # Panics + /// Panics if the plugin is not currently being + /// invoked on the main thread. + pub fn game_mut(&self) -> RefMut<Game> { + let ptr = self.game.borrow_mut(); + RefMut::map(ptr, |ptr| { + let game_ptr = ptr.expect("plugin is not exeuctugin"); + + assert!(self.invoking_on_main_thread.load(Ordering::Relaxed)); + + // SAFETY: `game_ptr` points to a valid `Game` whenever + // the plugin is executing. If the plugin is not + // executing, then we already panicked when unwrapping `ptr`. + unsafe { &mut *game_ptr.as_ptr() } + }) + } + + /// Gets the plugin ID. + pub fn plugin_id(&self) -> PluginId { + self.id + } + + /// Accesses a byte slice in the plugin's memory space. + /// + /// # Safety + /// **WASM**: mutating plugin memory or invoking + /// plugin functions while this byte slice is + /// alive is undefined behavior. + /// **Native**: `ptr` must be valid. + pub unsafe fn deref_bytes(&self, ptr: PluginPtr<u8>, len: u32) -> anyhow::Result<&[u8]> { + match &self.inner { + Inner::Wasm(w) => { + let w = w.borrow(); + let bytes = w.deref_bytes(ptr, len)?; + Ok(unsafe { std::slice::from_raw_parts(bytes.as_ptr(), bytes.len()) }) + } + Inner::Native(n) => n.deref_bytes(ptr, len), + } + } + + /// Accesses a byte slice in the plugin's memory space. + /// + /// # Safety + /// **WASM**: accessing plugin memory or invoking + /// plugin functions while this byte slice is + /// alive is undefined behavior. + /// **Native**: `ptr` must be valid and the aliasing + /// rules must not be violated. + pub unsafe fn deref_bytes_mut( + &self, + ptr: PluginPtrMut<u8>, + len: u32, + ) -> anyhow::Result<&mut [u8]> { + match &self.inner { + Inner::Wasm(w) => { + let w = w.borrow(); + let bytes = w.deref_bytes_mut(ptr, len)?; + Ok(unsafe { std::slice::from_raw_parts_mut(bytes.as_mut_ptr(), bytes.len()) }) + } + Inner::Native(n) => n.deref_bytes_mut(ptr, len), + } + } + + /// Accesses a `Pod` value in the plugin's memory space. + pub fn read_pod<T: Pod>(&self, ptr: PluginPtr<T>) -> anyhow::Result<T> { + // SAFETY: we do not return a reference to these + // bytes. + unsafe { + let bytes = self.deref_bytes(ptr.cast(), size_of::<T>() as u32)?; + bytemuck::try_from_bytes(bytes) + .map_err(|_| anyhow!("badly aligned data")) + .map(|val| *val) + } + } + + /// Accesses a `bincode`-encoded value in the plugin's memory space. + pub fn read_bincode<T: DeserializeOwned>( + &self, + ptr: PluginPtr<u8>, + len: u32, + ) -> anyhow::Result<T> { + // SAFETY: we do not return a reference to these + // bytes. + unsafe { + let bytes = self.deref_bytes(ptr.cast(), len)?; + bincode::deserialize(bytes).map_err(From::from) + } + } + + /// Accesses a `json`-encoded value in the plugin's memory space. + pub fn read_json<T: DeserializeOwned>( + &self, + ptr: PluginPtr<u8>, + len: u32, + ) -> anyhow::Result<T> { + // SAFETY: we do not return a reference to these + // bytes. + unsafe { + let bytes = self.deref_bytes(ptr.cast(), len)?; + serde_json::from_slice(bytes).map_err(From::from) + } + } + + /// Deserializes a component value in the plugin's memory space. + pub fn read_component<T: Component>(&self, ptr: PluginPtr<u8>, len: u32) -> anyhow::Result<T> { + // SAFETY: we do not return a reference to these + // bytes. + unsafe { + let bytes = self.deref_bytes(ptr.cast(), len)?; + T::from_bytes(bytes) + .ok_or_else(|| anyhow!("malformed component")) + .map(|(component, _bytes_read)| component) + } + } + + /// Reads a string from the plugin's memory space. + pub fn read_string(&self, ptr: PluginPtr<u8>, len: u32) -> anyhow::Result<String> { + // SAFETY: we do not return a reference to these bytes. + unsafe { + let bytes = self.deref_bytes(ptr.cast(), len)?; + let string = std::str::from_utf8(bytes)?.to_owned(); + Ok(string) + } + } + + /// Reads a `Vec<u8>` from the plugin's memory space. + pub fn read_bytes(&self, ptr: PluginPtr<u8>, len: u32) -> anyhow::Result<Vec<u8>> { + // SAFETY: we do not return a reference to these bytes. + unsafe { + let bytes = self.deref_bytes(ptr.cast(), len)?; + Ok(bytes.to_owned()) + } + } + + /// Allocates some memory within the plugin's bump + /// allocator. + /// + /// The memory is reset after the plugin finishes + /// executing the current system. + pub fn bump_allocate(&self, layout: Layout) -> anyhow::Result<PluginPtrMut<u8>> { + match &self.inner { + Inner::Wasm(w) => w.borrow().bump_allocate(layout), + Inner::Native(n) => n.bump_allocate(layout), + } + } + + /// Bump allocates some memory, then copies `data` into it. + pub fn bump_allocate_and_write_bytes(&self, data: &[u8]) -> anyhow::Result<PluginPtrMut<u8>> { + let layout = Layout::array::<u8>(data.len())?; + let ptr = self.bump_allocate(layout)?; + + // SAFETY: our access to these bytes is isolated to the + // current function. `ptr` is valid as it was just allocated. + unsafe { + self.write_bytes(ptr, data)?; + } + + Ok(ptr) + } + + /// Writes `data` to `ptr`. + /// + /// # Safety + /// **WASM**: No concerns. + /// **NATIVE**: `ptr` must point to a slice + /// of at least `len` valid bytes. + pub unsafe fn write_bytes(&self, ptr: PluginPtrMut<u8>, data: &[u8]) -> anyhow::Result<()> { + let bytes = self.deref_bytes_mut(ptr, data.len() as u32)?; + bytes.copy_from_slice(data); + Ok(()) + } + + /// Writes a `Pod` type to `ptr`. + pub fn write_pod<T: Pod>(&self, ptr: PluginPtrMut<T>, value: T) -> anyhow::Result<()> { + // SAFETY: Unlike `write_bytes`, we know `ptr` is valid for values + // of type `T` because of its type parameter. + unsafe { self.write_bytes(ptr.cast(), bytemuck::bytes_of(&value)) } + } + + /// Deallocates all bump-allocated memory. + fn bump_reset(&self) { + match &self.inner { + Inner::Wasm(w) => w.borrow().bump_reset(), + Inner::Native(n) => n.bump_reset(), + } + } +} + +enum Inner { + Wasm(ThreadPinned<wasm::WasmPluginContext>), + Native(native::NativePluginContext), +} diff --git a/feather/plugin-host/src/context/native.rs b/feather/plugin-host/src/context/native.rs new file mode 100644 index 000000000..564c5d8fb --- /dev/null +++ b/feather/plugin-host/src/context/native.rs @@ -0,0 +1,49 @@ +use std::{alloc::Layout, marker::PhantomData}; + +use crate::thread_pinned::ThreadPinned; + +use super::{PluginPtr, PluginPtrMut}; + +pub struct NativePluginContext { + bump: ThreadPinned<Vec<(*mut u8, Layout)>>, +} + +impl NativePluginContext { + pub fn new() -> Self { + Self { + bump: ThreadPinned::new(Vec::new()), + } + } + + pub unsafe fn deref_bytes(&self, ptr: PluginPtr<u8>, len: u32) -> anyhow::Result<&[u8]> { + Ok(std::slice::from_raw_parts(ptr.as_native(), len as usize)) + } + + pub unsafe fn deref_bytes_mut( + &self, + ptr: PluginPtrMut<u8>, + len: u32, + ) -> anyhow::Result<&mut [u8]> { + Ok(std::slice::from_raw_parts_mut( + ptr.as_native(), + len as usize, + )) + } + + pub fn bump_allocate(&self, layout: Layout) -> anyhow::Result<PluginPtrMut<u8>> { + let ptr = unsafe { std::alloc::alloc(layout) }; + self.bump.borrow_mut().push((ptr, layout)); + Ok(PluginPtrMut { + ptr: ptr as usize as u64, + _marker: PhantomData, + }) + } + + pub fn bump_reset(&self) { + for (ptr, layout) in self.bump.borrow_mut().drain(..) { + unsafe { + std::alloc::dealloc(ptr, layout); + } + } + } +} diff --git a/feather/plugin-host/src/context/wasm.rs b/feather/plugin-host/src/context/wasm.rs new file mode 100644 index 000000000..4b079fe01 --- /dev/null +++ b/feather/plugin-host/src/context/wasm.rs @@ -0,0 +1,79 @@ +use std::{alloc::Layout, marker::PhantomData}; + +use anyhow::bail; +use bump::WasmBump; +use wasmer::{Instance, LazyInit, Memory}; + +use crate::thread_pinned::ThreadPinned; + +use super::{PluginPtr, PluginPtrMut}; + +mod bump; + +#[derive(Default)] +pub struct WasmPluginContext { + bump: LazyInit<ThreadPinned<WasmBump>>, + + memory: LazyInit<Memory>, +} + +impl WasmPluginContext { + pub fn new() -> Self { + Self::default() + } + + pub fn init_with_instance(&mut self, instance: &Instance) -> anyhow::Result<()> { + let allocate = instance.exports.get_function("quill_allocate")?; + let deallocate = instance.exports.get_function("quill_deallocate")?; + + let bump = WasmBump::new(allocate.native()?, deallocate.native()?)?; + self.bump.initialize(ThreadPinned::new(bump)); + + self.memory + .initialize(instance.exports.get_memory("memory")?.clone()); + + Ok(()) + } + + pub unsafe fn deref_bytes(&self, ptr: PluginPtr<u8>, len: u32) -> anyhow::Result<&[u8]> { + let data = self.memory.get_ref().unwrap().data_unchecked(); + let offset = ptr.ptr as usize; + + if data.len() <= offset + len as usize { + bail!("pointer out of bounds"); + } + + Ok(&data[offset..(offset + len as usize)]) + } + + pub unsafe fn deref_bytes_mut( + &self, + ptr: PluginPtrMut<u8>, + len: u32, + ) -> anyhow::Result<&mut [u8]> { + let data = self.memory.get_ref().unwrap().data_unchecked_mut(); + let offset = ptr.ptr as usize; + + if data.len() <= offset + len as usize { + bail!("pointer out of bounds"); + } + + Ok(&mut data[offset..(offset + len as usize)]) + } + + pub fn bump_allocate(&self, layout: Layout) -> anyhow::Result<PluginPtrMut<u8>> { + self.bump + .get_ref() + .unwrap() + .borrow_mut() + .alloc(layout) + .map(|wasm_ptr| PluginPtrMut { + ptr: wasm_ptr.offset() as u64, + _marker: PhantomData, + }) + } + + pub fn bump_reset(&self) { + let _ = self.bump.get_ref().unwrap().borrow_mut().reset(); + } +} diff --git a/feather/plugin-host/src/context/wasm/bump.rs b/feather/plugin-host/src/context/wasm/bump.rs new file mode 100644 index 000000000..6c97db69a --- /dev/null +++ b/feather/plugin-host/src/context/wasm/bump.rs @@ -0,0 +1,146 @@ +use std::{alloc::Layout, cell::Cell}; + +use anyhow::Context; +use wasmer::{NativeFunc, WasmPtr}; + +const INITIAL_CHUNK_SIZE: usize = 2048; + +const CHUNK_ALIGN: usize = 16; + +fn round_up_to(n: usize, divisor: usize) -> Option<usize> { + debug_assert!(divisor > 0); + debug_assert!(divisor.is_power_of_two()); + Some(n.checked_add(divisor - 1)? & !(divisor - 1)) +} + +/// Host-controlled bump allocator for a WASM plugin. +/// See the Quill docs for why we use this. +/// +/// The implementation is mostly ported from the `bumpalo` +/// crate. +pub struct WasmBump { + /// Plugin function to allocate memory. Used + /// for the slow path when the current chunk + /// is exhausted. + allocate_function: NativeFunc<(u32, u32), u32>, + /// Plugin function to deallocate memory. + deallocate_function: NativeFunc<(u32, u32, u32)>, + /// Allocated chunks. + chunks: Vec<Chunk>, +} + +impl WasmBump { + /// Creates a new bump allocator. + pub fn new( + allocate_function: NativeFunc<(u32, u32), u32>, + deallocate_function: NativeFunc<(u32, u32, u32)>, + ) -> anyhow::Result<Self> { + let mut this = Self { + allocate_function, + deallocate_function, + chunks: Vec::new(), + }; + Ok(this) + } + + /// Allocates memory of the given layout + /// within the plugin's linear memory. + pub fn alloc(&mut self, layout: Layout) -> anyhow::Result<WasmPtr<u8>> { + let offset = match self.alloc_fast_path(layout) { + Some(offset) => offset, + None => self.alloc_slow_path(layout)?, + }; + Ok(WasmPtr::new(offset)) + } + + fn alloc_fast_path(&self, layout: Layout) -> Option<u32> { + let chunk = self.chunks.last().expect(">0 chunks"); + let ptr = chunk.ptr.get(); + let start = chunk.start; + debug_assert!(start <= ptr); + + let ptr = ptr.checked_sub(layout.size() as u32)?; + let aligned_ptr = ptr & !(layout.align() as u32 - 1); + + if aligned_ptr >= start { + chunk.ptr.set(aligned_ptr); + Some(aligned_ptr) + } else { + None + } + } + + /// Slow path for allocation where we need to allocate + /// a new chunk. + fn alloc_slow_path(&mut self, layout: Layout) -> anyhow::Result<u32> { + let previous_size = self.chunks.last().expect(">0 chunks").layout.size(); + let new_chunk = self.allocate_chunk(Some(layout), Some(previous_size))?; + self.chunks.push(new_chunk); + Ok(self + .alloc_fast_path(layout) + .expect("new chunk can fit layout")) + } + + fn allocate_chunk( + &self, + min_layout: Option<Layout>, + previous_size: Option<usize>, + ) -> anyhow::Result<Chunk> { + let mut new_size = match previous_size { + Some(previous_size) => previous_size + .checked_mul(2) + .context("chunk overflows usize")?, + None => INITIAL_CHUNK_SIZE, + }; + let mut align = CHUNK_ALIGN; + if let Some(min_layout) = min_layout { + align = align.max(min_layout.align()); + let requested_size = + round_up_to(min_layout.size(), align).context("allocation too large")?; + new_size = new_size.max(requested_size); + } + assert_eq!(align % CHUNK_ALIGN, 0); + assert_eq!(new_size % CHUNK_ALIGN, 0); + let layout = Layout::from_size_align(new_size, align).context("size or align is 0")?; + assert!(new_size >= previous_size.unwrap_or(0) * 2); + let start = self + .allocate_function + .call(layout.size() as u32, layout.align() as u32)?; + Ok(Chunk { + start, + layout, + ptr: Cell::new(start + new_size as u32), + }) + } + + /// Resets the bump allocator, freeing + /// all allocated memory. + pub fn reset(&mut self) -> anyhow::Result<()> { + // Free all but the last chunk. + for chunk in self.chunks.drain(..self.chunks.len()) { + self.deallocate_function.call( + chunk.start, + chunk.layout.size() as u32, + chunk.layout.align() as u32, + )?; + } + + // Allocate initial chunk + let chunk = self.allocate_chunk(None, None)?; + self.chunks.push(chunk); + + Ok(()) + } +} + +/// A chunk of memory in the bump allocator. +struct Chunk { + /// Offset into linear memory of the start + /// of this chunk. + start: u32, + /// Layout of the chunk. + layout: Layout, + /// Pointer to the next available byte plus one + /// in the chunk. Starts at the end of the chunk. + ptr: Cell<u32>, +} diff --git a/feather/plugin-host/src/env.rs b/feather/plugin-host/src/env.rs new file mode 100644 index 000000000..c7bc01ba9 --- /dev/null +++ b/feather/plugin-host/src/env.rs @@ -0,0 +1,20 @@ +use std::sync::Arc; + +use wasmer::{ExportError, HostEnvInitError, Instance, WasmerEnv}; + +use crate::context::PluginContext; + +/// The [`WasmerEnv`] passed to host calls. +#[derive(Clone)] +pub struct PluginEnv { + pub context: Arc<PluginContext>, +} + +impl WasmerEnv for PluginEnv { + fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { + self.context + .init_with_instance(instance) + .map_err(|e| wasmer::HostEnvInitError::Export(ExportError::Missing(e.to_string())))?; + Ok(()) + } +} diff --git a/feather/plugin-host/src/host_calls.rs b/feather/plugin-host/src/host_calls.rs new file mode 100644 index 000000000..91c0109f4 --- /dev/null +++ b/feather/plugin-host/src/host_calls.rs @@ -0,0 +1,76 @@ +//! Implements all host calls defined in the `quill-sys` crate. + +use std::collections::HashMap; +use std::sync::Arc; + +use paste::paste; + +use crate::env::PluginEnv; +use crate::host_function::{NativeHostFunction, WasmHostFunction}; + +mod block; +mod component; +mod entity; +mod entity_builder; +mod event; +mod plugin_message; +mod query; +mod system; + +macro_rules! host_calls { + ( + $($name:literal => $function:ident),* $(,)? + ) => { + pub fn generate_vtable() -> HashMap<&'static str, usize> { + let mut vtable = HashMap::new(); + $( + paste! { + vtable.insert($name, [< $function _struct >].to_function_pointer()); + } + )* + vtable + } + + pub fn generate_import_object(store: &wasmer::Store, env: &PluginEnv) -> wasmer::ImportObject { + $( + paste! { + let $function = [< $function _struct >].to_wasm_function(store, env.clone()); + } + )* + wasmer::imports! { + "quill_01" => {$( + $name => $function, + )*} + } + } + } +} + +use block::*; +use component::*; +use entity::*; +use entity_builder::*; +use event::*; +use plugin_message::*; +use query::*; +use system::*; + +host_calls! { + "register_system" => register_system, + "entity_get_component" => entity_get_component, + "entity_set_component" => entity_set_component, + "entity_add_event" => entity_add_event, + "add_event" => add_event, + "entity_builder_new_empty" => entity_builder_new_empty, + "entity_builder_new" => entity_builder_new, + "entity_builder_add_component" => entity_builder_add_component, + "entity_builder_finish" => entity_builder_finish, + "entity_query" => entity_query, + "entity_exists" => entity_exists, + "entity_send_message" => entity_send_message, + "entity_send_title" => entity_send_title, + "block_get" => block_get, + "block_set" => block_set, + "block_fill_chunk_section" => block_fill_chunk_section, + "plugin_message_send" => plugin_message_send, +} diff --git a/feather/plugin-host/src/host_calls/block.rs b/feather/plugin-host/src/host_calls/block.rs new file mode 100644 index 000000000..cc1f14b8b --- /dev/null +++ b/feather/plugin-host/src/host_calls/block.rs @@ -0,0 +1,42 @@ +use std::convert::TryInto; + +use feather_base::{BlockId, BlockPosition, ChunkPosition}; +use feather_plugin_host_macros::host_function; +use quill_common::block::BlockGetResult; + +use crate::context::PluginContext; + +/// NB: `u32` has the same layout as `BlockGetResult`. +#[host_function] +pub fn block_get(cx: &PluginContext, x: i32, y: i32, z: i32) -> anyhow::Result<u32> { + let pos = BlockPosition::new(x, y, z).try_into()?; + + let block = cx.game_mut().block(pos); + let result = BlockGetResult::new(block.map(BlockId::vanilla_id)); + Ok(result.to_u32()) +} + +#[host_function] +pub fn block_set(cx: &PluginContext, x: i32, y: i32, z: i32, block_id: u16) -> anyhow::Result<u32> { + let pos = BlockPosition::new(x, y, z).try_into()?; + let block = BlockId::from_vanilla_id(block_id); + + let was_successful = cx.game_mut().set_block(pos, block); + Ok(was_successful as u32) +} + +#[host_function] +pub fn block_fill_chunk_section( + cx: &PluginContext, + chunk_x: i32, + section_y: u32, + chunk_z: i32, + block_id: u16, +) -> anyhow::Result<u32> { + let chunk_pos = ChunkPosition::new(chunk_x, chunk_z); + let block = BlockId::from_vanilla_id(block_id); + let was_successful = cx + .game_mut() + .fill_chunk_section(chunk_pos, section_y as usize, block); + Ok(was_successful as u32) +} diff --git a/feather/plugin-host/src/host_calls/component.rs b/feather/plugin-host/src/host_calls/component.rs new file mode 100644 index 000000000..b9722255d --- /dev/null +++ b/feather/plugin-host/src/host_calls/component.rs @@ -0,0 +1,99 @@ +use anyhow::Context; +use feather_ecs::Entity; +use feather_plugin_host_macros::host_function; +use quill_common::{component::ComponentVisitor, HostComponent}; + +use crate::context::{PluginContext, PluginPtr, PluginPtrMut}; + +struct GetComponentVisitor<'a> { + cx: &'a PluginContext, + entity: Entity, +} + +impl<'a> ComponentVisitor<anyhow::Result<(PluginPtrMut<u8>, u32)>> for GetComponentVisitor<'a> { + fn visit<T: quill_common::Component>(self) -> anyhow::Result<(PluginPtrMut<u8>, u32)> { + let game = self.cx.game_mut(); + let component = match game.ecs.get::<T>(self.entity) { + Ok(c) => c, + Err(_) => return Ok((unsafe { PluginPtrMut::null() }, 0)), + }; + let bytes = component.to_cow_bytes(); + let ptr = self.cx.bump_allocate_and_write_bytes(&bytes)?; + + Ok((ptr, bytes.len() as u32)) + } +} + +#[host_function] +pub fn entity_get_component( + cx: &PluginContext, + entity: u64, + component: u32, + bytes_ptr_ptr: PluginPtrMut<PluginPtrMut<u8>>, + bytes_len_ptr: PluginPtrMut<u32>, +) -> anyhow::Result<()> { + let component = HostComponent::from_u32(component).context("invalid component")?; + let entity = Entity::from_bits(entity); + let visitor = GetComponentVisitor { cx, entity }; + let (bytes_ptr, bytes_len) = component.visit(visitor)?; + + cx.write_pod(bytes_ptr_ptr, bytes_ptr)?; + cx.write_pod(bytes_len_ptr, bytes_len)?; + + Ok(()) +} + +pub(crate) struct InsertComponentVisitor<'a> { + pub cx: &'a PluginContext, + pub bytes_ptr: PluginPtr<u8>, + pub bytes_len: u32, + pub action: SetComponentAction, +} + +pub(crate) enum SetComponentAction { + SetComponent(Entity), + AddEntityEvent(Entity), + AddEvent, +} + +impl<'a> ComponentVisitor<anyhow::Result<()>> for InsertComponentVisitor<'a> { + fn visit<T: quill_common::Component>(self) -> anyhow::Result<()> { + let component = self + .cx + .read_component::<T>(self.bytes_ptr, self.bytes_len)?; + let mut game = self.cx.game_mut(); + + match self.action { + SetComponentAction::SetComponent(entity) => { + let _ = game.ecs.insert(entity, component); + } + SetComponentAction::AddEntityEvent(entity) => { + let _ = game.ecs.insert_entity_event(entity, component); + } + SetComponentAction::AddEvent => { + game.ecs.insert_event(component); + } + } + + Ok(()) + } +} + +#[host_function] +pub fn entity_set_component( + cx: &PluginContext, + entity: u64, + component: u32, + bytes_ptr: PluginPtr<u8>, + bytes_len: u32, +) -> anyhow::Result<()> { + let entity = Entity::from_bits(entity); + let component = HostComponent::from_u32(component).context("invalid component")?; + let visitor = InsertComponentVisitor { + cx, + bytes_ptr, + bytes_len, + action: SetComponentAction::SetComponent(entity), + }; + component.visit(visitor) +} diff --git a/feather/plugin-host/src/host_calls/entity.rs b/feather/plugin-host/src/host_calls/entity.rs new file mode 100644 index 000000000..0224f6a0c --- /dev/null +++ b/feather/plugin-host/src/host_calls/entity.rs @@ -0,0 +1,39 @@ +use feather_base::Text; +use feather_common::chat::{ChatKind, ChatMessage}; +use feather_ecs::Entity; +use feather_plugin_host_macros::host_function; + +use crate::context::{PluginContext, PluginPtr}; + +#[host_function] +pub fn entity_exists(cx: &PluginContext, entity: u64) -> anyhow::Result<u32> { + Ok(cx.game_mut().ecs.entity(Entity::from_bits(entity)).is_ok()).map(|b| b as u32) +} + +#[host_function] +pub fn entity_send_message( + cx: &PluginContext, + entity: u64, + message_ptr: PluginPtr<u8>, + message_len: u32, +) -> anyhow::Result<()> { + let message = cx.read_json(message_ptr, message_len)?; + let entity = Entity::from_bits(entity); + let _ = cx + .game_mut() + .send_message(entity, ChatMessage::new(ChatKind::System, message)); + Ok(()) +} + +#[host_function] +pub fn entity_send_title( + cx: &PluginContext, + entity: u64, + title_ptr: PluginPtr<u8>, + title_len: u32, +) -> anyhow::Result<()> { + let title = cx.read_json(title_ptr, title_len)?; + let entity = Entity::from_bits(entity); + cx.game_mut().send_title(entity, title); + Ok(()) +} diff --git a/feather/plugin-host/src/host_calls/entity_builder.rs b/feather/plugin-host/src/host_calls/entity_builder.rs new file mode 100644 index 000000000..3274ec0fe --- /dev/null +++ b/feather/plugin-host/src/host_calls/entity_builder.rs @@ -0,0 +1,89 @@ +use anyhow::{bail, Context}; +use feather_base::Position; +use feather_plugin_host_macros::host_function; +use quill_common::{component::ComponentVisitor, HostComponent}; + +use crate::context::{PluginContext, PluginPtr}; + +#[host_function] +pub fn entity_builder_new_empty(cx: &PluginContext) -> anyhow::Result<u32> { + let builder = cx.game_mut().create_empty_entity_builder(); + let id = cx.entity_builders.borrow_mut().insert(builder); + + if id > u32::MAX as usize { + bail!("created too many entity builders!"); + } + + Ok(id as u32) +} + +#[host_function] +pub fn entity_builder_new( + cx: &PluginContext, + position: PluginPtr<Position>, + entity_init_ptr: PluginPtr<u8>, + entity_init_len: u32, +) -> anyhow::Result<u32> { + let position = cx.read_pod(position)?; + let init = cx.read_bincode(entity_init_ptr, entity_init_len)?; + let builder = cx.game_mut().create_entity_builder(position, init); + let id = cx.entity_builders.borrow_mut().insert(builder); + + if id > u32::MAX as usize { + bail!("created too many entity builders"); + } + + Ok(id as u32) +} + +struct BuilderAddComponentVisitor<'a> { + builder: u32, + cx: &'a PluginContext, + bytes_ptr: PluginPtr<u8>, + bytes_len: u32, +} + +impl<'a> ComponentVisitor<anyhow::Result<()>> for BuilderAddComponentVisitor<'a> { + fn visit<T: quill_common::Component>(self) -> anyhow::Result<()> { + let component = self + .cx + .read_component::<T>(self.bytes_ptr, self.bytes_len)?; + self.cx + .entity_builders + .borrow_mut() + .get_mut(self.builder as usize) + .context("invalid entity builder")? + .add(component); + Ok(()) + } +} + +#[host_function] +pub fn entity_builder_add_component( + cx: &PluginContext, + builder: u32, + component: u32, + bytes_ptr: PluginPtr<u8>, + bytes_len: u32, +) -> anyhow::Result<()> { + let component = HostComponent::from_u32(component).context("invalid component")?; + let visitor = BuilderAddComponentVisitor { + builder, + cx, + bytes_ptr, + bytes_len, + }; + component.visit(visitor) +} + +#[host_function] +pub fn entity_builder_finish(cx: &PluginContext, builder: u32) -> anyhow::Result<u64> { + let builder = cx + .entity_builders + .borrow_mut() + .remove(builder as usize) + .context("invalid entity builder")?; + + let entity = cx.game_mut().spawn_entity(builder); + Ok(entity.to_bits()) +} diff --git a/feather/plugin-host/src/host_calls/event.rs b/feather/plugin-host/src/host_calls/event.rs new file mode 100644 index 000000000..649ffce65 --- /dev/null +++ b/feather/plugin-host/src/host_calls/event.rs @@ -0,0 +1,42 @@ +use crate::context::{PluginContext, PluginPtr}; +use crate::host_calls::component::{InsertComponentVisitor, SetComponentAction}; +use anyhow::Context; +use feather_ecs::Entity; +use feather_plugin_host_macros::host_function; +use quill_common::HostComponent; + +#[host_function] +pub fn entity_add_event( + cx: &PluginContext, + entity: u64, + event: u32, + bytes_ptr: PluginPtr<u8>, + bytes_len: u32, +) -> anyhow::Result<()> { + let entity = Entity::from_bits(entity); + let event = HostComponent::from_u32(event).context("invalid component")?; + let visitor = InsertComponentVisitor { + cx, + bytes_ptr, + bytes_len, + action: SetComponentAction::AddEntityEvent(entity), + }; + event.visit(visitor) +} + +#[host_function] +pub fn add_event( + cx: &PluginContext, + event: u32, + bytes_ptr: PluginPtr<u8>, + bytes_len: u32, +) -> anyhow::Result<()> { + let event = HostComponent::from_u32(event).context("invalid component")?; + let visitor = InsertComponentVisitor { + cx, + bytes_ptr, + bytes_len, + action: SetComponentAction::AddEvent, + }; + event.visit(visitor) +} diff --git a/feather/plugin-host/src/host_calls/plugin_message.rs b/feather/plugin-host/src/host_calls/plugin_message.rs new file mode 100644 index 000000000..55108733c --- /dev/null +++ b/feather/plugin-host/src/host_calls/plugin_message.rs @@ -0,0 +1,24 @@ +use feather_common::events::PluginMessageEvent; +use feather_ecs::Entity; +use feather_plugin_host_macros::host_function; + +use crate::context::{PluginContext, PluginPtr}; + +#[host_function] +pub fn plugin_message_send( + cx: &PluginContext, + entity: u64, + channel_ptr: PluginPtr<u8>, + channel_len: u32, + data_ptr: PluginPtr<u8>, + data_len: u32, +) -> anyhow::Result<()> { + let channel = cx.read_string(channel_ptr, channel_len)?; + let data = cx.read_bytes(data_ptr, data_len)?; + + let entity = Entity::from_bits(entity); + let event = PluginMessageEvent { channel, data }; + cx.game_mut().ecs.insert_entity_event(entity, event)?; + + Ok(()) +} diff --git a/feather/plugin-host/src/host_calls/query.rs b/feather/plugin-host/src/host_calls/query.rs new file mode 100644 index 000000000..f52a85f4b --- /dev/null +++ b/feather/plugin-host/src/host_calls/query.rs @@ -0,0 +1,154 @@ +//! Implements the `entity_query` host call. + +use std::{alloc::Layout, any::TypeId, mem::size_of, ptr}; + +use anyhow::Context; +use feather_ecs::{DynamicQuery, DynamicQueryTypes, Ecs}; +use feather_plugin_host_macros::host_function; +use quill_common::{ + component::{ComponentVisitor, SerializationMethod}, + entity::QueryData, + Component, EntityId, HostComponent, PointerMut, +}; + +use crate::context::{PluginContext, PluginPtr, PluginPtrMut}; + +#[host_function] +pub fn entity_query( + cx: &PluginContext, + components_ptr: PluginPtr<u32>, + components_len: u32, + query_data_out: PluginPtrMut<QueryData>, +) -> anyhow::Result<()> { + let mut components = Vec::with_capacity(components_len as usize); + for i in 0..components_len { + let ptr = unsafe { components_ptr.add(i as usize) }; + let id = cx.read_pod(ptr)?; + + let component = HostComponent::from_u32(id).context("bad component type")?; + components.push(component); + } + + let game = cx.game_mut(); + let query_data = create_query_data(cx, &game.ecs, &components)?; + cx.write_pod(query_data_out, query_data)?; + + Ok(()) +} + +struct WrittenComponentData { + pointer: PluginPtrMut<u8>, + len: u32, +} + +/// `ComponentVisitor` implementation used to write +/// component data to plugin memory. +struct WriteComponentsVisitor<'a> { + query: &'a DynamicQuery<'a>, + cx: &'a PluginContext, + num_entities: usize, +} + +impl<'a> ComponentVisitor<anyhow::Result<WrittenComponentData>> for WriteComponentsVisitor<'a> { + fn visit<T: Component>(self) -> anyhow::Result<WrittenComponentData> { + let components = self.query.iter_component_slices(TypeId::of::<T>()); + + // Write each component. + // We use a different strategy depending + // on how the component is serialized. + let (buffer, len) = match T::SERIALIZATION_METHOD { + SerializationMethod::Bytemuck => { + // Allocate enough memory to hold all the components. + let layout = Layout::array::<T>(self.num_entities)?; + let buffer = self.cx.bump_allocate(layout)?; + + if size_of::<T>() != 0 { + // Copy the components into the buffer. + let mut byte_index = 0; + for component_slice in components { + for component in component_slice.as_slice::<T>() { + let bytes = component.as_bytes(); + + unsafe { + self.cx.write_bytes(buffer.add(byte_index), bytes)?; + } + + byte_index += bytes.len(); + } + } + } + + (buffer, self.num_entities * size_of::<T>()) + } + SerializationMethod::Bincode => { + // Memory will need to be allocated dynamically, + // but we can approximate a minimum capacity. + let mut bytes = Vec::with_capacity(self.num_entities * size_of::<T>()); + + // Write components into the buffer. + for component_slice in components { + for component in component_slice.as_slice::<T>() { + component.to_bytes(&mut bytes); + } + } + + let buffer = self.cx.bump_allocate_and_write_bytes(&bytes)?; + (buffer, bytes.len()) + } + }; + + Ok(WrittenComponentData { + pointer: buffer, + len: len as u32, + }) + } +} + +fn create_query_data( + cx: &PluginContext, + ecs: &Ecs, + types: &[HostComponent], +) -> anyhow::Result<QueryData> { + let query_types: Vec<TypeId> = types.iter().copied().map(HostComponent::type_id).collect(); + let query = ecs.query_dynamic(DynamicQueryTypes::new(&query_types, &[])); + + let num_entities = query.iter_entities().count(); + if num_entities == 0 { + return Ok(QueryData { + num_entities: 0, + entities_ptr: PointerMut::new(ptr::null_mut()), + component_ptrs: PointerMut::new(ptr::null_mut()), + component_lens: PointerMut::new(ptr::null_mut()), + }); + } + + let component_ptrs = cx.bump_allocate(Layout::array::<PluginPtrMut<u8>>(types.len())?)?; + let component_lens = cx.bump_allocate(Layout::array::<u32>(types.len())?)?; + for (i, &typ) in types.iter().enumerate() { + let data = typ.visit(WriteComponentsVisitor { + query: &query, + cx, + num_entities, + })?; + + unsafe { + cx.write_pod(component_ptrs.cast().add(i), data.pointer)?; + cx.write_pod(component_lens.cast().add(i), data.len)?; + } + } + + let entities_ptr = cx.bump_allocate(Layout::array::<EntityId>(num_entities)?)?; + for (i, entity) in query.iter_entities().enumerate() { + let bits = entity.to_bits(); + unsafe { + cx.write_pod(entities_ptr.cast().add(i), bits)?; + } + } + + Ok(QueryData { + num_entities: num_entities as u64, + entities_ptr: PointerMut::new(entities_ptr.as_native().cast()), + component_ptrs: PointerMut::new(component_ptrs.as_native().cast()), + component_lens: PointerMut::new(component_lens.as_native().cast()), + }) +} diff --git a/feather/plugin-host/src/host_calls/system.rs b/feather/plugin-host/src/host_calls/system.rs new file mode 100644 index 000000000..a1c4c0635 --- /dev/null +++ b/feather/plugin-host/src/host_calls/system.rs @@ -0,0 +1,42 @@ +#![allow(warnings)] + +use std::{cell::RefCell, rc::Rc}; + +use feather_common::Game; +use feather_ecs::{HasResources, SysResult}; +use feather_plugin_host_macros::host_function; + +use crate::{ + context::{PluginContext, PluginPtr, PluginPtrMut}, + PluginId, PluginManager, +}; + +#[host_function] +pub fn register_system( + cx: &PluginContext, + data_ptr: PluginPtrMut<u8>, + name_ptr: PluginPtr<u8>, + name_len: u32, +) -> anyhow::Result<()> { + let name = cx.read_string(name_ptr, name_len)?; + + let game = cx.game_mut(); + game.system_executor + .borrow_mut() + .add_system_with_name(plugin_system(cx.plugin_id(), data_ptr), &name); + + Ok(()) +} + +fn plugin_system(id: PluginId, data_ptr: PluginPtrMut<u8>) -> impl FnMut(&mut Game) -> SysResult { + move |game: &mut Game| { + let plugin_manager = Rc::clone(&*game.resources.get::<Rc<RefCell<PluginManager>>>()?); + let plugin_manager = plugin_manager.borrow(); + let plugin = plugin_manager.plugin(id); + if let Some(plugin) = plugin { + plugin.run_system(game, data_ptr)?; + } + + Ok(()) + } +} diff --git a/feather/plugin-host/src/host_function.rs b/feather/plugin-host/src/host_function.rs new file mode 100644 index 000000000..ed37b011d --- /dev/null +++ b/feather/plugin-host/src/host_function.rs @@ -0,0 +1,23 @@ +use std::{any::Any, marker::PhantomData, sync::Arc}; + +use wasmer::{FromToNativeWasmType, Store, WasmTypeList, WasmerEnv}; + +use crate::context::{PluginContext, PluginPtr, PluginPtrMut}; +use crate::env::PluginEnv; + +/// Signature of a host function. +pub trait WasmHostFunction { + /// Creates a WASM function given the plugin environment. + fn to_wasm_function(self, store: &Store, env: PluginEnv) -> wasmer::Function; +} + +/// Signature of a host function for native. +/// All HostFunction types also implement NativeHostFunction. +/// +/// This trait is implemented by the `#[host_function]` +/// macro attribute. +pub trait NativeHostFunction { + /// Creates a raw function pointer to be included + /// in the plugin's vtable. + fn to_function_pointer(self) -> usize; +} diff --git a/feather/plugin-host/src/lib.rs b/feather/plugin-host/src/lib.rs new file mode 100644 index 000000000..4167b6457 --- /dev/null +++ b/feather/plugin-host/src/lib.rs @@ -0,0 +1,149 @@ +//! Feather's implementation of the [Quill API](https://github.com/feather-rs/quill). +//! +//! Uses [`wasmer`](https://docs.rs/wasmer) to run WebAssembly plugins +//! in a sandbox. + +#![allow(warnings)] // TEMP + +use std::{ + fs, + path::Path, + sync::atomic::{AtomicUsize, Ordering}, +}; + +use ahash::AHashMap; +use anyhow::Context; +use env::PluginEnv; +use feather_common::Game; +use plugin::Plugin; +use quill_plugin_format::{PluginFile, PluginMetadata}; +use vec_arena::Arena; +use wasmer::{ + ChainableNamedResolver, CompilerConfig, ExportError, Features, Function, ImportObject, + Instance, Module, Store, JIT, +}; +use wasmer_wasi::{WasiEnv, WasiState, WasiVersion}; + +mod context; +mod env; +mod host_calls; +mod host_function; +mod plugin; +mod thread_pinned; +mod wasm_ptr_ext; + +/// Features enabled for WASM plugins +const WASM_FEATURES: Features = Features { + threads: true, + reference_types: false, + simd: true, + bulk_memory: true, + multi_value: false, + tail_call: false, + module_linking: false, + multi_memory: false, + memory64: false, + exceptions: true, +}; + +/// Unique ID of a plugin. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct PluginId(usize); + +/// Resource storing all enabled plugins plus the WebAssembly VM. +pub struct PluginManager { + plugins: Arena<Plugin>, + + store: wasmer::Store, +} + +impl Default for PluginManager { + fn default() -> Self { + Self::new() + } +} + +impl PluginManager { + /// Creates a plugin manager with no plugins. + pub fn new() -> Self { + let compiler_config = compiler_config(); + let engine_config = JIT::new(compiler_config).features(WASM_FEATURES); + let engine = engine_config.engine(); + let store = Store::new(&engine); + + Self { + plugins: Arena::new(), + store, + } + } + + /// Loads all plugins in the given directory. + pub fn load_dir(&mut self, game: &mut Game, dir: impl AsRef<Path>) -> anyhow::Result<()> { + let dir = dir.as_ref(); + if !dir.exists() { + return Ok(()); + } + + for entry in std::fs::read_dir(dir)? { + let entry = entry?; + if entry.file_type()?.is_dir() { + continue; + } + + if entry.path().extension() != Some("plugin".as_ref()) { + continue; + } + + let bytes = fs::read(entry.path())?; + self.load(game, &bytes).with_context(|| { + format!("failed to load plugin from {}", entry.path().display()) + })?; + } + + Ok(()) + } + + /// Loads and enables a plugin from the given plugin file bytes. + /// + /// Returns the ID of the loaded plugin. + pub fn load(&mut self, game: &mut Game, file: &[u8]) -> anyhow::Result<PluginId> { + let file = PluginFile::decode(file).context("malformed plugin file")?; + + let id = PluginId(self.plugins.next_vacant()); + let mut plugin = Plugin::load(self, &file, id)?; + + plugin.enable(game).context("failed to enable plugin")?; + + self.plugins.insert(plugin); + + Ok(id) + } + + /// Gets the plugin with the given ID, + /// or `None` if it has been unloaded. + pub fn plugin(&self, id: PluginId) -> Option<&Plugin> { + self.plugins.get(id.0) + } + + /// Mutably gets the plugin with the given ID, + /// or `None` if it has been unloaded. + pub fn plugin_mut(&mut self, id: PluginId) -> Option<&mut Plugin> { + self.plugins.get_mut(id.0) + } +} + +#[cfg(all(feature = "cranelift", not(feature = "llvm")))] +fn compiler_config() -> impl CompilerConfig { + use wasmer::{Cranelift, CraneliftOptLevel}; + let mut cfg = Cranelift::new(); + cfg.opt_level(CraneliftOptLevel::Speed); + cfg +} + +#[cfg(feature = "llvm")] +fn compiler_config() -> impl CompilerConfig { + use wasmer::{LLVMOptLevel, LLVM}; + let mut cfg = LLVM::new(); + cfg.opt_level(LLVMOptLevel::Aggressive); + cfg +} diff --git a/feather/plugin-host/src/plugin.rs b/feather/plugin-host/src/plugin.rs new file mode 100644 index 000000000..9390e3a65 --- /dev/null +++ b/feather/plugin-host/src/plugin.rs @@ -0,0 +1,102 @@ +use std::sync::Arc; + +use anyhow::bail; +use feather_common::Game; +use quill_plugin_format::{PluginFile, PluginMetadata, PluginTarget, Triple}; + +use crate::{ + context::{PluginContext, PluginPtrMut}, + PluginId, PluginManager, +}; + +mod native; +mod wasm; + +pub struct Plugin { + inner: Inner, + context: Arc<PluginContext>, + metadata: PluginMetadata, +} + +impl Plugin { + /// Loads a plugin from the given plugin file. + /// + /// Does not enable the plugin. + pub fn load(manager: &PluginManager, file: &PluginFile, id: PluginId) -> anyhow::Result<Self> { + let plugin_type = match &file.metadata().target { + PluginTarget::Wasm => "WebAssembly", + PluginTarget::Native { .. } => "native", + }; + log::info!( + "Loading {} plugin {} version {}", + plugin_type, + file.metadata().name, + file.metadata().version + ); + + let (inner, context) = match &file.metadata().target { + PluginTarget::Wasm => { + let context = Arc::new(PluginContext::new_wasm(id)); + let plugin = + wasm::WasmPlugin::load(manager, &context, file.module(), file.metadata())?; + (Inner::Wasm(plugin), context) + } + PluginTarget::Native { target_triple } => { + if target_triple != &Triple::host() { + bail!( + "native plguin was built for {}, but this system has target {}", + target_triple, + Triple::host() + ); + } + let plugin = native::NativePlugin::load(file.module())?; + let context = PluginContext::new_native(id); + (Inner::Native(plugin), Arc::new(context)) + } + }; + + Ok(Self { + inner, + context, + metadata: file.metadata().clone(), + }) + } + + /// Enables the plugin. + /// + /// # Panics + /// Panics if called more than once. + pub fn enable(&mut self, game: &mut Game) -> anyhow::Result<()> { + let context = Arc::clone(&self.context); + + self.context.enter(game, || match &self.inner { + Inner::Wasm(w) => w.enable(), + Inner::Native(n) => { + n.enable(context); + Ok(()) + } + })?; + + log::info!("Enabled plugin {} ", self.metadata.name); + Ok(()) + } + + /// Runs a plugin system. + /// + /// `data` must be the data pointer passed + /// to the `register_system` host call. + pub fn run_system(&self, game: &mut Game, data: PluginPtrMut<u8>) -> anyhow::Result<()> { + self.context.enter(game, || match &self.inner { + Inner::Wasm(w) => w.run_system(data), + Inner::Native(n) => { + n.run_system(data); + Ok(()) + } + }) + } +} + +enum Inner { + Wasm(wasm::WasmPlugin), + Native(native::NativePlugin), +} diff --git a/feather/plugin-host/src/plugin/native.rs b/feather/plugin-host/src/plugin/native.rs new file mode 100644 index 000000000..48601ffe1 --- /dev/null +++ b/feather/plugin-host/src/plugin/native.rs @@ -0,0 +1,92 @@ +use std::{io::Write, sync::Arc}; + +use anyhow::Context; +use libloading::Library; +use tempfile::{NamedTempFile, TempPath}; + +use crate::context::{PluginContext, PluginPtrMut}; + +/// A native plugin loaded from a shared library +pub struct NativePlugin { + /// The tempfile containing the shared library. + tempfile: TempPath, + + /// The plugin's shared library. + library: Library, + + /// The plugin's exported quill_setup function. + /// + /// Parameters: + /// 1. Host context pointer + /// 2. Pointer to bincode-encoded vtable + /// 3. Length of bincode-encoded vtable + enable: unsafe extern "C" fn(*const u8, *const u8, usize), + + /// The plugin's exported quill_run_system function. + /// + /// Parameters: + /// 1. Plugin data pointer for this system + run_system: unsafe extern "C" fn(*mut u8), +} + +impl NativePlugin { + pub fn load(module: &[u8]) -> anyhow::Result<Self> { + // Libraries have to be loaded from files, so + // we'll create a tempfile containing the module bytes. + let mut tempfile = NamedTempFile::new()?; + tempfile.write_all(module)?; + tempfile.flush()?; + let path = tempfile.into_temp_path(); + + // SAFETY: Library::new() is unsafe because + // the loaded module can execute arbitrary + // code. Since native plugins are trusted, + // this is sound. + let library = unsafe { Library::new(&path)? }; + + // SAFETY: these functions will not be accessed after the plugin is unloaded. + let enable = unsafe { + *library + .get("quill_setup".as_bytes()) + .context("plugin is missing quill_setup export")? + }; + let run_system = unsafe { + *library + .get("quill_run_system".as_bytes()) + .context("plugin is missing quill_run_system export")? + }; + + Ok(Self { + tempfile: path, + library, + enable, + run_system, + }) + } + + pub fn enable(&self, context: Arc<PluginContext>) { + let vtable = self.generate_vtable(); + let context_ptr = Arc::as_ptr(&context); + // Ensure context stays alive + std::mem::forget(context); + + // SAFETY: we assume the plugin is sound. + unsafe { + (self.enable)( + context_ptr.cast::<u8>(), + vtable.as_ptr(), + vtable.len() as usize, + ) + } + } + + fn generate_vtable(&self) -> Vec<u8> { + let vtable = crate::host_calls::generate_vtable(); + bincode::serialize(&vtable).expect("can't serialize vtable") + } + + pub fn run_system(&self, data: PluginPtrMut<u8>) { + // SAFETY: we assume the plugin is sound. + unsafe { (self.run_system)(data.as_native()) } + } +} diff --git a/feather/plugin-host/src/plugin/wasm.rs b/feather/plugin-host/src/plugin/wasm.rs new file mode 100644 index 000000000..73d839e9d --- /dev/null +++ b/feather/plugin-host/src/plugin/wasm.rs @@ -0,0 +1,77 @@ +use std::sync::Arc; + +use quill_plugin_format::PluginMetadata; +use wasmer::{ + ChainableNamedResolver, Features, Function, ImportObject, Instance, Module, NativeFunc, Store, +}; +use wasmer_wasi::{WasiEnv, WasiState, WasiVersion}; + +use crate::{ + context::{PluginContext, PluginPtr, PluginPtrMut}, + env::PluginEnv, + PluginManager, +}; + +pub struct WasmPlugin { + /// The WebAssembly instancing containing + /// the plugin. + instance: Instance, + + /// Exported function to enable the plugin. + enable: Function, + + /// Exported function to run a system given its data pointer. + run_system: NativeFunc<u32>, +} + +impl WasmPlugin { + pub fn load( + manager: &PluginManager, + cx: &Arc<PluginContext>, + module: &[u8], + metadata: &PluginMetadata, + ) -> anyhow::Result<Self> { + let env = PluginEnv { + context: Arc::clone(cx), + }; + let quill_imports = crate::host_calls::generate_import_object(&manager.store, &env); + let wasi_imports = generate_wasi_import_object(&manager.store, &metadata.identifier)?; + let imports = quill_imports.chain_back(wasi_imports); + + let module = Module::new(&manager.store, module)?; + let instance = Instance::new(&module, &imports)?; + + let run_system = instance + .exports + .get_function("quill_run_system")? + .native()? + .clone(); + let enable = instance.exports.get_function("quill_setup")?.clone(); + + Ok(Self { + instance, + run_system, + enable, + }) + } + + pub fn enable(&self) -> anyhow::Result<()> { + self.enable.call(&[])?; + Ok(()) + } + + pub fn run_system(&self, data_ptr: PluginPtrMut<u8>) -> anyhow::Result<()> { + self.run_system.call(data_ptr.ptr as u32)?; + Ok(()) + } +} + +fn generate_wasi_import_object(store: &Store, plugin_name: &str) -> anyhow::Result<ImportObject> { + let state = WasiState::new(plugin_name).build()?; + let env = WasiEnv::new(state); + Ok(wasmer_wasi::generate_import_object_from_env( + store, + env, + WasiVersion::Latest, + )) +} diff --git a/feather/plugin-host/src/thread_pinned.rs b/feather/plugin-host/src/thread_pinned.rs new file mode 100644 index 000000000..dccc72c47 --- /dev/null +++ b/feather/plugin-host/src/thread_pinned.rs @@ -0,0 +1,45 @@ +use std::{ + cell::{Ref, RefCell, RefMut}, + thread::{self, ThreadId}, +}; + +/// Wraps a [`RefCell`] but implements `Send` and `Sync`. +/// +/// The value can only be borrowed on the thread it was created +/// on; this is enforced at runtime. In other words, access to +/// the value is pinned to the main thread. +pub struct ThreadPinned<T> { + cell: RefCell<T>, + pinned_to: ThreadId, +} + +impl<T> ThreadPinned<T> { + pub fn new(value: T) -> Self { + Self { + cell: RefCell::new(value), + pinned_to: thread::current().id(), + } + } + + #[allow(unused)] + pub fn borrow(&self) -> Ref<T> { + self.assert_thread(); + self.cell.borrow() + } + + pub fn borrow_mut(&self) -> RefMut<T> { + self.assert_thread(); + self.cell.borrow_mut() + } + + fn assert_thread(&self) { + assert_eq!( + thread::current().id(), + self.pinned_to, + "can only borrow value on the main thread" + ); + } +} + +unsafe impl<T> Send for ThreadPinned<T> {} +unsafe impl<T> Sync for ThreadPinned<T> {} diff --git a/feather/plugin-host/src/wasm_ptr_ext.rs b/feather/plugin-host/src/wasm_ptr_ext.rs new file mode 100644 index 000000000..db0184d1c --- /dev/null +++ b/feather/plugin-host/src/wasm_ptr_ext.rs @@ -0,0 +1,29 @@ +use wasmer::{Array, WasmPtr}; + +pub trait WasmPtrExt { + fn add(self, offset: usize) -> Self; +} + +impl<T, Ty> WasmPtrExt for WasmPtr<T, Ty> +where + T: Copy, +{ + fn add(self, offset: usize) -> Self { + WasmPtr::new(self.offset() + offset as u32) + } +} + +pub trait WasmPtrIntoArray<T> { + fn array(self) -> WasmPtr<T, Array> + where + T: Copy; +} + +impl<T> WasmPtrIntoArray<T> for WasmPtr<T> +where + T: Copy, +{ + fn array(self) -> WasmPtr<T, Array> { + WasmPtr::new(self.offset()) + } +} diff --git a/feather/protocol/Cargo.toml b/feather/protocol/Cargo.toml new file mode 100644 index 000000000..d919d83b4 --- /dev/null +++ b/feather/protocol/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "feather-protocol" +version = "0.1.0" +authors = [ "caelunshun <caelunshun@gmail.com>" ] +edition = "2018" + +[dependencies] +aes = "0.7" +anyhow = "1" +base = { path = "../base", package = "feather-base" } +blocks = { path = "../blocks", package = "feather-blocks" } +bytemuck = "1" +byteorder = "1" +bytes = "0.5" +cfb8 = "0.7" +flate2 = "1" + +hematite-nbt = { git = "https://github.com/PistonDevelopers/hematite_nbt" } +num-traits = "0.2" +parking_lot = "0.11" # Arc<RwLock<Chunk>> compat +quill-common = { path = "../../quill/common" } +serde = "1" +thiserror = "1" +uuid = "0.8" +libcraft-core = { path = "../../libcraft/core" } +libcraft-items = { path = "../../libcraft/items" } diff --git a/feather/protocol/src/codec.rs b/feather/protocol/src/codec.rs new file mode 100644 index 000000000..d38217eb3 --- /dev/null +++ b/feather/protocol/src/codec.rs @@ -0,0 +1,191 @@ +use crate::{io::VarInt, ProtocolVersion, Readable, Writeable}; +use aes::Aes128; +use bytes::BytesMut; +use cfb8::{ + cipher::{AsyncStreamCipher, NewCipher}, + Cfb8, +}; +use flate2::{ + bufread::{ZlibDecoder, ZlibEncoder}, + Compression, +}; +use std::io::{Cursor, Read}; + +type AesCfb8 = Cfb8<Aes128>; +pub type CompressionThreshold = usize; + +/// An encryption key for use with AES-CFB8. +pub type CryptKey = [u8; 16]; + +/// State to serialize and deserialize packets from a byte stream. +#[derive(Default)] +pub struct MinecraftCodec { + /// If encryption is enabled, then this is the cryptor state. + cryptor: Option<AesCfb8>, + crypt_key: Option<CryptKey>, + /// If compression is enabled, then this is the compression threshold. + compression: Option<CompressionThreshold>, + + /// A buffer of received bytes. + received_buf: BytesMut, + /// Auxilary buffer. + staging_buf: Vec<u8>, + /// Another auxilary buffer. + compression_target: Vec<u8>, +} + +impl MinecraftCodec { + pub fn new() -> Self { + Self::default() + } + + /// Enables encryption with the provided key. + pub fn enable_encryption(&mut self, key: CryptKey) { + // yes, Mojang uses the same nonce for each packet. don't ask me why. + self.cryptor = Some(AesCfb8::new_from_slices(&key, &key).expect("key size is invalid")); + self.crypt_key = Some(key); + } + + /// Enables compression with the provided compression threshold. + pub fn enable_compression(&mut self, threshold: CompressionThreshold) { + self.compression = Some(threshold); + } + + /// Gets another `MinecraftCodec` with the same compression and encryption + /// parameters. + pub fn clone_with_settings(&self) -> MinecraftCodec { + MinecraftCodec { + cryptor: self + .crypt_key + .map(|key| AesCfb8::new_from_slices(&key, &key).expect("key size is invalid")), + crypt_key: self.crypt_key, + compression: self.compression, + received_buf: BytesMut::new(), + staging_buf: Vec::new(), + compression_target: Vec::new(), + } + } + + /// Writes a packet into the provided writer. + pub fn encode(&mut self, packet: &impl Writeable, output: &mut Vec<u8>) -> anyhow::Result<()> { + packet.write(&mut self.staging_buf, ProtocolVersion::V1_16_2)?; + + if let Some(threshold) = self.compression { + self.encode_compressed(output, threshold)?; + } else { + self.encode_uncompressed(output)?; + } + + if let Some(cryptor) = &mut self.cryptor { + cryptor.encrypt(output); + } + + self.staging_buf.clear(); + + Ok(()) + } + + fn encode_compressed( + &mut self, + output: &mut Vec<u8>, + threshold: CompressionThreshold, + ) -> anyhow::Result<()> { + let (data_length, data) = if self.staging_buf.len() >= threshold { + self.data_compressed() + } else { + self.data_uncompressed() + }; + + const MAX_VAR_INT_LENGTH: usize = 5; + let mut buf = [0u8; MAX_VAR_INT_LENGTH]; + let mut data_length_bytes = Cursor::new(&mut buf[..]); + VarInt(data_length as i32) + .write_to(&mut data_length_bytes) + .unwrap(); + + let packet_length = data_length_bytes.position() as usize + data.len(); + VarInt(packet_length as i32).write(output, ProtocolVersion::V1_16_2)?; + VarInt(data_length as i32).write(output, ProtocolVersion::V1_16_2)?; + output.extend_from_slice(data); + + self.compression_target.clear(); + + Ok(()) + } + + fn data_compressed(&mut self) -> (usize, &[u8]) { + let mut encoder = ZlibEncoder::new(self.staging_buf.as_slice(), Compression::default()); + encoder + .read_to_end(&mut self.compression_target) + .expect("compression failed"); + (self.staging_buf.len(), self.compression_target.as_slice()) + } + + fn data_uncompressed(&mut self) -> (usize, &[u8]) { + (0, self.staging_buf.as_slice()) + } + + fn encode_uncompressed(&mut self, output: &mut Vec<u8>) -> anyhow::Result<()> { + // TODO: we should probably be able to determine the length without writing the packet, + // which could remove an unnecessary copy. + let length = self.staging_buf.len() as i32; + VarInt(length).write(output, ProtocolVersion::V1_16_2)?; + output.extend_from_slice(&self.staging_buf); + + Ok(()) + } + + /// Accepts newly received bytes. + pub fn accept(&mut self, bytes: &[u8]) { + let start_index = self.received_buf.len(); + self.received_buf.extend(bytes); + + if let Some(cryptor) = &mut self.cryptor { + // Decrypt the new data (but not the whole received buffer, + // since old data was already decrypted) + cryptor.decrypt(&mut self.received_buf[start_index..]); + } + } + + /// Gets the next packet that was received, if any. + pub fn next_packet<T>(&mut self) -> anyhow::Result<Option<T>> + where + T: Readable, + { + let mut cursor = Cursor::new(&self.received_buf[..]); + let packet = if let Ok(length) = VarInt::read(&mut cursor, ProtocolVersion::V1_16_2) { + let length_field_length = cursor.position() as usize; + + if self.received_buf.len() - length_field_length >= length.0 as usize { + cursor = Cursor::new( + &self.received_buf + [length_field_length..length_field_length + length.0 as usize], + ); + + if self.compression.is_some() { + let data_length = VarInt::read(&mut cursor, ProtocolVersion::V1_16_2)?; + if data_length.0 != 0 { + let mut decoder = + ZlibDecoder::new(&cursor.get_ref()[cursor.position() as usize..]); + decoder.read_to_end(&mut self.compression_target)?; + cursor = Cursor::new(&self.compression_target); + } + } + + let packet = T::read(&mut cursor, ProtocolVersion::V1_16_2)?; + + let bytes_read = length.0 as usize + length_field_length; + self.received_buf = self.received_buf.split_off(bytes_read); + + self.compression_target.clear(); + Some(packet) + } else { + None + } + } else { + None + }; + + Ok(packet) + } +} diff --git a/feather/protocol/src/io.rs b/feather/protocol/src/io.rs new file mode 100644 index 000000000..4c9a51be6 --- /dev/null +++ b/feather/protocol/src/io.rs @@ -0,0 +1,917 @@ +//! Traits for reading/writing Minecraft-encoded values. + +use crate::{ProtocolVersion, Slot}; +use anyhow::{anyhow, bail, Context}; +use base::{ + anvil::entity::ItemNbt, metadata::MetaEntry, BlockId, BlockPosition, Direction, EntityMetadata, + Gamemode, Item, ItemStackBuilder, ValidBlockPosition, +}; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use libcraft_items::InventorySlot::*; +use num_traits::{FromPrimitive, ToPrimitive}; +use quill_common::components::PreviousGamemode; +use serde::{de::DeserializeOwned, Serialize}; +use std::io::ErrorKind; +use std::{ + borrow::Cow, + collections::BTreeMap, + convert::{TryFrom, TryInto}, + io::{self, Cursor, Read, Write}, + iter, + marker::PhantomData, + num::TryFromIntError, +}; +use thiserror::Error; +use uuid::Uuid; + +/// Trait implemented for types which can be read +/// from a buffer. +pub trait Readable { + /// Reads this type from the given buffer. + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized; +} + +/// Trait implemented for types which can be written +/// to a buffer. +pub trait Writeable: Sized { + /// Writes this value to the given buffer. + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()>; +} + +impl<'a, T> Writeable for &'a T +where + T: Writeable, +{ + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + T::write(*self, buffer, version)?; + Ok(()) + } +} + +/// Error when reading a value. +#[derive(Debug, Error)] +pub enum Error { + #[error("unexpected end of input: failed to read value of type `{0}`")] + UnexpectedEof(&'static str), +} + +macro_rules! integer_impl { + ($($int:ty, $read_fn:tt, $write_fn:tt),* $(,)?) => { + $( + impl Readable for $int { + fn read(buffer: &mut Cursor<&[u8]>, _version: ProtocolVersion) -> anyhow::Result<Self> { + buffer.$read_fn::<BigEndian>().map_err(anyhow::Error::from) + } + } + + impl Writeable for $int { + fn write(&self, buffer: &mut Vec<u8>, _version: ProtocolVersion) -> anyhow::Result<()> { + buffer.$write_fn::<BigEndian>(*self)?; + Ok(()) + } + } + )* + } +} + +integer_impl! { + u16, read_u16, write_u16, + u32, read_u32, write_u32, + u64, read_u64, write_u64, + + i16, read_i16, write_i16, + i32, read_i32, write_i32, + i64, read_i64, write_i64, + + f32, read_f32, write_f32, + f64, read_f64, write_f64, +} + +impl Readable for u8 { + fn read(buffer: &mut Cursor<&[u8]>, _version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + buffer.read_u8().map_err(anyhow::Error::from) + } +} + +impl Writeable for u8 { + fn write(&self, buffer: &mut Vec<u8>, _version: ProtocolVersion) -> anyhow::Result<()> { + buffer.write_u8(*self)?; + Ok(()) + } +} + +impl Readable for i8 { + fn read(buffer: &mut Cursor<&[u8]>, _version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + buffer.read_i8().map_err(anyhow::Error::from) + } +} + +impl Writeable for i8 { + fn write(&self, buffer: &mut Vec<u8>, _version: ProtocolVersion) -> anyhow::Result<()> { + buffer.write_i8(*self)?; + Ok(()) + } +} + +impl<T> Readable for Option<T> +where + T: Readable, +{ + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + // Assume boolean prefix. + let present = bool::read(buffer, version)?; + + if present { + Ok(Some(T::read(buffer, version)?)) + } else { + Ok(None) + } + } +} + +impl<T> Writeable for Option<T> +where + T: Writeable, +{ + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + let present = self.is_some(); + present.write(buffer, version)?; + + if let Some(value) = self { + value.write(buffer, version)?; + } + + Ok(()) + } +} + +/// A variable-length integer as defined by the Minecraft protocol. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct VarInt(pub i32); + +impl Readable for VarInt { + fn read(buffer: &mut Cursor<&[u8]>, _version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + Self::read_from(buffer).map_err(Into::into) + } +} + +impl TryFrom<VarInt> for usize { + type Error = TryFromIntError; + fn try_from(value: VarInt) -> Result<Self, Self::Error> { + value.0.try_into() + } +} + +impl From<usize> for VarInt { + fn from(x: usize) -> Self { + VarInt(x as i32) + } +} + +impl From<VarInt> for i32 { + fn from(x: VarInt) -> Self { + x.0 + } +} + +impl From<i32> for VarInt { + fn from(x: i32) -> Self { + VarInt(x) + } +} + +impl VarInt { + pub fn write_to(&self, mut writer: impl Write) -> io::Result<usize> { + let mut x = self.0 as u32; + let mut i = 0; + loop { + let mut temp = (x & 0b0111_1111) as u8; + x >>= 7; + if x != 0 { + temp |= 0b1000_0000; + } + + writer.write_all(&[temp])?; + + i += 1; + if x == 0 { + break; + } + } + Ok(i) + } + pub fn read_from(mut reader: impl Read) -> io::Result<Self> { + let mut num_read = 0; + let mut result = 0; + + loop { + let read = reader.read_u8()?; + let value = i32::from(read & 0b0111_1111); + result |= value.overflowing_shl(7 * num_read).0; + + num_read += 1; + + if num_read > 5 { + return Err(io::Error::new( + ErrorKind::InvalidData, + "VarInt too long (max length: 5)", + )); + } + if read & 0b1000_0000 == 0 { + break; + } + } + Ok(VarInt(result)) + } +} + +impl Writeable for VarInt { + fn write(&self, buffer: &mut Vec<u8>, _version: ProtocolVersion) -> anyhow::Result<()> { + self.write_to(buffer).expect("write to Vec failed"); + Ok(()) + } +} + +/// A variable-length integer as defined by the Minecraft protocol. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct VarLong(pub i64); + +impl Readable for VarLong { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let mut num_read = 0; + let mut result = 0; + + loop { + let read = u8::read(buffer, version)?; + let value = i64::from(read & 0b0111_1111); + result |= value.overflowing_shl(7 * num_read).0; + + num_read += 1; + + if num_read > 10 { + bail!( + "VarInt too long (max length: 5, value read so far: {})", + result + ); + } + if read & 0b1000_0000 == 0 { + break; + } + } + Ok(VarLong(result)) + } +} + +impl From<VarLong> for i64 { + fn from(x: VarLong) -> Self { + x.0 + } +} + +impl From<i64> for VarLong { + fn from(x: i64) -> Self { + VarLong(x) + } +} + +impl Writeable for VarLong { + fn write(&self, buffer: &mut Vec<u8>, _version: ProtocolVersion) -> anyhow::Result<()> { + let mut x = self.0 as u64; + loop { + let mut temp = (x & 0b0111_1111) as u8; + x >>= 7; + if x != 0 { + temp |= 0b1000_0000; + } + + buffer.write_u8(temp).unwrap(); + + if x == 0 { + break; + } + } + + Ok(()) + } +} + +impl Readable for String { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + // Length is encoded as VarInt. + // Following `length` bytes are the UTF8-encoded + // string. + + let length = VarInt::read(buffer, version) + .context("failed to read string length")? + .0 as usize; + + // TODO: support custom length limits + // Current max length is max value of a signed 16-bit int. + let max_length = std::i16::MAX as usize; + if length > max_length { + bail!( + "string length {} exceeds maximum allowed length of {}", + length, + max_length + ); + } + + // Read string into buffer. + let mut temp = vec![0u8; length]; + buffer + .read_exact(&mut temp) + .map_err(|_| Error::UnexpectedEof("String"))?; + let s = std::str::from_utf8(&temp).context("string contained invalid UTF8")?; + + Ok(s.to_owned()) + } +} + +impl Writeable for String { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + VarInt(self.len() as i32).write(buffer, version)?; + buffer.extend_from_slice(self.as_bytes()); + + Ok(()) + } +} + +impl Readable for bool { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let x = u8::read(buffer, version)?; + + if x == 0 { + Ok(false) + } else if x == 1 { + Ok(true) + } else { + Err(anyhow::anyhow!("invalid boolean tag {}", x)) + } + } +} + +impl Writeable for bool { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + let x = if *self { 1u8 } else { 0 }; + x.write(buffer, version)?; + + Ok(()) + } +} + +pub const MAX_LENGTH: usize = 1024 * 1024; // 2^20 elements + +/// Reads and writes an array of inner `Writeable`s. +/// The array is prefixed with a `VarInt` length. +/// +/// This will reject arrays of lengths larger than MAX_LENGTH. +pub struct LengthPrefixedVec<'a, P, T>(pub Cow<'a, [T]>, PhantomData<P>) +where + [T]: ToOwned<Owned = Vec<T>>; + +impl<'a, P, T> Readable for LengthPrefixedVec<'a, P, T> +where + T: Readable, + [T]: ToOwned<Owned = Vec<T>>, + P: TryInto<usize> + Readable, + P::Error: std::error::Error + Send + Sync + 'static, +{ + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let length: usize = P::read(buffer, version)?.try_into()?; + + if length > MAX_LENGTH { + bail!("array length too large ({} > {})", length, MAX_LENGTH); + } + + let vec = iter::repeat_with(|| T::read(buffer, version)) + .take(length) + .collect::<anyhow::Result<Vec<T>>>()?; + Ok(Self(Cow::Owned(vec), PhantomData)) + } +} + +impl<'a, P, T> Writeable for LengthPrefixedVec<'a, P, T> +where + T: Writeable, + [T]: ToOwned<Owned = Vec<T>>, + P: TryFrom<usize> + Writeable, + P::Error: std::error::Error + Send + Sync + 'static, +{ + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + P::try_from(self.0.len())?.write(buffer, version)?; + self.0 + .iter() + .for_each(|item| item.write(buffer, version).expect("failed to write to vec")); + + Ok(()) + } +} + +impl<'a, P, T> From<LengthPrefixedVec<'a, P, T>> for Vec<T> +where + [T]: ToOwned<Owned = Vec<T>>, +{ + fn from(x: LengthPrefixedVec<'a, P, T>) -> Self { + x.0.into_owned() + } +} + +impl<'a, P, T> From<&'a [T]> for LengthPrefixedVec<'a, P, T> +where + [T]: ToOwned<Owned = Vec<T>>, +{ + fn from(slice: &'a [T]) -> Self { + Self(Cow::Borrowed(slice), PhantomData) + } +} + +impl<'a, P, T> From<Vec<T>> for LengthPrefixedVec<'a, P, T> +where + [T]: ToOwned<Owned = Vec<T>>, +{ + fn from(vec: Vec<T>) -> Self { + Self(Cow::Owned(vec), PhantomData) + } +} + +pub type VarIntPrefixedVec<'a, T> = LengthPrefixedVec<'a, VarInt, T>; +pub type ShortPrefixedVec<'a, T> = LengthPrefixedVec<'a, u16, T>; + +/// A vector of bytes which consumes all remaining bytes in this packet. +/// This is used by the plugin messaging packets, for one. +pub struct LengthInferredVecU8<'a>(pub Cow<'a, [u8]>); + +impl<'a> Readable for LengthInferredVecU8<'a> { + fn read(buffer: &mut Cursor<&[u8]>, _version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let mut vec = Vec::new(); + buffer.read_to_end(&mut vec)?; + Ok(LengthInferredVecU8(Cow::Owned(vec))) + } +} + +impl<'a> Writeable for LengthInferredVecU8<'a> { + fn write(&self, buffer: &mut Vec<u8>, _version: ProtocolVersion) -> anyhow::Result<()> { + buffer.extend_from_slice(&*self.0); + Ok(()) + } +} + +impl<'a> From<&'a [u8]> for LengthInferredVecU8<'a> { + fn from(slice: &'a [u8]) -> Self { + LengthInferredVecU8(Cow::Borrowed(slice)) + } +} + +impl<'a> From<LengthInferredVecU8<'a>> for Vec<u8> { + fn from(x: LengthInferredVecU8<'a>) -> Self { + x.0.into_owned() + } +} + +/// Wrapper over an arbitrary type that implements `Deserialize` and `Serialize`. +/// +/// The value will be written to a packet as NBT data. +#[derive(Debug, Clone)] +pub struct Nbt<T>(pub T); + +impl<T> Readable for Nbt<T> +where + T: DeserializeOwned, +{ + fn read(buffer: &mut Cursor<&[u8]>, _version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + nbt::from_reader(buffer) + .map_err(anyhow::Error::from) + .map(Nbt) + } +} + +impl<T> Writeable for Nbt<T> +where + T: Serialize, +{ + fn write(&self, buffer: &mut Vec<u8>, _version: ProtocolVersion) -> anyhow::Result<()> { + nbt::to_writer(buffer, &self.0, None).unwrap_or_else(|e| { + panic!( + "could not serialize struct of type '{}' to NBT: {}", + std::any::type_name::<T>(), + e + ) + }); + + Ok(()) + } +} + +impl<T> From<T> for Nbt<T> { + fn from(t: T) -> Self { + Nbt(t) + } +} + +impl Readable for Slot { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let present = bool::read(buffer, version)?; + + if present { + let item_id = VarInt::read(buffer, version)?.0; + let count = u8::read(buffer, version)? as u32; + + // Read NBT, but make sure to reset the buffer position if it's missing. + let position = buffer.position(); + let tags: Option<ItemNbt> = Nbt::read(buffer, version).ok().map(|nbt| nbt.0); + if tags.is_none() { + buffer.set_position(position + 1); // account for TAG_End, which is 1 byte + } + + let item = Item::from_id(item_id.try_into()?) + .ok_or_else(|| anyhow!("unknown item ID {}", item_id))?; + + // Todo fix: Panics if count is zero + Ok(Filled( + ItemStackBuilder::with_item(item) + .count(count) + .apply_damage(tags.and_then(|t| t.damage)) + .into(), + )) + } else { + Ok(Empty) + } + } +} + +impl Writeable for Slot { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + self.is_filled().write(buffer, version)?; + + if let Filled(stack) = self { + VarInt(stack.item().id() as i32).write(buffer, version)?; + (stack.count() as u8).write(buffer, version)?; + + let tags: ItemNbt = stack.into(); + if tags != ItemNbt::default() { + Nbt(tags).write(buffer, version)?; + } else { + 0u8.write(buffer, version)?; // TAG_End + } + } + + Ok(()) + } +} + +impl Readable for EntityMetadata { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let mut values = BTreeMap::new(); + + loop { + let index = u8::read(buffer, version)?; + + if index == 0xFF { + break; + } + + let entry = read_meta_entry(buffer, version)?; + values.insert(index, entry); + } + + Ok(EntityMetadata { values }) + } +} + +fn read_meta_entry( + buffer: &mut Cursor<&[u8]>, + version: ProtocolVersion, +) -> anyhow::Result<MetaEntry> { + let id = VarInt::read(buffer, version)?.0; + + Ok(match id { + 0 => MetaEntry::Byte(i8::read(buffer, version)?), + 1 => MetaEntry::VarInt(VarInt::read(buffer, version)?.0), + 2 => MetaEntry::Float(f32::read(buffer, version)?), + 3 => MetaEntry::String(String::read(buffer, version)?), + 4 => MetaEntry::Chat(String::read(buffer, version)?), + 5 => MetaEntry::OptChat(if bool::read(buffer, version)? { + Some(String::read(buffer, version)?) + } else { + None + }), + 6 => MetaEntry::Slot(Slot::read(buffer, version)?), + 7 => MetaEntry::Boolean(bool::read(buffer, version)?), + 8 => MetaEntry::Rotation( + f32::read(buffer, version)?, + f32::read(buffer, version)?, + f32::read(buffer, version)?, + ), + 9 => MetaEntry::Position(ValidBlockPosition::read(buffer, version)?), + 10 => MetaEntry::OptPosition(if bool::read(buffer, version)? { + Some(ValidBlockPosition::read(buffer, version)?) + } else { + None + }), + 11 => MetaEntry::Direction( + Direction::from_i32(VarInt::read(buffer, version)?.0) + .ok_or_else(|| anyhow!("invalid direction ID"))?, + ), + 12 => MetaEntry::OptUuid(if bool::read(buffer, version)? { + Some(Uuid::read(buffer, version)?) + } else { + None + }), + 13 => MetaEntry::OptBlockId({ + let id = VarInt::read(buffer, version)?.0; + if id == 0 { + None + } else { + Some(id) + } + }), + 14 => MetaEntry::Nbt(Nbt::read(buffer, version)?.0), + 15 => MetaEntry::Particle, + 16 => MetaEntry::VillagerData( + VarInt::read(buffer, version)?.0, + VarInt::read(buffer, version)?.0, + VarInt::read(buffer, version)?.0, + ), + 17 => MetaEntry::OptVarInt({ + let varint = VarInt::read(buffer, version)?.0; + if varint == 0 { + None + } else { + Some(varint - 1) + } + }), + 18 => MetaEntry::Pose(VarInt::read(buffer, version)?.0), + x => bail!("invalid entity metadata entry ID {}", x), + }) +} + +impl Writeable for EntityMetadata { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + for (index, entry) in self.iter() { + index.write(buffer, version)?; + VarInt(entry.id()).write(buffer, version)?; + write_meta_entry(entry, buffer, version)?; + } + + // End of metadata + buffer.push(0xFF); + Ok(()) + } +} + +fn write_meta_entry( + entry: &MetaEntry, + buffer: &mut Vec<u8>, + version: ProtocolVersion, +) -> anyhow::Result<()> { + match entry { + MetaEntry::Byte(x) => x.write(buffer, version)?, + MetaEntry::VarInt(x) => { + VarInt(*x).write(buffer, version)?; + } + MetaEntry::Float(x) => x.write(buffer, version)?, + MetaEntry::String(x) => x.write(buffer, version)?, + MetaEntry::Chat(x) => x.write(buffer, version)?, + MetaEntry::OptChat(ox) => { + if let Some(x) = ox { + true.write(buffer, version)?; + x.write(buffer, version)?; + } else { + false.write(buffer, version)?; + } + } + MetaEntry::Slot(slot) => slot.write(buffer, version)?, + MetaEntry::Boolean(x) => x.write(buffer, version)?, + MetaEntry::Rotation(x, y, z) => { + x.write(buffer, version)?; + y.write(buffer, version)?; + z.write(buffer, version)?; + } + MetaEntry::Position(x) => x.write(buffer, version)?, + MetaEntry::OptPosition(ox) => { + if let Some(x) = ox { + true.write(buffer, version)?; + x.write(buffer, version)?; + } else { + false.write(buffer, version)?; + } + } + MetaEntry::Direction(x) => VarInt(x.to_i32().unwrap()).write(buffer, version)?, + MetaEntry::OptUuid(ox) => { + if let Some(x) = ox { + true.write(buffer, version)?; + x.write(buffer, version)?; + } else { + false.write(buffer, version)?; + } + } + MetaEntry::OptBlockId(ox) => { + if let Some(x) = ox { + VarInt(*x).write(buffer, version)?; + } else { + VarInt(0).write(buffer, version)?; // No value implies air + } + } + MetaEntry::Nbt(val) => Nbt(val).write(buffer, version)?, + MetaEntry::Particle => unimplemented!("entity metadata with particles"), + MetaEntry::VillagerData(villager_type, villager_profession, level) => { + VarInt(*villager_type).write(buffer, version)?; + VarInt(*villager_profession).write(buffer, version)?; + VarInt(*level).write(buffer, version)?; + } + MetaEntry::OptVarInt(ox) => { + if let Some(x) = ox { + true.write(buffer, version)?; + x.write(buffer, version)?; + } else { + false.write(buffer, version)?; + } + } + MetaEntry::Pose(x) => VarInt(x.to_i32().unwrap()).write(buffer, version)?, + } + + Ok(()) +} + +impl Readable for Uuid { + fn read(buffer: &mut Cursor<&[u8]>, _version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let mut bytes = uuid::Bytes::default(); + buffer.read_exact(&mut bytes)?; + + Ok(Uuid::from_bytes(bytes)) + } +} + +impl Writeable for Uuid { + fn write(&self, buffer: &mut Vec<u8>, _version: ProtocolVersion) -> anyhow::Result<()> { + buffer.extend_from_slice(self.as_bytes()); + Ok(()) + } +} + +impl Readable for ValidBlockPosition { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let val = i64::read(buffer, version)?; + + let x = (val >> 38) as i32; + let y = (val & 0xFFF) as i32; + let z = (val << 26 >> 38) as i32; + + Ok(BlockPosition { x, y, z }.try_into()?) + } +} + +impl Writeable for ValidBlockPosition { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + let val = ((self.x() as u64 & 0x3FFFFFF) << 38) + | ((self.z() as u64 & 0x3FFFFFF) << 12) + | (self.y() as u64 & 0xFFF); + val.write(buffer, version)?; + + Ok(()) + } +} + +/// An angle written in stops, where each stop +/// is 1/256th of a full turn. +/// +/// This type converts degrees to stops. +#[derive(Copy, Clone, Debug)] +pub struct Angle(pub f32); + +impl From<Angle> for f32 { + fn from(angle: Angle) -> Self { + angle.0 + } +} + +impl Readable for Angle { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let val = u8::read(buffer, version)?; + Ok(Angle((val as f32 / 256.0) * 360.0)) + } +} + +impl Writeable for Angle { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + let temp = (256.0 / 360.0) * (self.0 % 360.0); + // Wrap negative values 'x' in the range [-256.0 to 0] to the + // correct angle in the range [0 to 256.0 ) by changing 'x' to + // x = 256.0 - x + let val = ((temp + 256.0) % 256.0) as u8; + val.write(buffer, version)?; + + Ok(()) + } +} + +impl Readable for BlockId { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let id = VarInt::read(buffer, version)?.0; + + let block = BlockId::from_vanilla_id(id.try_into()?); + Ok(block) + } +} + +impl Writeable for BlockId { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + VarInt(self.vanilla_id().into()).write(buffer, version)?; + Ok(()) + } +} + +impl Readable for Gamemode { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let id = u8::read(buffer, version)?; + Ok(match id { + 0 => Gamemode::Survival, + 1 => Gamemode::Creative, + 2 => Gamemode::Adventure, + 3 => Gamemode::Spectator, + id => bail!("invalid gamemode ID {}", id), + }) + } +} + +impl Writeable for Gamemode { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + let id = match self { + Gamemode::Survival => 0, + Gamemode::Creative => 1, + Gamemode::Adventure => 2, + Gamemode::Spectator => 3, + }; + (id as u8).write(buffer, version)?; + + Ok(()) + } +} + +impl Readable for PreviousGamemode { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + Ok(Self::from_id(i8::read(buffer, version)?)) + } +} + +impl Writeable for PreviousGamemode { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + self.id().write(buffer, version) + } +} diff --git a/feather/protocol/src/lib.rs b/feather/protocol/src/lib.rs new file mode 100644 index 000000000..411ac5ef8 --- /dev/null +++ b/feather/protocol/src/lib.rs @@ -0,0 +1,240 @@ +use anyhow::anyhow; + +pub mod codec; +pub mod io; +pub mod packets; + +use crate::codec::CompressionThreshold; +#[doc(inline)] +pub use codec::MinecraftCodec; +pub use io::Nbt; +pub use io::{Readable, VarInt, VarLong, Writeable}; +use libcraft_items::InventorySlot; +#[doc(inline)] +pub use packets::{ + client::{ClientHandshakePacket, ClientLoginPacket, ClientPlayPacket, ClientStatusPacket}, + server::{ServerLoginPacket, ServerPlayPacket, ServerStatusPacket}, + VariantOf, +}; + +pub type Slot = InventorySlot; + +/// A protocol version. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ProtocolVersion { + V1_16_2, +} + +/// A protocol state. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum ProtocolState { + Handshake, + Status, + Login, + Play, +} + +/// Reads an arbitrary packet sent by a client based on a dynamically-updated +/// protocol state. As opposed to `MinecraftCodec`, this struct does not type-encode +/// the current protocol state using generics. +/// +/// This is a wrapper around a `MinecraftCodec` but more useful in certain sitations +/// (e.g. when writing a proxy.) +pub struct ClientPacketCodec { + state: ProtocolState, + codec: MinecraftCodec, +} + +impl Default for ClientPacketCodec { + fn default() -> Self { + Self::new() + } +} + +impl ClientPacketCodec { + pub fn new() -> Self { + Self { + state: ProtocolState::Handshake, + codec: MinecraftCodec::new(), + } + } + + pub fn set_state(&mut self, state: ProtocolState) { + self.state = state + } + + pub fn set_compression(&mut self, threshold: CompressionThreshold) { + self.codec.enable_compression(threshold) + } + + /// Decodes a `ClientPacket` using the provided data. + pub fn decode(&mut self, data: &[u8]) -> anyhow::Result<Option<ClientPacket>> { + self.codec.accept(data); + match self.state { + ProtocolState::Handshake => self + .codec + .next_packet::<ClientHandshakePacket>() + .map(|opt| opt.map(ClientPacket::from)), + ProtocolState::Status => self + .codec + .next_packet::<ClientStatusPacket>() + .map(|opt| opt.map(ClientPacket::from)), + ProtocolState::Login => self + .codec + .next_packet::<ClientLoginPacket>() + .map(|opt| opt.map(ClientPacket::from)), + ProtocolState::Play => self + .codec + .next_packet::<ClientPlayPacket>() + .map(|opt| opt.map(ClientPacket::from)), + } + } + + /// Encodes a `ClientPacket` into a buffer. + pub fn encode(&mut self, packet: &ClientPacket, buffer: &mut Vec<u8>) { + match packet { + ClientPacket::Handshake(packet) => self.codec.encode(packet, buffer).unwrap(), + ClientPacket::Status(packet) => self.codec.encode(packet, buffer).unwrap(), + ClientPacket::Login(packet) => self.codec.encode(packet, buffer).unwrap(), + ClientPacket::Play(packet) => self.codec.encode(packet, buffer).unwrap(), + } + } +} + +/// Similar to `ClientPacketCodec` but for server-sent packets. +pub struct ServerPacketCodec { + state: ProtocolState, + codec: MinecraftCodec, +} + +impl Default for ServerPacketCodec { + fn default() -> Self { + Self::new() + } +} + +impl ServerPacketCodec { + pub fn new() -> Self { + Self { + state: ProtocolState::Handshake, + codec: MinecraftCodec::new(), + } + } + + pub fn set_state(&mut self, state: ProtocolState) { + self.state = state + } + + pub fn set_compression(&mut self, threshold: CompressionThreshold) { + self.codec.enable_compression(threshold) + } + + /// Decodes a `ServerPacket` using the provided data. + pub fn decode(&mut self, data: &[u8]) -> anyhow::Result<Option<ServerPacket>> { + self.codec.accept(data); + match self.state { + ProtocolState::Handshake => Err(anyhow!("server sent data during handshake state")), + ProtocolState::Status => self + .codec + .next_packet::<ServerStatusPacket>() + .map(|opt| opt.map(ServerPacket::from)), + ProtocolState::Login => self + .codec + .next_packet::<ServerLoginPacket>() + .map(|opt| opt.map(ServerPacket::from)), + ProtocolState::Play => self + .codec + .next_packet::<ServerPlayPacket>() + .map(|opt| opt.map(ServerPacket::from)), + } + } + + /// Encodes a `ServerPacket` into a buffer. + pub fn encode(&mut self, packet: &ServerPacket, buffer: &mut Vec<u8>) { + match packet { + ServerPacket::Status(packet) => self.codec.encode(packet, buffer).unwrap(), + ServerPacket::Login(packet) => self.codec.encode(packet, buffer).unwrap(), + ServerPacket::Play(packet) => self.codec.encode(packet, buffer).unwrap(), + } + } +} + +/// A packet sent by the client from any one of the packet stages. +#[derive(Debug, Clone)] +pub enum ClientPacket { + Handshake(ClientHandshakePacket), + Status(ClientStatusPacket), + Login(ClientLoginPacket), + Play(ClientPlayPacket), +} + +impl ClientPacket { + pub fn id(&self) -> u32 { + match self { + ClientPacket::Handshake(packet) => packet.id(), + ClientPacket::Status(packet) => packet.id(), + ClientPacket::Login(packet) => packet.id(), + ClientPacket::Play(packet) => packet.id(), + } + } +} + +impl From<ClientHandshakePacket> for ClientPacket { + fn from(packet: ClientHandshakePacket) -> Self { + ClientPacket::Handshake(packet) + } +} + +impl From<ClientStatusPacket> for ClientPacket { + fn from(packet: ClientStatusPacket) -> Self { + ClientPacket::Status(packet) + } +} + +impl From<ClientLoginPacket> for ClientPacket { + fn from(packet: ClientLoginPacket) -> Self { + ClientPacket::Login(packet) + } +} + +impl From<ClientPlayPacket> for ClientPacket { + fn from(packet: ClientPlayPacket) -> Self { + ClientPacket::Play(packet) + } +} + +/// A packet sent by the server from any one of the packet stages. +#[derive(Debug, Clone)] +pub enum ServerPacket { + Status(ServerStatusPacket), + Login(ServerLoginPacket), + Play(ServerPlayPacket), +} + +impl ServerPacket { + pub fn id(&self) -> u32 { + match self { + ServerPacket::Status(packet) => packet.id(), + ServerPacket::Login(packet) => packet.id(), + ServerPacket::Play(packet) => packet.id(), + } + } +} + +impl From<ServerStatusPacket> for ServerPacket { + fn from(packet: ServerStatusPacket) -> Self { + ServerPacket::Status(packet) + } +} + +impl From<ServerLoginPacket> for ServerPacket { + fn from(packet: ServerLoginPacket) -> Self { + ServerPacket::Login(packet) + } +} + +impl From<ServerPlayPacket> for ServerPacket { + fn from(packet: ServerPlayPacket) -> Self { + ServerPacket::Play(packet) + } +} diff --git a/feather/protocol/src/packets.rs b/feather/protocol/src/packets.rs new file mode 100644 index 000000000..445051ef0 --- /dev/null +++ b/feather/protocol/src/packets.rs @@ -0,0 +1,294 @@ +macro_rules! user_type { + (VarInt) => { + i32 + }; + (VarIntPrefixedVec <$inner:ident>) => { + Vec<$inner> + }; + (ShortPrefixedVec <$inner:ident>) => { + Vec<$inner> + }; + (LengthInferredVecU8) => { + Vec<u8> + }; + (Angle) => { + f32 + }; + ($typ:ty) => { + $typ + }; +} + +macro_rules! user_type_convert_to_writeable { + (VarInt, $e:expr) => { + VarInt(*$e as i32) + }; + (VarIntPrefixedVec <$inner:ident>, $e:expr) => { + VarIntPrefixedVec::from($e.as_slice()) + }; + (ShortPrefixedVec <$inner:ident>, $e:expr) => { + ShortPrefixedVec::from($e.as_slice()) + }; + (LengthInferredVecU8, $e:expr) => { + LengthInferredVecU8::from($e.as_slice()) + }; + (Angle, $e:expr) => { + Angle(*$e) + }; + ($typ:ty, $e:expr) => { + $e + }; +} + +macro_rules! packets { + ( + $( + $packet:ident { + $( + $field:ident $typ:ident $(<$generics:ident>)? + );* $(;)? + } $(,)? + )* + ) => { + $( + #[derive(Debug, Clone)] + pub struct $packet { + $( + pub $field: user_type!($typ $(<$generics>)?), + )* + } + + #[allow(unused_imports, unused_variables)] + impl crate::Readable for $packet { + fn read(buffer: &mut ::std::io::Cursor<&[u8]>, version: crate::ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized + { + use anyhow::Context as _; + $( + let $field = <$typ $(<$generics>)?>::read(buffer, version) + .context(concat!("failed to read field `", stringify!($field), "` of packet `", stringify!($packet), "`"))? + .into(); + )* + + Ok(Self { + $( + $field, + )* + }) + } + } + + #[allow(unused_variables)] + impl crate::Writeable for $packet { + fn write(&self, buffer: &mut Vec<u8>, version: crate::ProtocolVersion) -> anyhow::Result<()> { + $( + user_type_convert_to_writeable!($typ $(<$generics>)?, &self.$field).write(buffer, version)?; + )* + Ok(()) + } + } + )* + }; +} + +macro_rules! discriminant_to_literal { + (String, $discriminant:expr) => { + &*$discriminant + }; + ($discriminant_type:ident, $discriminant:expr) => { + $discriminant.into() + }; +} + +macro_rules! def_enum { + ( + $ident:ident ($discriminant_type:ident) { + $( + $discriminant:literal = $variant:ident + $( + { + $( + $field:ident $typ:ident $(<$generics:ident>)? + );* $(;)? + } + )? + ),* $(,)? + } + ) => { + #[derive(Debug, Clone)] + pub enum $ident { + $( + $variant + $( + { + $( + $field: user_type!($typ $(<$generics>)?), + )* + } + )?, + )* + } + + impl crate::Readable for $ident { + fn read(buffer: &mut ::std::io::Cursor<&[u8]>, version: crate::ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized + { + use anyhow::Context as _; + let discriminant = <$discriminant_type>::read(buffer, version) + .context(concat!("failed to read discriminant for enum type ", stringify!($ident)))?; + + match discriminant_to_literal!($discriminant_type, discriminant) { + $( + $discriminant => { + $( + $( + let $field = <$typ $(<$generics>)?>::read(buffer, version) + .context(concat!("failed to read field `", stringify!($field), + "` of enum `", stringify!($ident), "::", stringify!($variant), "`"))? + .into(); + )* + )? + + Ok($ident::$variant $( + { + $( + $field, + )* + } + )?) + }, + )* + _ => Err(anyhow::anyhow!( + concat!( + "no discriminant for enum `", stringify!($ident), "` matched value {:?}" + ), discriminant + )) + } + } + } + + impl crate::Writeable for $ident { + fn write(&self, buffer: &mut Vec<u8>, version: crate::ProtocolVersion) -> anyhow::Result<()> { + match self { + $( + $ident::$variant $( + { + $($field,)* + } + )? => { + let discriminant = <$discriminant_type>::from($discriminant); + discriminant.write(buffer, version)?; + + $( + $( + user_type_convert_to_writeable!($typ $(<$generics>)?, $field).write(buffer, version)?; + )* + )? + } + )* + } + Ok(()) + } + } + }; +} + +macro_rules! packet_enum { + ( + $ident:ident { + $($id:literal = $packet:ident),* $(,)? + } + ) => { + #[derive(Debug, Clone)] + pub enum $ident { + $( + $packet($packet), + )* + } + + impl $ident { + /// Returns the packet ID of this packet. + pub fn id(&self) -> u32 { + match self { + $( + $ident::$packet(_) => $id, + )* + } + } + } + + impl crate::Readable for $ident { + fn read(buffer: &mut ::std::io::Cursor<&[u8]>, version: crate::ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized + { + let packet_id = VarInt::read(buffer, version)?.0; + match packet_id { + $( + id if id == $id => Ok($ident::$packet($packet::read(buffer, version)?)), + )* + _ => Err(anyhow::anyhow!("unknown packet ID {}", packet_id)), + } + } + } + + impl crate::Writeable for $ident { + fn write(&self, buffer: &mut Vec<u8>, version: crate::ProtocolVersion) -> anyhow::Result<()> { + VarInt(self.id() as i32).write(buffer, version)?; + match self { + $( + $ident::$packet(packet) => { + packet.write(buffer, version)?; + } + )* + } + Ok(()) + } + } + + $( + impl VariantOf<$ident> for $packet { + fn discriminant_id() -> u32 { $id } + + #[allow(unreachable_patterns)] + fn destructure(e: $ident) -> Option<Self> { + match e { + $ident::$packet(p) => Some(p), + _ => None, + } + } + } + + impl From<$packet> for $ident { + fn from(packet: $packet) -> Self { + $ident::$packet(packet) + } + } + )* + } +} + +/// Trait implemented for packets which can be converted from a packet +/// enum. For example, `SpawnEntity` implements `VariantOf<ServerPlayPacket>`. +pub trait VariantOf<Enum> { + /// Returns the unique ID used to determine whether + /// an enum variant matches this variant. + fn discriminant_id() -> u32; + + /// Attempts to destructure the `Enum` into this type. + /// Returns `None` if `enum` is not the correct variant. + fn destructure(e: Enum) -> Option<Self> + where + Self: Sized; +} + +use crate::io::{Angle, LengthInferredVecU8, Nbt, ShortPrefixedVec, VarInt, VarIntPrefixedVec}; +use crate::Slot; +use base::BlockId; +use nbt::Blob; +use uuid::Uuid; + +pub mod client; +pub mod server; diff --git a/feather/protocol/src/packets/client.rs b/feather/protocol/src/packets/client.rs new file mode 100644 index 000000000..3708c12a4 --- /dev/null +++ b/feather/protocol/src/packets/client.rs @@ -0,0 +1,79 @@ +//! Packets sent from client to server. + +use super::*; + +mod handshake; +mod login; +mod play; +mod status; + +pub use handshake::*; +pub use login::*; +pub use play::*; +pub use status::*; + +packet_enum!(ClientHandshakePacket { + 0x00 = Handshake, +}); + +packet_enum!(ClientStatusPacket { + 0x00 = Request, + 0x01 = Ping, +}); + +packet_enum!(ClientLoginPacket { + 0x00 = LoginStart, + 0x01 = EncryptionResponse, + 0x02 = LoginPluginResponse, +}); + +packet_enum!(ClientPlayPacket { + 0x00 = TeleportConfirm, + 0x01 = QueryBlockNbt, + 0x02 = SetDifficulty, + 0x03 = ChatMessage, + 0x04 = ClientStatus, + 0x05 = ClientSettings, + 0x06 = TabComplete, + 0x07 = WindowConfirmation, + 0x08 = ClickWindowButton, + 0x09 = ClickWindow, + 0x0A = CloseWindow, + 0x0B = PluginMessage, + 0x0C = EditBook, + 0x0D = QueryEntityNbt, + 0x0E = InteractEntity, + 0x0F = GenerateStructure, + 0x10 = KeepAlive, + 0x11 = LockDifficulty, + 0x12 = PlayerPosition, + 0x13 = PlayerPositionAndRotation, + 0x14 = PlayerRotation, + 0x15 = PlayerMovement, + 0x16 = VehicleMove, + 0x17 = SteerBoat, + 0x18 = PickItem, + 0x19 = CraftRecipeRequest, + 0x1A = PlayerAbilities, + 0x1B = PlayerDigging, + 0x1C = EntityAction, + 0x1D = SteerVehicle, + 0x1E = SetDisplayedRecipe, + 0x1F = SetRecipeBookState, + 0x20 = NameItem, + 0x21 = ResourcePackStatus, + 0x22 = AdvancementTab, + 0x23 = SelectTrade, + 0x24 = SetBeaconEffect, + 0x25 = HeldItemChange, + 0x26 = UpdateCommandBlock, + 0x27 = UpdateCommandBlockMinecart, + 0x28 = CreativeInventoryAction, + 0x29 = UpdateJigsawBlock, + 0x2A = UpdateStructureBlock, + 0x2B = UpdateSign, + 0x2C = Animation, + 0x2D = Spectate, + 0x2E = PlayerBlockPlacement, + 0x2F = UseItem, +}); diff --git a/feather/protocol/src/packets/client/handshake.rs b/feather/protocol/src/packets/client/handshake.rs new file mode 100644 index 000000000..70fa2ec51 --- /dev/null +++ b/feather/protocol/src/packets/client/handshake.rs @@ -0,0 +1,17 @@ +use super::*; + +def_enum! { + HandshakeState (VarInt) { + 1 = Status, + 2 = Login, + } +} + +packets! { + Handshake { + protocol_version VarInt; + server_address String; + server_port u16; + next_state HandshakeState; + } +} diff --git a/feather/protocol/src/packets/client/login.rs b/feather/protocol/src/packets/client/login.rs new file mode 100644 index 000000000..8e3694eab --- /dev/null +++ b/feather/protocol/src/packets/client/login.rs @@ -0,0 +1,18 @@ +use super::*; + +packets! { + LoginStart { + name String; + } + + EncryptionResponse { + shared_secret VarIntPrefixedVec<u8>; + verify_token VarIntPrefixedVec<u8>; + } + + LoginPluginResponse { + message_id VarInt; + successful bool; + data LengthInferredVecU8; + } +} diff --git a/feather/protocol/src/packets/client/play.rs b/feather/protocol/src/packets/client/play.rs new file mode 100644 index 000000000..211c71e6a --- /dev/null +++ b/feather/protocol/src/packets/client/play.rs @@ -0,0 +1,356 @@ +use base::ValidBlockPosition; + +use super::*; +use crate::packets::server::Hand; + +packets! { + TeleportConfirm { + teleport_id VarInt; + } + + QueryBlockNbt { + transaction_id VarInt; + position ValidBlockPosition; + } + + QueryEntityNbt { + transaction_id VarInt; + entity_id VarInt; + } + + SetDifficulty { + new_difficulty u8; + } + + ChatMessage { + message String; + } +} + +def_enum! { + ClientStatus (VarInt) { + 0 = PerformRespawn, + 1 = RequestStats, + } +} + +packets! { + ClientSettings { + locale String; + view_distance u8; + chat_mode ChatMode; + chat_colors bool; + displayed_skin_parts u8; + main_hand VarInt; + } +} + +def_enum! { + ChatMode (VarInt) { + 0 = Enabled, + 1 = CommandsOnly, + 2 = Hidden, + } +} + +packets! { + TabComplete { + transaction_id VarInt; + text String; + } + + WindowConfirmation { + window_id u8; + action_number u16; + accepted bool; + } + + ClickWindowButton { + window_id u8; + button_id u8; + } + + ClickWindow { + window_id u8; + slot i16; + button i8; + action_number u16; + mode VarInt; + clicked_item Slot; + } + + CloseWindow { + window_id u8; + } + + PluginMessage { + channel String; + data LengthInferredVecU8; + } + + EditBook { + new_book Slot; + is_signing bool; + hand VarInt; + } + + InteractEntity { + entity_id VarInt; + kind InteractEntityKind; + sneaking bool; + } +} + +def_enum! { + InteractEntityKind (VarInt) { + 0 = Interact, + 1 = Attack, + 2 = InteractAt { + target_x f32; + target_y f32; + target_z f32; + hand VarInt; + }, + } +} + +packets! { + GenerateStructure { + position ValidBlockPosition; + levels VarInt; + keep_jigsaws bool; + } + + KeepAlive { + id u64; + } + + LockDifficulty { + locked bool; + } + + PlayerPosition { + x f64; + feet_y f64; + z f64; + on_ground bool; + } + + PlayerPositionAndRotation { + x f64; + feet_y f64; + z f64; + yaw f32; + pitch f32; + on_ground bool; + } + + PlayerRotation { + yaw f32; + pitch f32; + on_ground bool; + } + + PlayerMovement { + on_ground bool; + } + + VehicleMove { + x f64; + y f64; + z f64; + yaw f32; + pitch f32; + } + + SteerBoat { + left_paddle_turning bool; + right_paddle_turning bool; + } + + PickItem { + slot VarInt; + } + + CraftRecipeRequest { + window_id u8; + recipe String; + make_all bool; + } + + PlayerAbilities { + flags u8; + } + + SetDisplayedRecipe { + recipe_id String; + } + + SetRecipeBookState { + book_id VarInt; + book_open bool; + filter_active bool; + } + + PlayerDigging { + status PlayerDiggingStatus; + position ValidBlockPosition; + face BlockFace; + } +} + +def_enum! { + PlayerDiggingStatus (VarInt) { + 0 = StartDigging, + 1 = CancelDigging, + 2 = FinishDigging, + 3 = DropItemStack, + 4 = DropItem, + 5 = ShootArrow, + 6 = SwapItemInHand, + } +} + +def_enum! { + BlockFace (u8) { + 0 = Bottom, + 1 = Top, + 2 = North, + 3 = South, + 4 = West, + 5 = East, + } +} + +packets! { + EntityAction { + entity_id VarInt; + action_id EntityActionKind; + jump_boost VarInt; + } +} + +def_enum! { + EntityActionKind (VarInt) { + 0 = StartSneaking, + 1 = StopSneaking, + 2 = LeaveBed, + 3 = StartSprinting, + 4 = StopSprinting, + 5 = StartHorseJump, + 6 = StopJorseJump, + 7 = OpenHorseInventory, + 8 = StartElytraFlight, + } +} + +packets! { + SteerVehicle { + sideways f32; + forward f32; + flags u8; + } +} + +packets! { + NameItem { + name String; + } + + ResourcePackStatus { + result VarInt; + } + + AdvancementTab { + tab_id Option<String>; + } + + SelectTrade { + selected_slot VarInt; + } + + SetBeaconEffect { + primary_effect VarInt; + secondary_effect VarInt; + } + + HeldItemChange { + slot u16; + } + + UpdateCommandBlock { + position ValidBlockPosition; + command String; + mode VarInt; + flags u8; + } + + UpdateCommandBlockMinecart { + entity_id VarInt; + command String; + track_output bool; + } + + CreativeInventoryAction { + slot i16; + clicked_item Slot; + } + + UpdateJigsawBlock { + position ValidBlockPosition; + name String; + target String; + pool String; + final_state String; + joint_type String; + } + + UpdateStructureBlock { + position ValidBlockPosition; + action VarInt; + mode VarInt; + name String; + offset_x i8; + offset_y i8; + offset_z i8; + size_x i8; + size_y i8; + size_z i8; + mirror VarInt; + rotation VarInt; + metadata String; + integrity f32; + seed u64; + flags u8; + } + + UpdateSign { + position ValidBlockPosition; + line_1 String; + line_2 String; + line_3 String; + line_4 String; + } + + Animation { + hand Hand; + } + + Spectate { + target_player Uuid; + } + + PlayerBlockPlacement { + hand VarInt; + position ValidBlockPosition; + face BlockFace; + cursor_position_x f32; + cursor_position_y f32; + cursor_position_z f32; + inside_block bool; + } + + UseItem { + hand VarInt; + } +} diff --git a/feather/protocol/src/packets/client/status.rs b/feather/protocol/src/packets/client/status.rs new file mode 100644 index 000000000..ec9dd3b9b --- /dev/null +++ b/feather/protocol/src/packets/client/status.rs @@ -0,0 +1,7 @@ +packets! { + Request {} + + Ping { + payload i64; + } +} diff --git a/feather/protocol/src/packets/server.rs b/feather/protocol/src/packets/server.rs new file mode 100644 index 000000000..2c761925e --- /dev/null +++ b/feather/protocol/src/packets/server.rs @@ -0,0 +1,119 @@ +//! Packets sent from server to client; + +use super::*; + +mod login; +mod play; +mod status; + +pub use login::*; +pub use play::*; +pub use status::*; + +packet_enum!(ServerStatusPacket { + 0x00 = Response, + 0x01 = Pong, +}); + +packet_enum!(ServerLoginPacket { + 0x00 = DisconnectLogin, + 0x01 = EncryptionRequest, + 0x02 = LoginSuccess, + 0x03 = SetCompression, + 0x04 = LoginPluginRequest, +}); + +packet_enum!(ServerPlayPacket { + 0x00 = SpawnEntity, + 0x01 = SpawnExperienceOrb, + 0x02 = SpawnLivingEntity, + 0x03 = SpawnPainting, + 0x04 = SpawnPlayer, + 0x05 = EntityAnimation, + 0x06 = Statistics, + 0x07 = AcknowledgePlayerDigging, + 0x08 = BlockBreakAnimation, + 0x09 = BlockEntityData, + 0x0A = BlockAction, + 0x0B = BlockChange, + 0x0C = BossBar, + 0x0D = ServerDifficulty, + 0x0E = ChatMessage, + 0x0F = TabComplete, + 0x10 = DeclareCommands, + 0x11 = WindowConfirmation, + 0x12 = CloseWindow, + 0x13 = WindowItems, + 0x14 = WindowProperty, + 0x15 = SetSlot, + 0x16 = SetCooldown, + 0x17 = PluginMessage, + 0x18 = NamedSoundEffect, + 0x19 = Disconnect, + 0x1A = EntityStatus, + 0x1B = Explosion, + 0x1C = UnloadChunk, + 0x1D = ChangeGameState, + 0x1E = OpenHorseWindow, + 0x1F = KeepAlive, + 0x20 = ChunkData, + 0x21 = Effect, + 0x22 = Particle, + 0x23 = UpdateLight, + 0x24 = JoinGame, + 0x25 = MapData, + 0x26 = TradeList, + 0x27 = EntityPosition, + 0x28 = EntityPositionAndRotation, + 0x29 = EntityRotation, + 0x2A = EntityMovement, + 0x2B = VehicleMove, + 0x2C = OpenBook, + 0x2D = OpenWindow, + 0x2E = OpenSignEditor, + 0x2F = CraftRecipeResponse, + 0x30 = PlayerAbilities, + 0x31 = CombatEvent, + 0x32 = PlayerInfo, + 0x33 = FacePlayer, + 0x34 = PlayerPositionAndLook, + 0x35 = UnlockRecipes, + 0x36 = DestroyEntities, + 0x37 = RemoveEntityEffect, + 0x38 = ResourcePack, + 0x39 = Respawn, + 0x3A = EntityHeadLook, + 0x3B = MultiBlockChange, + 0x3C = SelectAdvancementTab, + 0x3D = WorldBorder, + 0x3E = Camera, + 0x3F = HeldItemChange, + 0x40 = UpdateViewPosition, + 0x41 = UpdateViewDistance, + 0x42 = SpawnPosition, + 0x43 = DisplayScoreboard, + 0x44 = SendEntityMetadata, + 0x45 = AttachEntity, + 0x46 = EntityVelocity, + 0x47 = EntityEquipment, + 0x48 = SetExperience, + 0x49 = UpdateHealth, + 0x4A = ScoreboardObjective, + 0x4B = SetPassengers, + 0x4C = Teams, + 0x4D = UpdateScore, + 0x4E = TimeUpdate, + 0x4F = Title, + 0x50 = EntitySoundEffect, + 0x51 = SoundEffect, + 0x52 = StopSound, + 0x53 = PlayerListHeaderAndFooter, + 0x54 = NbtQueryResponse, + 0x55 = CollectItem, + 0x56 = EntityTeleport, + 0x57 = Advancements, + 0x58 = EntityProperties, + 0x59 = EntityEffect, + 0x5A = DeclareRecipes, + 0x5B = AllTags, +}); diff --git a/feather/protocol/src/packets/server/login.rs b/feather/protocol/src/packets/server/login.rs new file mode 100644 index 000000000..6626d3130 --- /dev/null +++ b/feather/protocol/src/packets/server/login.rs @@ -0,0 +1,28 @@ +use super::*; + +packets! { + DisconnectLogin { + reason String; + } + + EncryptionRequest { + server_id String; + public_key VarIntPrefixedVec<u8>; + verify_token VarIntPrefixedVec<u8>; + } + + LoginSuccess { + uuid Uuid; + username String; + } + + SetCompression { + threshold VarInt; + } + + LoginPluginRequest { + message_id VarInt; + channel String; + data LengthInferredVecU8; + } +} diff --git a/feather/protocol/src/packets/server/play.rs b/feather/protocol/src/packets/server/play.rs new file mode 100644 index 000000000..e52266b58 --- /dev/null +++ b/feather/protocol/src/packets/server/play.rs @@ -0,0 +1,1404 @@ +use std::io::Cursor; + +use anyhow::{anyhow, bail}; + +use base::{ + BlockState, EntityMetadata, Gamemode, ParticleKind, ProfileProperty, ValidBlockPosition, +}; +pub use chunk_data::{ChunkData, ChunkDataKind}; +use quill_common::components::PreviousGamemode; +pub use update_light::UpdateLight; + +use crate::{io::VarLong, ProtocolVersion, Readable, Writeable}; + +use super::*; + +mod chunk_data; +mod update_light; +packets! { + SpawnEntity { + entity_id VarInt; + uuid Uuid; + kind VarInt; + x f64; + y f64; + z f64; + pitch Angle; + yaw Angle; + data i32; + velocity_x i16; + velocity_y i16; + velocity_z i16; + } + + SpawnExperienceOrb { + entity_id VarInt; + x f64; + y f64; + z f64; + count u16; + } + + SpawnLivingEntity { + entity_id VarInt; + entity_uuid Uuid; + kind VarInt; + x f64; + y f64; + z f64; + yaw Angle; + pitch Angle; + head_pitch Angle; + velocity_x i16; + velocity_y i16; + velocity_z i16; + } + + SpawnPainting { + entity_id VarInt; + entity_uuid Uuid; + motive VarInt; + location ValidBlockPosition; + direction PaintingDirection; + } +} + +def_enum! { + PaintingDirection (i8) { + 0 = South, + 1 = West, + 2 = North, + 3 = East, + } +} + +packets! { + SpawnPlayer { + entity_id VarInt; + player_uuid Uuid; + x f64; + y f64; + z f64; + yaw Angle; + pitch Angle; + } + + EntityAnimation { + entity_id VarInt; + animation Animation; + } +} + +def_enum! { + Animation (u8) { + 0 = SwingMainArm, + 1 = TakeDamage, + 2 = LeaveBed, + 3 = SwingOffhand, + 4 = CriticalEffect, + 5 = MagicCriticalEffect, + } +} + +packets! { + Statistics { + statistics VarIntPrefixedVec<Statistic>; + } + + Statistic { + category_id VarInt; + statistic_id VarInt; + value VarInt; + } + + AcknowledgePlayerDigging { + position ValidBlockPosition; + block BlockId; + status PlayerDiggingStatus; + successful bool; + } +} + +def_enum! { + PlayerDiggingStatus (VarInt) { + 0 = Started, + 1 = Cancelled, + 2 = Finished, + } +} + +packets! { + BlockBreakAnimation { + entity_id VarInt; + position ValidBlockPosition; + destroy_stage u8; + } + + BlockEntityData { + position ValidBlockPosition; + action u8; + data Nbt<Blob>; + } + + BlockAction { + position ValidBlockPosition; + action_id u8; + action_param u8; + block_type VarInt; + } + + BlockChange { + position ValidBlockPosition; + block BlockId; + } + + BossBar { + uuid Uuid; + action BossBarAction; + } +} + +def_enum! { + BossBarAction (VarInt) { + 0 = Add { + title String; + health f32; + color BossBarColor; + division BossBarDivision; + flags u8; + }, + 1 = Remove, + 2 = UpdateHealth { health f32 }, + 3 = UpdateTitle { title String }, + 4 = UpdateStyle { color BossBarColor; division BossBarDivision; }, + 5 = UpdateFlags { flags u8; } + } +} + +def_enum! { + BossBarColor (VarInt) { + 0 = Pink, + 1 = Blue, + 2 = Red, + 3 = Green, + 4 = Yellow, + 5 = Purple, + 6 = White, + } +} + +def_enum! { + BossBarDivision (VarInt) { + 0 = None, + 1 = Notch6, + 2 = Notch10, + 3 = Notch12, + 4 = Notch20, + } +} + +packets! { + ServerDifficulty { + difficulty u8; + locked bool; + } + + ChatMessage { + message String; + position ChatPosition; + sender Uuid; + } +} + +def_enum! { + ChatPosition (i8) { + 0 = Chat, + 1 = SystemMessage, + 2 = Hotbar, + } +} + +packets! { + MultiBlockChange { + chunk_section_coordinate u64; + dont_trust_edges bool; + records VarIntPrefixedVec<VarLong>; + } + + TabComplete { + id VarInt; + start VarInt; + length VarInt; + matches VarIntPrefixedVec<TabCompleteMatch>; + } + + TabCompleteMatch { + value String; + has_tooltip bool; + tooltip Option<String>; + } + + DeclareCommands { + // (not implemented) + __todo__ LengthInferredVecU8; + /* nodes LengthPrefixedVec<CommandNode>; + root_index VarInt; */ + } + + CommandNode { + flags u8; + children VarIntPrefixedVec<VarInt>; + redirect_node Option<VarInt>; + name Option<String>; + parser Option<String>; + // TODO: handle properties, which vary depending on the value of `parser`. + // This can be handled with an enum. + __todo__ LengthInferredVecU8; + } + + WindowConfirmation { + window_id u8; + action_number i16; + is_accepted bool; + } + + CloseWindow { + window_id u8; + } + + WindowItems { + window_id u8; + items ShortPrefixedVec<Slot>; + } + + WindowProperty { + window_id u8; + property i16; + value i16; + } + + SetSlot { + window_id u8; + slot i16; + slot_data Slot; + } + + SetCooldown { + item_id VarInt; + cooldown_ticks VarInt; + } + + PluginMessage { + channel String; + data LengthInferredVecU8; + } + + NamedSoundEffect { + name String; + category VarInt; + position_x i32; + position_y i32; + position_z i32; + volume f32; + pitch f32; + } + + Disconnect { + reason String; + } + + EntityStatus { + entity_id i32; + // status changes meaning depending on entity Type + status i8; + } + + Explosion { + x f32; + y f32; + z f32; + strength f32; + records VarIntPrefixedVec<ExplosionRecord>; + player_motion_x f32; + player_motion_y f32; + player_motion_z f32; + } + + ExplosionRecord { + x_offset i8; + y_offset i8; + z_offset i8; + } + + UnloadChunk { + chunk_x i32; + chunk_z i32; + } + + ChangeGameState { + state_change GameStateChange; + } + + OpenHorseWindow { + window_id u8; + slot_count VarInt; + entity_id i32; + } + + KeepAlive { + id i64; + } + + Effect { + effect_id i32; + position ValidBlockPosition; + data i32; + disable_relative_volume bool; + } +} + +#[derive(Debug, Clone)] +pub enum GameStateChange { + /// Sends block.minecraft.spawn.not_valid to client + SendNoRespawnBlockAvailableMessage, + EndRaining, + BeginRaining, + ChangeGamemode { + gamemode: Gamemode, + }, + /// Sent when the player enters an end portal from minecraft:the_end to minecraft:overworld + WinGame { + show_credits: bool, + }, + /// See https://help.minecraft.net/hc/en-us/articles/4408948974989-Minecraft-Java-Edition-Demo-Mode- + DemoEvent(DemoEventType), + /// Sent when any player is struck by an arrow. + ArrowHitAnyPlayer, + /// Seems to change both skycolor and lightning. + RainLevelChange { + /// Possible values are from 0 to 1 + rain_level: f32, + }, + /// Seems to change both skycolor and lightning (same as Rain level change, but doesn't start rain). + /// It also requires rain to render by notchian client. + ThunderLevelChange { + /// Possible values are from 0 to 1 + thunder_level: f32, + }, + PlayPufferfishStingSound, + PlayElderGuardianAppearance, + /// Send when doImmediateRespawn gamerule changes. + EnableRespawnScreen { + enable: bool, + }, +} + +#[derive(Debug, Clone)] +pub enum DemoEventType { + ShowWelcomeToDemoScreen, + TellMovementControls, + TellJumpControl, + TellInventoryControl, + TellDemoIsOver, +} + +impl Writeable for GameStateChange { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + // Reason + match self { + GameStateChange::SendNoRespawnBlockAvailableMessage => 0u8, + GameStateChange::EndRaining => 1, + GameStateChange::BeginRaining => 2, + GameStateChange::ChangeGamemode { .. } => 3, + GameStateChange::WinGame { .. } => 4, + GameStateChange::DemoEvent(_) => 5, + GameStateChange::ArrowHitAnyPlayer => 6, + GameStateChange::RainLevelChange { .. } => 7, + GameStateChange::ThunderLevelChange { .. } => 8, + GameStateChange::PlayPufferfishStingSound => 9, + GameStateChange::PlayElderGuardianAppearance => 10, + GameStateChange::EnableRespawnScreen { .. } => 11, + } + .write(buffer, version)?; + + // Value + match self { + GameStateChange::ChangeGamemode { gamemode } => *gamemode as u8 as f32, + GameStateChange::WinGame { show_credits } => *show_credits as u8 as f32, + GameStateChange::DemoEvent(DemoEventType::ShowWelcomeToDemoScreen) => 0.0, + GameStateChange::DemoEvent(DemoEventType::TellMovementControls) => 101.0, + GameStateChange::DemoEvent(DemoEventType::TellJumpControl) => 102.0, + GameStateChange::DemoEvent(DemoEventType::TellInventoryControl) => 103.0, + GameStateChange::DemoEvent(DemoEventType::TellDemoIsOver) => 104.0, + GameStateChange::RainLevelChange { rain_level } => *rain_level, + GameStateChange::ThunderLevelChange { thunder_level } => *thunder_level, + GameStateChange::EnableRespawnScreen { enable } => !enable as u8 as f32, + _ => 0.0, + } + .write(buffer, version)?; + + Ok(()) + } +} + +impl Readable for GameStateChange { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let reason = u8::read(buffer, version)?; + let value = f32::read(buffer, version)?; + Ok(match reason { + 0 => GameStateChange::SendNoRespawnBlockAvailableMessage, + 1 => GameStateChange::EndRaining, + 2 => GameStateChange::BeginRaining, + 3 => GameStateChange::ChangeGamemode { + gamemode: Gamemode::from_id(value as u8) + .ok_or(anyhow!("Unsupported gamemode ID"))?, + }, + 4 => GameStateChange::WinGame { + show_credits: value as u8 != 0, + }, + 5 => GameStateChange::DemoEvent(match value as u8 { + 0 => DemoEventType::ShowWelcomeToDemoScreen, + 101 => DemoEventType::TellMovementControls, + 102 => DemoEventType::TellJumpControl, + 103 => DemoEventType::TellInventoryControl, + 104 => DemoEventType::TellDemoIsOver, + other => bail!("Invalid demo event type: {}", other), + }), + 6 => GameStateChange::ArrowHitAnyPlayer, + 7 => GameStateChange::RainLevelChange { rain_level: value }, + 8 => GameStateChange::ThunderLevelChange { + thunder_level: value, + }, + 9 => GameStateChange::PlayPufferfishStingSound, + 10 => GameStateChange::PlayElderGuardianAppearance, + 11 => GameStateChange::EnableRespawnScreen { + enable: value as u8 == 0, + }, + other => bail!("Invalid game state change reason: {}", other), + }) + } +} + +packets! { + JoinGame { + entity_id i32; + is_hardcore bool; + gamemode Gamemode; + previous_gamemode PreviousGamemode; // can be -1 if "not set", otherwise corresponds to a gamemode ID + world_names VarIntPrefixedVec<String>; + + dimension_codec Nbt<Blob>; + dimension Nbt<Blob>; + + world_name String; + hashed_seed u64; + max_players VarInt; + view_distance VarInt; + reduced_debug_info bool; + enable_respawn_screen bool; + + is_debug bool; + is_flat bool; + } +} + +packets! { + MapData { + map_id VarInt; + scale i8; + show_tracking_position bool; + is_locked bool; + icons VarIntPrefixedVec<Icon>; + // TODO: a bunch of fields only if a Columns is set to 0 + __todo__ LengthInferredVecU8; + } + + Icon { + kind VarInt; + x i8; + z i8; + direction i8; + display_name Option<String>; + } + + TradeList { + __todo__ LengthInferredVecU8; + } + + EntityPosition { + entity_id VarInt; + delta_x i16; + delta_y i16; + delta_z i16; + on_ground bool; + } + + EntityPositionAndRotation { + entity_id VarInt; + delta_x i16; + delta_y i16; + delta_z i16; + yaw Angle; + pitch Angle; + on_ground bool; + } + + EntityRotation { + entity_id VarInt; + yaw Angle; + pitch Angle; + on_ground bool; + } + + EntityMovement { + entity_id VarInt; + } + + VehicleMove { + x f64; + y f64; + z f64; + yaw f32; + pitch f32; + } + + OpenBook { + hand Hand; + } +} + +def_enum! { + Hand (VarInt) { + 0 = Main, + 1 = Off, + } +} + +packets! { + OpenWindow { + window_id VarInt; + window_kind VarInt; + window_title String; + } + + OpenSignEditor { + position ValidBlockPosition; + } + + CraftRecipeResponse { + window_id i8; + recipe String; + } + + PlayerAbilities { + flags u8; + flying_speed f32; + fov_modifier f32; + } + + CombatEvent { + event CombatEventKind; + } +} + +def_enum! { + CombatEventKind (VarInt) { + 0 = EnterCombat, + 1 = EndCombat { + duration VarInt; + entity_id i32; + }, + 2 = EntityDead { + player_id VarInt; + entity_id i32; + message String; + } + } +} + +#[derive(Debug, Clone)] +pub struct Particle { + pub particle_kind: ParticleKind, + pub long_distance: bool, + pub x: f64, + pub y: f64, + pub z: f64, + pub offset_x: f32, + pub offset_y: f32, + pub offset_z: f32, + pub particle_data: f32, + pub particle_count: i32, +} + +impl Readable for Particle { + fn read( + buffer: &mut std::io::Cursor<&[u8]>, + version: crate::ProtocolVersion, + ) -> anyhow::Result<Self> + where + Self: Sized, + { + let id = i32::read(buffer, version)?; + let mut particle_kind = ParticleKind::from_id(id as u32).unwrap(); + let long_distance = bool::read(buffer, version)?; + let x = f64::read(buffer, version)?; + let y = f64::read(buffer, version)?; + let z = f64::read(buffer, version)?; + let offset_x = f32::read(buffer, version)?; + let offset_y = f32::read(buffer, version)?; + let offset_z = f32::read(buffer, version)?; + let particle_data = f32::read(buffer, version)?; + let particle_count = i32::read(buffer, version)?; + + match &mut particle_kind { + ParticleKind::Dust { + ref mut red, + ref mut green, + ref mut blue, + ref mut scale, + } => { + *red = f32::read(buffer, version)?; + *green = f32::read(buffer, version)?; + *blue = f32::read(buffer, version)?; + *scale = f32::read(buffer, version)?; + } + ParticleKind::Block(ref mut block_state) => { + let state = VarInt::read(buffer, version)?; + *block_state = BlockState::from_id(state.0 as u16).unwrap(); + } + ParticleKind::FallingDust(ref mut block_state) => { + let state = VarInt::read(buffer, version)?; + *block_state = BlockState::from_id(state.0 as u16).unwrap(); + } + ParticleKind::Item(ref mut item) => { + let _slot = Slot::read(buffer, version)?; + *item = None; // TODO: Use item from libcraft once fully moved + } + _ => {} + } + + Ok(Particle { + particle_kind, + long_distance, + x, + y, + z, + offset_x, + offset_y, + offset_z, + particle_data, + particle_count, + }) + } +} + +impl Writeable for Particle { + fn write(&self, buffer: &mut Vec<u8>, version: crate::ProtocolVersion) -> anyhow::Result<()> { + self.particle_kind.id().write(buffer, version)?; + self.long_distance.write(buffer, version)?; + self.x.write(buffer, version)?; + self.y.write(buffer, version)?; + self.z.write(buffer, version)?; + self.offset_x.write(buffer, version)?; + self.offset_y.write(buffer, version)?; + self.offset_z.write(buffer, version)?; + self.particle_data.write(buffer, version)?; + self.particle_count.write(buffer, version)?; + + match self.particle_kind { + ParticleKind::Dust { + red, + green, + blue, + scale, + } => { + red.write(buffer, version)?; + green.write(buffer, version)?; + blue.write(buffer, version)?; + scale.write(buffer, version)?; + } + ParticleKind::Block(block_state) => { + VarInt(block_state.id() as i32).write(buffer, version)?; + } + ParticleKind::FallingDust(block_state) => { + VarInt(block_state.id() as i32).write(buffer, version)?; + } + ParticleKind::Item(_item) => { + todo![]; + } + _ => {} + } + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct AddPlayer { + pub uuid: Uuid, + pub name: String, + pub properties: Vec<ProfileProperty>, + pub gamemode: Gamemode, + pub ping: i32, + pub display_name: Option<String>, +} + +#[derive(Debug, Clone)] +pub enum PlayerInfo { + AddPlayers(Vec<AddPlayer>), + UpdateGamemodes(Vec<(Uuid, Gamemode)>), + UpdatePings(Vec<(Uuid, i32)>), + UpdateDisplayNames(Vec<(Uuid, Option<String>)>), + RemovePlayers(Vec<Uuid>), +} + +impl Readable for PlayerInfo { + fn read( + buffer: &mut std::io::Cursor<&[u8]>, + version: crate::ProtocolVersion, + ) -> anyhow::Result<Self> + where + Self: Sized, + { + let action = VarInt::read(buffer, version)?.0; + let num_players = VarInt::read(buffer, version)?.0; + + match action { + 0 => { + let mut vec = Vec::new(); + for _ in 0..num_players { + let uuid = Uuid::read(buffer, version)?; + let name = String::read(buffer, version)?; + + let num_properties = VarInt::read(buffer, version)?; + let mut properties = Vec::new(); + for _ in 0..num_properties.0 { + let name = String::read(buffer, version)?; + let value = String::read(buffer, version)?; + let signature = if bool::read(buffer, version)? { + String::read(buffer, version)? + } else { + String::new() + }; + properties.push(ProfileProperty { + name, + value, + signature, + }); + } + + let gamemode = Gamemode::read(buffer, version)?; + let ping = VarInt::read(buffer, version)?.0; + let display_name = if bool::read(buffer, version)? { + Some(String::read(buffer, version)?) + } else { + None + }; + vec.push(AddPlayer { + uuid, + name, + properties, + gamemode, + ping, + display_name, + }) + } + Ok(PlayerInfo::AddPlayers(vec)) + } + 1 => { + let mut vec = Vec::new(); + for _ in 0..num_players { + let uuid = Uuid::read(buffer, version)?; + let gamemode = Gamemode::read(buffer, version)?; + vec.push((uuid, gamemode)); + } + Ok(PlayerInfo::UpdateGamemodes(vec)) + } + 2 => { + let mut vec = Vec::new(); + for _ in 0..num_players { + let uuid = Uuid::read(buffer, version)?; + let ping = VarInt::read(buffer, version)?.0; + vec.push((uuid, ping)); + } + Ok(PlayerInfo::UpdatePings(vec)) + } + 3 => { + let mut vec = Vec::new(); + for _ in 0..num_players { + let uuid = Uuid::read(buffer, version)?; + let display_name = if bool::read(buffer, version)? { + Some(String::read(buffer, version)?) + } else { + None + }; + vec.push((uuid, display_name)); + } + Ok(PlayerInfo::UpdateDisplayNames(vec)) + } + 4 => { + let mut vec = Vec::new(); + for _ in 0..num_players { + let uuid = Uuid::read(buffer, version)?; + vec.push(uuid); + } + Ok(PlayerInfo::RemovePlayers(vec)) + } + x => Err(anyhow::anyhow!("invalid player info action '{}'", x)), + } + } +} + +impl Writeable for PlayerInfo { + fn write(&self, buffer: &mut Vec<u8>, version: crate::ProtocolVersion) -> anyhow::Result<()> { + let (action_id, num_players) = match self { + PlayerInfo::AddPlayers(vec) => (0, vec.len()), + PlayerInfo::UpdateGamemodes(vec) => (1, vec.len()), + PlayerInfo::UpdatePings(vec) => (2, vec.len()), + PlayerInfo::UpdateDisplayNames(vec) => (3, vec.len()), + PlayerInfo::RemovePlayers(vec) => (4, vec.len()), + }; + VarInt(action_id).write(buffer, version)?; + VarInt(num_players as i32).write(buffer, version)?; + + match self { + PlayerInfo::AddPlayers(vec) => { + for action in vec { + action.uuid.write(buffer, version)?; + action.name.write(buffer, version)?; + + VarInt(action.properties.len() as i32).write(buffer, version)?; + for prop in &action.properties { + prop.name.write(buffer, version)?; + prop.value.write(buffer, version)?; + true.write(buffer, version)?; // signature is present + prop.signature.write(buffer, version)?; + } + + action.gamemode.write(buffer, version)?; + VarInt(action.ping).write(buffer, version)?; + + action.display_name.is_some().write(buffer, version)?; + if let Some(display_name) = &action.display_name { + display_name.write(buffer, version)?; + } + } + } + PlayerInfo::UpdateGamemodes(vec) => { + for (uuid, gamemode) in vec { + uuid.write(buffer, version)?; + gamemode.write(buffer, version)?; + } + } + PlayerInfo::UpdatePings(vec) => { + for (uuid, ping) in vec { + uuid.write(buffer, version)?; + VarInt(*ping).write(buffer, version)?; + } + } + PlayerInfo::UpdateDisplayNames(vec) => { + for (uuid, display_name) in vec { + uuid.write(buffer, version)?; + display_name.is_some().write(buffer, version)?; + if let Some(display_name) = &display_name { + display_name.write(buffer, version)?; + } + } + } + PlayerInfo::RemovePlayers(vec) => { + for uuid in vec { + uuid.write(buffer, version)? + } + } + } + Ok(()) + } +} + +packets! { + FacePlayer { + feet_or_eyes VarInt; + target_x f64; + target_y f64; + target_z f64; + entity Option<FacePlayerEntity>; + } + + FacePlayerEntity { + entity_id VarInt; + feet_or_eyes VarInt; + } + + PlayerPositionAndLook { + x f64; + y f64; + z f64; + yaw f32; + pitch f32; + flags u8; + teleport_id VarInt; + } + + UnlockRecipes { + __todo__ LengthInferredVecU8; + } + + DestroyEntities { + entity_ids VarIntPrefixedVec<VarInt>; + } + + RemoveEntityEffect { + entity_id VarInt; + effect_id u8; + } + + ResourcePack { + url String; + hash String; + } + + Respawn { + dimension Nbt<Blob>; + world_name String; + hashed_seed u64; + gamemode Gamemode; + previous_gamemode Gamemode; + is_debug bool; + is_flat bool; + copy_metadata bool; + } + + EntityHeadLook { + entity_id VarInt; + head_yaw Angle; + } + + SelectAdvancementTab { + identifier Option<String>; + } +} + +def_enum! { + WorldBorder (VarInt) { + 0 = SetSize { + diameter f64; + }, + 1 = LerpSize { + old_diameter f64; + new_diameter f64; + speed u64; + }, + 2 = SetCenter { + x f64; + z f64; + }, + 3 = Initialize { + x f64; + z f64; + old_diameter f64; + new_diameter f64; + speed VarLong; + portal_teeport_boundary VarInt; + warning_time VarInt; + warning_blocks VarInt; + }, + 4 = SetWarningTime { + warning_time VarInt; + }, + 5 = SetWarningBlocks { + warning_blocks VarInt; + }, + } +} + +packets! { + Camera { + camera_id VarInt; + } + + HeldItemChange { + slot u8; // 0-8 + } + + UpdateViewPosition { + chunk_x VarInt; + chunk_z VarInt; + } + + UpdateViewDistance { + view_distance VarInt; + } + + DisplayScoreboard { + position u8; + score_name String; + } + + AttachEntity { + attached_entity_id i32; + holding_entity_id i32; + } + + EntityVelocity { + entity_id VarInt; + velocity_x i16; + velocity_y i16; + velocity_z i16; + } + + SendEntityMetadata { + entity_id VarInt; + entries EntityMetadata; + } +} + +#[derive(Debug, Clone)] +pub struct EntityEquipment { + pub entity_id: i32, + pub entries: Vec<EquipmentEntry>, +} + +impl Readable for EntityEquipment { + fn read( + buffer: &mut std::io::Cursor<&[u8]>, + version: crate::ProtocolVersion, + ) -> anyhow::Result<Self> + where + Self: Sized, + { + let entity_id = VarInt::read(buffer, version)?.0; + + // entries are terminated when the equipment slot top bit + // is no longer set + let mut entries = Vec::new(); + loop { + let slot_byte = u8::read(buffer, version)?; + let slot = match slot_byte & 0b0111_1111 { + 0 => EquipmentSlot::MainHand, + 1 => EquipmentSlot::OffHand, + 2 => EquipmentSlot::Boots, + 3 => EquipmentSlot::Leggings, + 4 => EquipmentSlot::Chestplate, + 5 => EquipmentSlot::Helmet, + slot => bail!("invalid equipment slot Id {}", slot), + }; + + let item = Slot::read(buffer, version)?; + + entries.push(EquipmentEntry { slot, item }); + + if slot_byte & 0b1000_0000 == 0 { + break; + } + } + + Ok(EntityEquipment { entity_id, entries }) + } +} + +impl Writeable for EntityEquipment { + fn write(&self, buffer: &mut Vec<u8>, version: crate::ProtocolVersion) -> anyhow::Result<()> { + VarInt(self.entity_id).write(buffer, version)?; + + for (i, entry) in self.entries.iter().enumerate() { + let mut slot_byte = match entry.slot { + EquipmentSlot::MainHand => 0u8, + EquipmentSlot::OffHand => 1, + EquipmentSlot::Boots => 2, + EquipmentSlot::Leggings => 3, + EquipmentSlot::Chestplate => 4, + EquipmentSlot::Helmet => 5, + }; + if i != self.entries.len() - 1 { + slot_byte |= 0b1000_0000; + } + slot_byte.write(buffer, version)?; + entry.item.write(buffer, version)?; + } + + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct EquipmentEntry { + pub slot: EquipmentSlot, + pub item: Slot, +} + +def_enum! { + EquipmentSlot (VarInt) { + 0 = MainHand, + 1 = OffHand, + 2 = Boots, + 3 = Leggings, + 4 = Chestplate, + 5 = Helmet, + } +} + +packets! { + SetExperience { + experience_bar f32; + level VarInt; + total_experience VarInt; + } + + UpdateHealth { + health f32; + food VarInt; + food_saturation f32; + } + + ScoreboardObjective { + objective_name String; + mode i8; + objective_value Option<String>; + kind Option<VarInt>; + } + + SetPassengers { + entity_id VarInt; + passengers VarIntPrefixedVec<VarInt>; + } + + Teams { + team_name String; + mode TeamsMode; + } +} + +def_enum! { + TeamsMode (i8) { + 0 = CreateTeam { + display_name String; + friendly_flags u8; + name_tag_visibility String; + collision_rule String; + team_color VarInt; + team_prefix String; + team_suffix String; + entities VarIntPrefixedVec<String>; // usernames or UUIDs + }, + 1 = RemoveTeam, + 2 = UpdateTeamInfo { + display_name String; + friendly_flags u8; + name_tag_visibility String; + collision_rule String; + team_color VarInt; + team_prefix String; + team_suffix String; + }, + 3 = AddEntitiesToTeam { + entities VarIntPrefixedVec<String>; + }, + 4 = RemoveEntitiesFromTeam { + entities VarIntPrefixedVec<String>; + }, + } +} + +packets! { + UpdateScore { + entity_name String; + action u8; + objective_name String; + value Option<VarInt>; + } + + SpawnPosition { + position ValidBlockPosition; + } + + TimeUpdate { + world_age u64; + time_of_day u64; + } +} + +def_enum! { + Title (VarInt) { + 0 = SetTitle { + text String; + }, + 1 = SetSubtitle { + text String; + }, + 2 = SetActionBar { + text String; + }, + 3 = SetTimesAndDisplay { + fade_in i32; + stay i32; + fade_out i32; + }, + 4 = Hide, + 5 = Reset, + } +} + +packets! { + EntitySoundEffect { + sound_id VarInt; + sound_category VarInt; + entity_id VarInt; + volume f32; + pitch f32; + } + + SoundEffect { + sound_id VarInt; + sound_category VarInt; + position_x i32; + position_y i32; + position_z i32; + volume f32; + pitch f32; + } + + StopSound { + flags u8; + source Option<VarInt>; + sound Option<String>; + } + + PlayerListHeaderAndFooter { + header String; + footer String; + } + + NbtQueryResponse { + transaction_id VarInt; + nbt Nbt<Blob>; + } + + CollectItem { + collected_entity_id VarInt; + collector_entity_id VarInt; + item_count VarInt; + } + + EntityTeleport { + entity_id VarInt; + x f64; + y f64; + z f64; + yaw Angle; + pitch Angle; + on_ground bool; + } + + Advancements { + __todo__ LengthInferredVecU8; + } + + EntityProperties { + __todo__ LengthInferredVecU8; + } + + EntityEffect { + entity_id VarInt; + effect_id u8; + amplifier i8; + duration VarInt; + flags u8; + } + + DeclareRecipes { + // This packet isn't currently working. Fortunately, we don't really need it. + __todo__ LengthInferredVecU8; + } +} + +def_enum! { + Recipe (String) { + "minecraft:crafting_shapeless" = Shapeless { + id String; + group String; + ingredient VarInt; + ingredients VarIntPrefixedVec<Ingredient>; + result Slot; + }, + "minecraft:crafting_shaped" = Shaped { + id String; + width VarInt; + height VarInt; + group String; + ingredients VarIntPrefixedVec<Ingredient>; + result Slot; + }, + "minecraft:crafting_special_armordye" = ArmorDye { id String; }, + "minecraft:crafting_special_bookcloning" = BookCloning { id String; }, + "minecraft:crafting_special_mapcloning" = MapCloning { id String; }, + "minecraft:crafting_special_mapextending" = MapExtending { id String; }, + "minecraft:crafting_special_firework_rocket" = FireworkRocket { id String; }, + "minecraft:crafting_special_firework_star" = FireworkStar { id String; }, + "minecraft:crafting_special_firework_star_fade" = FireworkStarFade { id String; }, + "minecraft:crafting_special_repairitem" = RepairItem { id String; }, + "minecraft:crafting_special_tippedarrow" = TippedArrow { id String; }, + "minecraft:crafting_special_bannderduplicate" = BannerDuplicate { id String; }, + "minecraft:crafting_special_banneraddpattern" = BannerAddPattern { id String; }, + "minecraft:crafting_special_shielddecoration" = ShieldDecoration { id String; }, + "minecraft:crafting_special_shulkerboxcoloring" = ShulkerBoxColoring { id String; }, + "minecraft:crafting_special_suspiciousstew" = SuspiciousStew { id String; }, + "minecraft:smelting" = Smelting { + id String; + group String; + ingredient Ingredient; + result Slot; + experience f32; + cooking_time VarInt; + }, + "minecraft:blasting" = Blasting { + id String; + group String; + ingredient Ingredient; + result Slot; + experience f32; + cooking_time VarInt; + }, + "minecraft:smoking" = Smoking { + id String; + group String; + ingredient Ingredient; + result Slot; + experience f32; + cooking_time VarInt; + }, + "minecraft:campfire_cooking" = CampfireCooking { + id String; + group String; + ingredient Ingredient; + result Slot; + experience f32; + cooking_time VarInt; + }, + "minecraft:stonecutting" = Stonecutting { + id String; + group String; + ingredient Ingredient; + result Slot; + } + } +} + +packets! { + Ingredient { + allowed_items VarIntPrefixedVec<Slot>; + } + + AllTags { + block_tags VarIntPrefixedVec<Tag>; + item_tags VarIntPrefixedVec<Tag>; + fluid_tags VarIntPrefixedVec<Tag>; + entity_tags VarIntPrefixedVec<Tag>; + } + + Tag { + name String; + entries VarIntPrefixedVec<VarInt>; + } +} diff --git a/feather/protocol/src/packets/server/play/chunk_data.rs b/feather/protocol/src/packets/server/play/chunk_data.rs new file mode 100644 index 000000000..569ce0148 --- /dev/null +++ b/feather/protocol/src/packets/server/play/chunk_data.rs @@ -0,0 +1,280 @@ +use std::{ + fmt::{self, Debug}, + marker::PhantomData, + sync::Arc, +}; + +use base::{Chunk, ChunkHandle, ChunkLock, ChunkPosition, ChunkSection}; +use blocks::BlockId; +use libcraft_core::Biome; +use serde::{ + de, + de::{SeqAccess, Visitor}, + Deserialize, Deserializer, Serialize, +}; + +use crate::{io::VarInt, Nbt, ProtocolVersion, Readable, Writeable}; + +#[derive(Serialize, Deserialize)] +struct Heightmaps { + #[serde(rename = "MOTION_BLOCKING")] + #[serde(serialize_with = "nbt::i64_array")] + #[serde(deserialize_with = "deserialize_i64_37")] + motion_blocking: [i64; 37], +} + +#[derive(Debug, Clone)] +pub enum ChunkDataKind { + /// Load a chunk on the client. Sends all sections + biomes. + LoadChunk, + /// Overwrite an existing chunk on the client. Sends + /// only the sections in `sections`. + OverwriteChunk { sections: Vec<usize> }, +} + +/// Packet to load a chunk on the client. +#[derive(Clone)] +pub struct ChunkData { + /// The chunk to send. + pub chunk: ChunkHandle, + + /// Whether this packet will load a chunk on + /// the client or overwrite an existing one. + pub kind: ChunkDataKind, +} + +impl Debug for ChunkData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut debug_struct = f.debug_struct("ChunkData"); + debug_struct.field("position", &self.chunk.read().position()); + debug_struct.field("kind", &self.kind); + debug_struct.finish() + } +} + +impl ChunkData { + fn should_skip_section(&self, y: usize) -> bool { + match &self.kind { + ChunkDataKind::LoadChunk => false, + ChunkDataKind::OverwriteChunk { sections } => !sections.contains(&y), + } + } +} + +impl Writeable for ChunkData { + fn write(&self, buffer: &mut Vec<u8>, version: ProtocolVersion) -> anyhow::Result<()> { + let chunk = self.chunk.read(); + + chunk.position().x.write(buffer, version)?; + chunk.position().z.write(buffer, version)?; + + let full_chunk = matches!(self.kind, ChunkDataKind::LoadChunk); + full_chunk.write(buffer, version)?; + + // Compute primary bit mask + let mut bitmask = 0; + for (y, section) in chunk.sections().iter().enumerate().skip(1).take(16) { + if section.is_some() { + if self.should_skip_section(y) { + continue; + } + + bitmask |= 1 << (y - 1) as i32; + } + } + VarInt(bitmask).write(buffer, version)?; + + let heightmaps = build_heightmaps(&chunk); + Nbt(heightmaps).write(buffer, version)?; + + if full_chunk { + // Write biomes (only if we're sending a new chunk) + VarInt(1024).write(buffer, version)?; // length of biomes + for &biome in chunk.biomes().as_slice() { + VarInt(biome.id() as i32).write(buffer, version)?; + } + } + + // Sections + let mut data = Vec::new(); + for (y, section) in chunk.sections().iter().enumerate().skip(1).take(16) { + if let Some(section) = section { + if self.should_skip_section(y) { + continue; + } + encode_section(section, &mut data, version)?; + } + } + VarInt(data.len() as i32).write(buffer, version)?; + buffer.extend_from_slice(&data); + + VarInt(0).write(buffer, version)?; // number of block entities - always 0 for Feather + + Ok(()) + } +} + +fn build_heightmaps(chunk: &Chunk) -> Heightmaps { + let mut motion_blocking = [0; 37]; + let chunk_motion_blocking = chunk.heightmaps().motion_blocking.as_u64_slice(); + motion_blocking.copy_from_slice(bytemuck::cast_slice::<_, i64>(chunk_motion_blocking)); + Heightmaps { motion_blocking } +} + +fn encode_section( + section: &ChunkSection, + buffer: &mut Vec<u8>, + version: ProtocolVersion, +) -> anyhow::Result<()> { + (section.non_air_blocks() as u16).write(buffer, version)?; + (section.blocks().data().bits_per_value() as u8).write(buffer, version)?; + + if let Some(palette) = section.blocks().palette() { + VarInt(palette.len() as i32).write(buffer, version)?; + for &block in palette.as_slice() { + VarInt(block.vanilla_id() as i32).write(buffer, version)?; + } + } + + let data = section.blocks().data().as_u64_slice(); + VarInt(data.len() as i32).write(buffer, version)?; + for &x in data { + x.write(buffer, version)?; + } + + Ok(()) +} + +impl Readable for ChunkData { + fn read(buffer: &mut std::io::Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let chunk_x = i32::read(buffer, version)?; + let chunk_z = i32::read(buffer, version)?; + + let mut chunk = Chunk::new(ChunkPosition { + x: chunk_x, + z: chunk_z, + }); + + let full_chunk = bool::read(buffer, version)?; + let chunk_data_kind: ChunkDataKind = match full_chunk { + true => ChunkDataKind::LoadChunk, + false => ChunkDataKind::OverwriteChunk { sections: vec![] }, + }; + + let primary_bit_mask = VarInt::read(buffer, version)?.0; + let heightmaps: Nbt<Heightmaps> = Nbt::read(buffer, version)?; + let heightmaps = heightmaps.0; + for (heightmaps_index, i) in heightmaps.motion_blocking.iter().enumerate() { + chunk + .heightmaps_mut() + .motion_blocking + .set_height_index(heightmaps_index, *i); + } + + if full_chunk { + let biomes_length = VarInt::read(buffer, version)?.0; + assert_eq!(biomes_length, 1024); + for y in 0..64 { + for z in 0..4 { + for x in 0..4 { + chunk.biomes_mut().set( + x, + y, + z, + Biome::from_id(VarInt::read(buffer, version)?.0 as u32) + .unwrap_or(Biome::Plains), + ); + } + } + } + } + + VarInt::read(buffer, version)?; // Size of following array + + for i in 0..16 { + if (primary_bit_mask & (1 << i)) != 0 { + if chunk.section(i).is_none() { + chunk.set_section_at(i as isize, Some(ChunkSection::default())); + } + if let Some(section) = chunk.section_mut(i + 1) { + let non_air_blocks = u16::read(buffer, version)?; + section + .blocks_mut() + .set_air_blocks(4096 - non_air_blocks as u32); + let bits_per_block = u8::read(buffer, version)?; + section + .blocks_mut() + .data_mut() + .set_bits_per_value(bits_per_block as usize); + if bits_per_block <= 4 || (5..=8).contains(&bits_per_block) { + if let Some(pallete) = section.blocks_mut().palette_mut() { + let pallete_length = VarInt::read(buffer, version)?.0 as usize; + for _ in 0..pallete_length { + let block_id = VarInt::read(buffer, version)?.0; + pallete.index_or_insert(BlockId::from_vanilla_id(block_id as u16)); + } + } + } + let data_length = VarInt::read(buffer, version)?.0 as usize; + for i in 0..data_length { + section.blocks_mut().data_mut().as_u64_mut_vec()[i] = + u64::read(buffer, version)?; + } + } + } + } + + VarInt::read(buffer, version)?; // Block entities length, redundant for feather right now + + Ok(Self { + chunk: Arc::new(ChunkLock::new(chunk, true)), + kind: chunk_data_kind, + }) + } +} + +fn deserialize_i64_37<'de, D>(deserializer: D) -> Result<[i64; 37], D::Error> +where + D: Deserializer<'de>, +{ + struct MaxVisitor(PhantomData<fn() -> [i64; 37]>); + + impl<'de> Visitor<'de> for MaxVisitor { + type Value = [i64; 37]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence of 37 numbers") + } + + fn visit_seq<S>(self, mut seq: S) -> Result<[i64; 37], S::Error> + where + S: SeqAccess<'de>, + { + let mut res = [0; 37]; + let mut index: usize = 0; + + while let Some(value) = seq.next_element()? { + res[index] = value; + index += 1; + } + + if index != 37 { + return Err(de::Error::custom(format!( + "expected 37 numbers, found {}", + index + ))); + } + + Ok(res) + } + } + + // Create the visitor and ask the deserializer to drive it. The + // deserializer will call visitor.visit_seq() if a seq is present in + // the input data. + let visitor = MaxVisitor(PhantomData); + deserializer.deserialize_seq(visitor) +} diff --git a/feather/protocol/src/packets/server/play/update_light.rs b/feather/protocol/src/packets/server/play/update_light.rs new file mode 100644 index 000000000..51ad2070d --- /dev/null +++ b/feather/protocol/src/packets/server/play/update_light.rs @@ -0,0 +1,129 @@ +use std::{fmt::Debug, sync::Arc}; + +use base::{chunk::PackedArray, Chunk, ChunkHandle, ChunkLock, ChunkPosition, ChunkSection}; + +use crate::{io::VarInt, ProtocolVersion, Readable, Writeable}; + +#[derive(Clone)] +pub struct UpdateLight { + pub chunk: ChunkHandle, +} + +impl Debug for UpdateLight { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug_struct = f.debug_struct("UpdateLight"); + debug_struct.field("position", &self.chunk.read().position()); + debug_struct.finish() + } +} + +impl Writeable for UpdateLight { + fn write(&self, buffer: &mut Vec<u8>, version: crate::ProtocolVersion) -> anyhow::Result<()> { + let chunk = self.chunk.read(); + VarInt(chunk.position().x).write(buffer, version)?; + VarInt(chunk.position().z).write(buffer, version)?; + + true.write(buffer, version)?; // trust edges? + + let mut mask = 0; + for (y, section) in chunk.sections().iter().enumerate() { + if section.is_some() { + mask |= 1 << y; + } + } + + VarInt(mask).write(buffer, version)?; // sky light mask + VarInt(mask).write(buffer, version)?; // block light mask + + VarInt(!mask).write(buffer, version)?; // empty sky light mask + VarInt(!mask).write(buffer, version)?; // empty block light mask + + for section in chunk.sections().iter().flatten() { + encode_light(section.light().sky_light(), buffer, version); + } + + for section in chunk.sections().iter().flatten() { + encode_light(section.light().block_light(), buffer, version); + } + + Ok(()) + } +} + +fn encode_light(light: &PackedArray, buffer: &mut Vec<u8>, version: ProtocolVersion) { + VarInt(2048).write(buffer, version).unwrap(); + let light_data: &[u8] = bytemuck::cast_slice(light.as_u64_slice()); + assert_eq!(light_data.len(), 2048); + buffer.extend_from_slice(light_data); +} + +impl Readable for UpdateLight { + fn read( + buffer: &mut std::io::Cursor<&[u8]>, + version: crate::ProtocolVersion, + ) -> anyhow::Result<Self> + where + Self: Sized, + { + let mut chunk = Chunk::new(ChunkPosition { + x: VarInt::read(buffer, version)?.0, + z: VarInt::read(buffer, version)?.0, + }); + + let _trust_edges = bool::read(buffer, version)?; + + let sky_light_mask = VarInt::read(buffer, version)?.0; + let block_light_mask = VarInt::read(buffer, version)?.0; + let _empty_sky_light_mask = VarInt::read(buffer, version)?; + let _empty_block_light_mask = VarInt::read(buffer, version)?; + + for i in 0..18 { + if (sky_light_mask & (1 << i)) != 0 { + let probably_2048 = VarInt::read(buffer, version)?.0 as usize; + assert_eq!(probably_2048, 2048); + let mut bytes: Vec<u8> = Vec::new(); + for _ in 0..probably_2048 { + bytes.push(u8::read(buffer, version)?); + } + let mut bytes = bytes.iter(); + if chunk.section(i).is_none() { + chunk.set_section_at(i as isize, Some(ChunkSection::default())); + } + if let Some(section) = chunk.section_mut(i + 1) { + for x in 0..16 { + for y in 0..16 { + for z in 0..16 { + section.set_sky_light_at(x, y, z, *bytes.next().unwrap_or(&15)); + } + } + } + } + } + } + + for i in 0..18 { + if (block_light_mask & (1 << i)) != 0 { + let probably_2048 = VarInt::read(buffer, version)?.0 as usize; + assert_eq!(probably_2048, 2048); + let mut bytes: Vec<u8> = Vec::new(); + for _ in 0..probably_2048 { + bytes.push(u8::read(buffer, version)?); + } + let mut bytes = bytes.iter(); + if let Some(section) = chunk.section_mut(i) { + for x in 0..16 { + for y in 0..16 { + for z in 0..16 { + section.set_block_light_at(x, y, z, *bytes.next().unwrap_or(&15)); + } + } + } + } + } + } + + Ok(Self { + chunk: Arc::new(ChunkLock::new(chunk, true)), + }) + } +} diff --git a/feather/protocol/src/packets/server/status.rs b/feather/protocol/src/packets/server/status.rs new file mode 100644 index 000000000..6cff7b1fb --- /dev/null +++ b/feather/protocol/src/packets/server/status.rs @@ -0,0 +1,9 @@ +packets! { + Response { + response String; + } + + Pong { + payload i64; + } +} diff --git a/feather/server/Cargo.toml b/feather/server/Cargo.toml new file mode 100644 index 000000000..970560311 --- /dev/null +++ b/feather/server/Cargo.toml @@ -0,0 +1,72 @@ +[package] +name = "feather-server" +version = "0.1.0" +authors = [ "caelunshun <caelunshun@gmail.com>" ] +edition = "2018" +default-run = "feather-server" + +[[bin]] +path = "src/main.rs" +name = "feather-server" + +[lib] +path = "src/lib.rs" + +[dependencies] +ahash = "0.7" +anyhow = "1" +base = { path = "../base", package = "feather-base" } +base64 = "0.13" +time = { version = "0.3", features = ["local-offset", "formatting", "macros"] } +colored = "2" +common = { path = "../common", package = "feather-common" } +crossbeam-utils = "0.8" +ecs = { path = "../ecs", package = "feather-ecs" } +fern = "0.6" +flate2 = "1" +flume = "0.10" +futures-lite = "1" +hematite-nbt = { git = "https://github.com/PistonDevelopers/hematite_nbt" } +log = "0.4" +md-5 = "0.9" +num-bigint = "0.4" +num-traits = "0.2" +once_cell = "1" +parking_lot = "0.11" +plugin-host = { path = "../plugin-host", package = "feather-plugin-host" } +protocol = { path = "../protocol", package = "feather-protocol" } +quill-common = { path = "../../quill/common" } + +rand = "0.8" +ring = "0.16" + +rsa = "0.5" +rsa-der = "0.3" +base64ct = "1" + +serde = { version = "1", features = [ "derive" ] } +serde_json = "1" +sha-1 = "0.9" +tokio = { version = "1", features = [ "full" ] } +toml = "0.5" +ureq = { version = "2", features = [ "json" ] } +utils = { path = "../utils", package = "feather-utils" } +uuid = "0.8" +slab = "0.4" +libcraft-core = { path = "../../libcraft/core" } +libcraft-items = { path = "../../libcraft/items" } +worldgen = { path = "../worldgen", package = "feather-worldgen" } + +[features] +default = [ "plugin-cranelift" ] + +# Use zlib-ng for faster compression. Requires CMake. +zlib-ng = [ "flate2/zlib-ng-compat" ] + +# Use Cranelift to JIT-compile plugins. Pure Rust +# but produces slower code than LLVM. +plugin-cranelift = [ "plugin-host/cranelift" ] +# Use LLVM to JIT-compile plugins. Produces +# very fast code, but requires LLVM to be installed +# on the build system. May impact startup times. +plugin-llvm = [ "plugin-host/llvm" ] diff --git a/server/config/feather.toml b/feather/server/config.toml similarity index 53% rename from server/config/feather.toml rename to feather/server/config.toml index c7144080a..5e9efff7a 100644 --- a/server/config/feather.toml +++ b/feather/server/config.toml @@ -1,41 +1,25 @@ # Configuration for the Feather server. -# Many of the options here are unimplemented and have no effect. -# Those that are unimplemented have been labeled so. - -[io] +[network] +address = "0.0.0.0" +port = 25565 # Packets with a size more than or equal to this value will be sent compressed. # Compressing packets reduces bandwidth usage but increases CPU activity. compression_threshold = 256 -[proxy] -# IP forwarding using either "bungee" (BungeeCord/Waterfall/Travertine) or "velocity" (Velocity) -proxy_mode = "none" # Unimplemented - [server] online_mode = true motd = "A Feather server" max_players = 16 default_gamemode = "creative" -difficulty = "none" # Unimplemented -view_distance = 6 -address = "0.0.0.0" -port = 25565 - -[gameplay] -monster_spawning = true # Unimplemented -animal_spawning = true # Unimplemented -pvp = true # Unimplemented -nerf_spawner_mobs = false # Unimplemented -# Either "classic" for 1.8 PvP or "new" for 1.9 -pvp_style = "classic" # Unimplemented +view_distance = 12 [log] -# If you prefer less verbose logs, switch this to "info." -# If you want to hurt your eyes while looking at the -# server console, set it to "trace." +# If you prefer less verbose logs, switch this to "info". +# For development, it might be useful to set this to "trace". level = "debug" +# UNINMPLEMENTED [resource_pack] # Server resource pack which is sent to players # upon joining. Set this to an empty string to disable. @@ -47,12 +31,22 @@ hash = "" # The name of the directory containing the world. name = "world" # The generator to use if the world does not exist. -# Implemented values are: default, flat +# Implemented values are: default, flat, void generator = "default" # The seed to use if the world does not exist. # Leaving this value empty will generate a random seed. # If this value is not a valid integer (i64), the string # will be converted using a hash function. seed = "" -# Interval at which to save modified chunks. -save_interval = "1min" \ No newline at end of file + +[proxy] +# Select the IP forwarding mode that is used by proxies like BungeeCord or Velocity. +# Valid values are +# - "none" - for usage without a proxy or with feathers built in proxy +# - "bungee" - for BungeeCord/Waterfall/Travertine +# - "velocity" - for Velocity style proxies +proxy_mode = "none" + +# For Velocity, you must specify the forwarding-secret from Velocity's +# velocity.toml file. +velocity_secret = "" diff --git a/feather/server/src/chunk_subscriptions.rs b/feather/server/src/chunk_subscriptions.rs new file mode 100644 index 000000000..fc7484a0f --- /dev/null +++ b/feather/server/src/chunk_subscriptions.rs @@ -0,0 +1,70 @@ +use ahash::AHashMap; +use base::ChunkPosition; +use common::{events::ViewUpdateEvent, view::View, Game}; +use ecs::{SysResult, SystemExecutor}; +use quill_common::events::EntityRemoveEvent; +use utils::vec_remove_item; + +use crate::{ClientId, Server}; + +/// Data structure to query which clients should +/// receive updates from a given chunk, fast. +#[derive(Default)] +pub struct ChunkSubscriptions { + chunks: AHashMap<ChunkPosition, Vec<ClientId>>, +} + +impl ChunkSubscriptions { + pub fn subscriptions_for(&self, chunk: ChunkPosition) -> &[ClientId] { + self.chunks + .get(&chunk) + .map(Vec::as_slice) + .unwrap_or_default() + } +} + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems + .group::<Server>() + .add_system(update_chunk_subscriptions); +} + +fn update_chunk_subscriptions(game: &mut Game, server: &mut Server) -> SysResult { + // Update players whose views have changed + for (_, (event, &client_id)) in game.ecs.query::<(&ViewUpdateEvent, &ClientId)>().iter() { + for new_chunk in event.new_view.difference(event.old_view) { + server + .chunk_subscriptions + .chunks + .entry(new_chunk) + .or_default() + .push(client_id); + } + for old_chunk in event.old_view.difference(event.new_view) { + remove_subscription(server, old_chunk, client_id); + } + } + + // Update players that have left + for (_, (_event, &client_id, &view)) in game + .ecs + .query::<(&EntityRemoveEvent, &ClientId, &View)>() + .iter() + { + for chunk in view.iter() { + remove_subscription(server, chunk, client_id); + } + } + + Ok(()) +} + +fn remove_subscription(server: &mut Server, chunk: ChunkPosition, client_id: ClientId) { + if let Some(vec) = server.chunk_subscriptions.chunks.get_mut(&chunk) { + vec_remove_item(vec, &client_id); + + if vec.is_empty() { + server.chunk_subscriptions.chunks.remove(&chunk); + } + } +} diff --git a/feather/server/src/client.rs b/feather/server/src/client.rs new file mode 100644 index 000000000..f18af09a1 --- /dev/null +++ b/feather/server/src/client.rs @@ -0,0 +1,646 @@ +use std::{ + cell::{Cell, RefCell}, + collections::VecDeque, + io::Cursor, + sync::Arc, +}; + +use ahash::AHashSet; +use flume::{Receiver, Sender}; +use slab::Slab; +use uuid::Uuid; + +use base::{ + BlockId, ChunkHandle, ChunkPosition, EntityKind, EntityMetadata, Gamemode, Position, + ProfileProperty, Text, ValidBlockPosition, +}; +use common::{ + chat::{ChatKind, ChatMessage}, + Window, +}; +use libcraft_items::InventorySlot; +use packets::server::{Particle, SetSlot, SpawnLivingEntity, UpdateLight, WindowConfirmation}; +use protocol::packets::server::{ + ChangeGameState, EntityPosition, EntityPositionAndRotation, EntityTeleport, GameStateChange, + HeldItemChange, PlayerAbilities, +}; +use protocol::{ + packets::{ + self, + server::{ + AddPlayer, Animation, BlockChange, ChatPosition, ChunkData, ChunkDataKind, + DestroyEntities, Disconnect, EntityAnimation, EntityHeadLook, JoinGame, KeepAlive, + PlayerInfo, PlayerPositionAndLook, PluginMessage, SendEntityMetadata, SpawnPlayer, + Title, UnloadChunk, UpdateViewPosition, WindowItems, + }, + }, + ClientPlayPacket, Nbt, ProtocolVersion, ServerPlayPacket, Writeable, +}; +use quill_common::components::{OnGround, PreviousGamemode}; + +use crate::{ + entities::{PreviousOnGround, PreviousPosition}, + initial_handler::NewPlayer, + network_id_registry::NetworkId, + Options, +}; + +/// Max number of chunks to send to a client per tick. +const MAX_CHUNKS_PER_TICK: usize = 10; + +/// ID of a client. Can be reused. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct ClientId(usize); + +/// Stores all `Client`s. +#[derive(Default)] +pub struct Clients { + slab: Slab<Client>, +} + +impl Clients { + pub fn new() -> Self { + Self::default() + } + + pub fn insert(&mut self, client: Client) -> ClientId { + ClientId(self.slab.insert(client)) + } + + pub fn remove(&mut self, id: ClientId) -> Option<Client> { + self.slab.try_remove(id.0) + } + + pub fn get(&self, id: ClientId) -> Option<&Client> { + self.slab.get(id.0) + } + + pub fn get_mut(&mut self, id: ClientId) -> Option<&mut Client> { + self.slab.get_mut(id.0) + } + + pub fn iter(&self) -> impl Iterator<Item = &'_ Client> + '_ { + self.slab.iter().map(|(_i, client)| client) + } +} + +/// A client connected to a server. +/// +/// This struct provides methods to send packets +/// to the client. +pub struct Client { + packets_to_send: Sender<ServerPlayPacket>, + received_packets: Receiver<ClientPlayPacket>, + options: Arc<Options>, + username: String, + profile: Vec<ProfileProperty>, + uuid: Uuid, + + teleport_id_counter: Cell<i32>, + + network_id: Option<NetworkId>, + sent_entities: RefCell<AHashSet<NetworkId>>, + + knows_position: Cell<bool>, + known_chunks: RefCell<AHashSet<ChunkPosition>>, + + chunk_send_queue: RefCell<VecDeque<ChunkData>>, + + /// The previous own position sent by the client. + /// Used to detect when we need to teleport the client. + client_known_position: Cell<Option<Position>>, + + disconnected: Cell<bool>, +} + +impl Client { + pub fn new(player: NewPlayer, options: Arc<Options>) -> Self { + Self { + packets_to_send: player.packets_to_send, + received_packets: player.received_packets, + options, + username: player.username, + teleport_id_counter: Cell::new(0), + network_id: None, + profile: player.profile, + uuid: player.uuid, + sent_entities: RefCell::new(AHashSet::new()), + knows_position: Cell::new(false), + known_chunks: RefCell::new(AHashSet::new()), + chunk_send_queue: RefCell::new(VecDeque::new()), + client_known_position: Cell::new(None), + disconnected: Cell::new(false), + } + } + + pub fn set_client_known_position(&self, pos: Position) { + self.client_known_position.set(Some(pos)); + } + + pub fn client_known_position(&self) -> Option<Position> { + self.client_known_position.get() + } + + pub fn profile(&self) -> &[ProfileProperty] { + &self.profile + } + + pub fn network_id(&self) -> Option<NetworkId> { + self.network_id + } + + pub fn uuid(&self) -> Uuid { + self.uuid + } + + pub fn username(&self) -> &str { + &self.username + } + + pub fn received_packets(&self) -> impl Iterator<Item = ClientPlayPacket> + '_ { + self.received_packets.try_iter() + } + + pub fn is_disconnected(&self) -> bool { + self.received_packets.is_disconnected() || self.disconnected.get() + } + + pub fn known_chunks(&self) -> usize { + self.known_chunks.borrow().len() + } + + pub fn knows_own_position(&self) -> bool { + self.knows_position.get() + } + + pub fn tick(&self) { + let num_to_send = MAX_CHUNKS_PER_TICK.min(self.chunk_send_queue.borrow().len()); + for packet in self.chunk_send_queue.borrow_mut().drain(0..num_to_send) { + log::trace!( + "Sending chunk at {:?} to {}", + packet.chunk.read().position(), + self.username + ); + let chunk = Arc::clone(&packet.chunk); + self.send_packet(UpdateLight { chunk }); + self.send_packet(packet); + } + } + + /// Returns whether the entity with the given ID + /// is currently loaded on the client. + pub fn is_entity_loaded(&self, network_id: NetworkId) -> bool { + self.sent_entities.borrow().contains(&network_id) + } + + pub fn set_network_id(&mut self, network_id: NetworkId) { + self.network_id = Some(network_id); + } + + pub fn send_join_game(&self, gamemode: Gamemode, previous_gamemode: PreviousGamemode) { + log::trace!("Sending Join Game to {}", self.username); + // Use the dimension codec sent by the default vanilla server. (Data acquired via tools/proxy) + let dimension_codec = nbt::Blob::from_reader(&mut Cursor::new(include_bytes!( + "../../../assets/dimension_codec.nbt" + ))) + .expect("dimension codec asset is malformed"); + let dimension = nbt::Blob::from_reader(&mut Cursor::new(include_bytes!( + "../../../assets/dimension.nbt" + ))) + .expect("dimension asset is malformed"); + + self.send_packet(JoinGame { + entity_id: self.network_id.expect("No network id! Use client.set_network_id(NetworkId) before calling this method.").0, + is_hardcore: false, + gamemode, + previous_gamemode, + world_names: vec!["world".to_owned()], + dimension_codec: Nbt(dimension_codec), + dimension: Nbt(dimension), + world_name: "world".to_owned(), + hashed_seed: 0, + max_players: 0, + view_distance: self.options.view_distance as i32, + reduced_debug_info: false, + enable_respawn_screen: true, + is_debug: false, + is_flat: false, + }); + } + + pub fn send_brand(&self) { + let mut data = Vec::new(); + "Feather" + .to_owned() + .write(&mut data, ProtocolVersion::V1_16_2) + .unwrap(); + self.send_plugin_message("minecraft:brand", data) + } + + pub fn send_plugin_message(&self, channel: impl Into<String>, data: impl Into<Vec<u8>>) { + let channel = channel.into(); + log::trace!("Sending plugin message {} to {}", channel, self.username); + self.send_packet(PluginMessage { + channel, + data: data.into(), + }) + } + + pub fn update_own_position(&self, new_position: Position) { + log::trace!( + "Updating position of {} to {:?}", + self.username, + new_position + ); + self.send_packet(PlayerPositionAndLook { + x: new_position.x, + y: new_position.y, + z: new_position.z, + yaw: new_position.yaw, + pitch: new_position.pitch, + flags: 0, + teleport_id: self.teleport_id_counter.get(), + }); + self.teleport_id_counter + .set(self.teleport_id_counter.get() + 1); + self.knows_position.set(true); + self.client_known_position.set(Some(new_position)); + } + + pub fn update_own_chunk(&self, pos: ChunkPosition) { + log::trace!("Updating chunk position of {} to {:?}", self.username, pos); + self.send_packet(UpdateViewPosition { + chunk_x: pos.x, + chunk_z: pos.z, + }); + } + + pub fn send_chunk(&self, chunk: &ChunkHandle) { + self.chunk_send_queue.borrow_mut().push_back(ChunkData { + chunk: Arc::clone(chunk), + kind: ChunkDataKind::LoadChunk, + }); + self.known_chunks + .borrow_mut() + .insert(chunk.read().position()); + } + + pub fn overwrite_chunk_sections(&self, chunk: &ChunkHandle, sections: Vec<usize>) { + self.send_packet(ChunkData { + chunk: Arc::clone(chunk), + kind: ChunkDataKind::OverwriteChunk { sections }, + }); + } + + pub fn send_block_change(&self, position: ValidBlockPosition, new_block: BlockId) { + self.send_packet(BlockChange { + position, + block: new_block, + }); + } + + pub fn unload_chunk(&self, pos: ChunkPosition) { + log::trace!("Unloading chunk at {:?} on {}", pos, self.username); + self.send_packet(UnloadChunk { + chunk_x: pos.x, + chunk_z: pos.z, + }); + self.known_chunks.borrow_mut().remove(&pos); + } + + pub fn add_tablist_player( + &self, + uuid: Uuid, + name: String, + profile: &[ProfileProperty], + gamemode: Gamemode, + ) { + log::trace!("Sending AddPlayer({}) to {}", name, self.username); + let action = AddPlayer { + uuid, + name, + properties: profile.to_vec(), + gamemode, + ping: 0, + display_name: None, + }; + self.send_packet(PlayerInfo::AddPlayers(vec![action])); + } + + pub fn remove_tablist_player(&self, uuid: Uuid) { + log::trace!("Sending RemovePlayer({}) to {}", uuid, self.username); + self.send_packet(PlayerInfo::RemovePlayers(vec![uuid])); + } + + pub fn change_player_tablist_gamemode(&self, uuid: Uuid, gamemode: Gamemode) { + self.send_packet(PlayerInfo::UpdateGamemodes(vec![(uuid, gamemode)])); + } + + pub fn unload_entity(&self, id: NetworkId) { + log::trace!("Unloading {:?} on {}", id, self.username); + self.sent_entities.borrow_mut().remove(&id); + self.send_packet(DestroyEntities { + entity_ids: vec![id.0.into()], + }); + } + + pub fn send_player(&self, network_id: NetworkId, uuid: Uuid, pos: Position) { + log::trace!("Sending {:?} to {}", uuid, self.username); + assert!(!self.sent_entities.borrow().contains(&network_id)); + self.send_packet(SpawnPlayer { + entity_id: network_id.0, + player_uuid: uuid, + x: pos.x, + y: pos.y, + z: pos.z, + yaw: pos.yaw, + pitch: pos.pitch, + }); + self.register_entity(network_id); + } + + pub fn send_living_entity( + &self, + network_id: NetworkId, + uuid: Uuid, + pos: Position, + kind: EntityKind, + ) { + log::trace!( + "Spawning a {:?} on {} (entity type ID: {})", + kind, + self.username, + kind.id() + ); + self.send_packet(SpawnLivingEntity { + entity_id: network_id.0, + entity_uuid: uuid, + kind: kind.id() as i32, + x: pos.x, + y: pos.y, + z: pos.z, + yaw: pos.yaw, + pitch: pos.pitch, + head_pitch: pos.pitch, + velocity_x: 0, + velocity_y: 0, + velocity_z: 0, + }); + } + + pub fn update_entity_position( + &self, + network_id: NetworkId, + position: Position, + prev_position: PreviousPosition, + on_ground: OnGround, + prev_on_ground: PreviousOnGround, + ) { + if self.network_id == Some(network_id) { + // This entity is the client. Only update + // the position if it has changed from the client's + // known position. + if Some(position) != self.client_known_position.get() { + self.update_own_position(position); + } + return; + } + + let no_change_yaw = (position.yaw - prev_position.0.yaw).abs() < 0.001; + let no_change_pitch = (position.pitch - prev_position.0.pitch).abs() < 0.001; + + // If the entity jumps or falls we should send a teleport packet instead to keep relative movement in sync. + if on_ground != prev_on_ground.0 { + self.send_packet(EntityTeleport { + entity_id: network_id.0, + x: position.x, + y: position.y, + z: position.z, + yaw: position.yaw, + pitch: position.pitch, + on_ground: *on_ground, + }); + + return; + } + + if no_change_yaw && no_change_pitch { + self.send_packet(EntityPosition { + entity_id: network_id.0, + delta_x: ((position.x * 32.0 - prev_position.0.x * 32.0) * 128.0) as i16, + delta_y: ((position.y * 32.0 - prev_position.0.y * 32.0) * 128.0) as i16, + delta_z: ((position.z * 32.0 - prev_position.0.z * 32.0) * 128.0) as i16, + on_ground: on_ground.0, + }); + } else { + self.send_packet(EntityPositionAndRotation { + entity_id: network_id.0, + delta_x: ((position.x * 32.0 - prev_position.0.x * 32.0) * 128.0) as i16, + delta_y: ((position.y * 32.0 - prev_position.0.y * 32.0) * 128.0) as i16, + delta_z: ((position.z * 32.0 - prev_position.0.z * 32.0) * 128.0) as i16, + yaw: position.yaw, + pitch: position.pitch, + on_ground: on_ground.0, + }); + + // Needed for head orientation + self.send_packet(EntityHeadLook { + entity_id: network_id.0, + head_yaw: position.yaw, + }); + } + } + + pub fn send_keepalive(&self) { + log::trace!("Sending keepalive to {}", self.username); + self.send_packet(KeepAlive { id: 0 }); + } + + pub fn send_entity_animation(&self, network_id: NetworkId, animation: Animation) { + if self.network_id == Some(network_id) { + return; + } + self.send_packet(EntityAnimation { + entity_id: network_id.0, + animation, + }) + } + + pub fn send_chat_message(&self, message: ChatMessage) { + let packet = chat_packet(message); + self.send_packet(packet); + } + + /// Sends all the required packets to display the [`Title`] + /// + /// If both the `title` and the `sub_title` are set to `None` + /// This will emit the [`Title::Hide`] packet. + /// + /// If the sum of `fade_in`, `stay` and `fade_out` is `0` + /// This will emit the [`Title::Reset`] packet. + pub fn send_title(&self, title: base::Title) { + if title.title.is_none() && title.sub_title.is_none() { + self.send_packet(Title::Hide); + } else if title.fade_in + title.stay + title.fade_out == 0 { + self.send_packet(Title::Reset); + } else { + if let Some(main_title) = title.title { + self.send_packet(Title::SetTitle { + text: main_title.to_string(), + }); + } + + if let Some(sub_title) = title.sub_title { + self.send_packet(Title::SetSubtitle { + text: sub_title.to_string(), + }) + } + + self.send_packet(Title::SetTimesAndDisplay { + fade_in: title.fade_in as i32, + stay: title.stay as i32, + fade_out: title.fade_out as i32, + }); + } + } + + /// Resets the title for the player, this removes + /// the text from the screen. + /// + /// Not to be confused with [`Self::hide_title()`] + pub fn reset_title(&self) { + self.send_packet(Title::Reset); + } + + /// Hides the title for the player, this removes + /// the text from the screen, but it will re-appear again + /// if the set times packet is sent again. + /// + /// Not to be confused with [`Self::reset_title()`] + pub fn hide_title(&self) { + self.send_packet(Title::Hide); + } + + pub fn confirm_window_action(&self, window_id: u8, action_number: i16, is_accepted: bool) { + self.send_packet(WindowConfirmation { + window_id, + action_number, + is_accepted, + }); + } + + pub fn send_window_items(&self, window: &Window) { + log::trace!("Updating window for {}", self.username); + let packet = WindowItems { + window_id: 0, + items: window.inner().to_vec(), + }; + self.send_packet(packet); + } + + pub fn set_slot(&self, slot: i16, item: &InventorySlot) { + log::trace!("Setting slot {} of {} to {:?}", slot, self.username, item); + self.send_packet(SetSlot { + window_id: 0, + slot, + slot_data: item.clone(), + }); + } + + pub fn send_particle(&self, particle: &base::Particle, position: &Position) { + self.send_packet(Particle { + particle_kind: particle.kind, + long_distance: true, + x: position.x, + y: position.y, + z: position.z, + offset_x: particle.offset_x, + offset_y: particle.offset_y, + offset_z: particle.offset_z, + particle_data: 0.0, + particle_count: particle.count, + }) + } + + pub fn set_cursor_slot(&self, item: &InventorySlot) { + log::trace!("Setting cursor slot of {} to {:?}", self.username, item); + self.set_slot(-1, item); + } + + pub fn send_player_model_flags(&self, netowrk_id: NetworkId, model_flags: u8) { + let mut entity_metadata = EntityMetadata::new(); + entity_metadata.set(16, model_flags); + self.send_packet(SendEntityMetadata { + entity_id: netowrk_id.0, + entries: entity_metadata, + }); + } + + pub fn send_entity_metadata(&self, network_id: NetworkId, metadata: EntityMetadata) { + if self.network_id == Some(network_id) { + return; + } + self.send_packet(SendEntityMetadata { + entity_id: network_id.0, + entries: metadata, + }); + } + + pub fn send_abilities(&self, abilities: &base::anvil::player::PlayerAbilities) { + let mut bitfield = 0; + if *abilities.invulnerable { + bitfield |= 1 << 0; + } + if *abilities.is_flying { + bitfield |= 1 << 1; + } + if *abilities.may_fly { + bitfield |= 1 << 2; + } + if *abilities.instabreak { + bitfield |= 1 << 3; + } + self.send_packet(PlayerAbilities { + flags: bitfield, + flying_speed: *abilities.fly_speed, + fov_modifier: *abilities.walk_speed, + }); + } + + pub fn set_hotbar_slot(&self, slot: u8) { + self.send_packet(HeldItemChange { slot }); + } + + pub fn change_gamemode(&self, gamemode: Gamemode) { + self.send_packet(ChangeGameState { + state_change: GameStateChange::ChangeGamemode { gamemode }, + }) + } + + fn register_entity(&self, network_id: NetworkId) { + self.sent_entities.borrow_mut().insert(network_id); + } + + fn send_packet(&self, packet: impl Into<ServerPlayPacket>) { + let _ = self.packets_to_send.try_send(packet.into()); + } + + pub fn disconnect(&self, reason: &str) { + self.disconnected.set(true); + self.send_packet(Disconnect { + reason: Text::from(reason.to_owned()).to_string(), + }); + } +} + +fn chat_packet(message: ChatMessage) -> packets::server::ChatMessage { + packets::server::ChatMessage { + message: message.text().to_string(), + position: match message.kind() { + ChatKind::PlayerChat => ChatPosition::Chat, + ChatKind::System => ChatPosition::SystemMessage, + ChatKind::AboveHotbar => ChatPosition::Hotbar, + }, + sender: Uuid::default(), + } +} diff --git a/feather/server/src/config.rs b/feather/server/src/config.rs new file mode 100644 index 000000000..9111a037f --- /dev/null +++ b/feather/server/src/config.rs @@ -0,0 +1,142 @@ +//! Loads an `Options` from a TOML config. + +use std::{fs, net::IpAddr, path::Path, str::FromStr}; + +use anyhow::Context; +use base::Gamemode; +use serde::{Deserialize, Deserializer}; + +use crate::{favicon::Favicon, Options}; + +const DEFAULT_CONFIG: &str = include_str!("../config.toml"); + +/// Loads the config, creating a default config if needed. +pub fn load(path: &str) -> anyhow::Result<ConfigContainer> { + let path = Path::new(path); + let default_config = DEFAULT_CONFIG; + let mut is_created = false; + + if !path.exists() { + log::info!("Creating default config"); + fs::write(path, default_config)?; + is_created = true; + } + + let config_string = fs::read_to_string(path)?; + let config: Config = toml::from_str(&config_string).context("invalid config.toml file")?; + + Ok(ConfigContainer { + config, + was_config_created: is_created, + }) +} + +/// A wrapper for the result returned by [load]. +pub struct ConfigContainer { + pub config: Config, + pub was_config_created: bool, +} + +#[derive(Debug, Deserialize)] +pub struct Config { + pub network: Network, + pub server: ServerConfig, + pub log: Log, + pub world: World, + pub proxy: Proxy, +} + +impl Config { + pub fn to_options(&self) -> Options { + Options { + port: self.network.port, + bind_address: self.network.address.to_string(), + favicon: Favicon::load_default(), + motd: self.server.motd.clone(), + online_mode: if self.proxy.proxy_mode != ProxyMode::None { + false + } else { + self.server.online_mode + }, + compression_threshold: if self.network.compression_threshold <= 0 { + None + } else { + Some(self.network.compression_threshold as usize) + }, + view_distance: self.server.view_distance, + max_players: self.server.max_players, + default_gamemode: self.server.default_gamemode, + proxy_mode: match self.proxy.proxy_mode { + ProxyMode::None => None, + ProxyMode::Bungee => Some(crate::options::ProxyMode::Bungeecord), + ProxyMode::Velocity => Some(crate::options::ProxyMode::Velocity), + }, + velocity_secret: self.proxy.velocity_secret.clone(), + } + } +} + +#[derive(Debug, Deserialize)] +pub struct Network { + pub address: IpAddr, + pub port: u16, + pub compression_threshold: i32, +} + +#[derive(Debug, Deserialize)] +pub struct ServerConfig { + pub online_mode: bool, + pub motd: String, + pub max_players: u32, + pub default_gamemode: Gamemode, + pub view_distance: u32, +} + +#[derive(Debug, Deserialize)] +pub struct Log { + #[serde(deserialize_with = "deserialize_log_level")] + pub level: log::LevelFilter, +} + +#[derive(Debug, Deserialize)] +pub struct World { + pub name: String, + pub generator: String, + pub seed: String, +} + +#[derive(Debug, Deserialize)] +pub struct Proxy { + pub proxy_mode: ProxyMode, + pub velocity_secret: String, +} + +#[derive(Debug, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum ProxyMode { + None, + Bungee, + Velocity, +} + +fn deserialize_log_level<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result<log::LevelFilter, D::Error> { + let string: String = String::deserialize(deserializer)?; + let level = log::LevelFilter::from_str(&string).map_err(|_| { + serde::de::Error::custom( + "invalid log level: valid options are trace, debug, info, warn, error", + ) + })?; + Ok(level) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_config_is_valid() { + let _config: Config = toml::from_str(DEFAULT_CONFIG).unwrap(); + } +} diff --git a/feather/server/src/connection_worker.rs b/feather/server/src/connection_worker.rs new file mode 100644 index 000000000..2fe57e784 --- /dev/null +++ b/feather/server/src/connection_worker.rs @@ -0,0 +1,250 @@ +use std::{fmt::Debug, io, net::SocketAddr, sync::Arc, time::Duration}; + +use base::Text; +use flume::{Receiver, Sender}; +use futures_lite::FutureExt; +use io::ErrorKind; +use protocol::{ + codec::CryptKey, packets::server::Disconnect, ClientPlayPacket, MinecraftCodec, Readable, + ServerPlayPacket, Writeable, +}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::{ + tcp::{OwnedReadHalf, OwnedWriteHalf}, + TcpStream, + }, + time::timeout, +}; + +use crate::{ + initial_handler::{InitialHandling, NewPlayer}, + options::Options, + player_count::PlayerCount, +}; + +/// Tokio task which handles a connection and processes +/// packets. +/// +/// # Lifecycle +/// * A connection is made, and the `Listener` spawns a `Worker`. +/// * Connection goes through initial handling, i.e., the handshake process. +/// * If the connection was not a status ping, then the main server thread +/// is notified of the new connection via a channel. +pub struct Worker { + reader: Reader, + writer: Writer, + options: Arc<Options>, + player_count: PlayerCount, + packets_to_send_tx: Sender<ServerPlayPacket>, + received_packets_rx: Receiver<ClientPlayPacket>, + new_players: Sender<NewPlayer>, +} + +impl Worker { + pub fn new( + stream: TcpStream, + _addr: SocketAddr, + options: Arc<Options>, + player_count: PlayerCount, + new_players: Sender<NewPlayer>, + ) -> Self { + let (reader, writer) = stream.into_split(); + + let (received_packets_tx, received_packets_rx) = flume::bounded(32); + let (packets_to_send_tx, packets_to_send_rx) = flume::unbounded(); + let reader = Reader::new(reader, received_packets_tx); + let writer = Writer::new(writer, packets_to_send_rx); + + Self { + reader, + writer, + options, + player_count, + packets_to_send_tx, + received_packets_rx, + new_players, + } + } + + pub fn start(self) { + tokio::task::spawn(async move { + self.run().await; + }); + } + + async fn run(mut self) { + let result = crate::initial_handler::handle(&mut self).await; + match result { + Ok(result) => self.proceed(result).await, + Err(e) => log::debug!("Initial handling failed: {:?}", e), + } + } + + async fn proceed(mut self, result: InitialHandling) { + match result { + InitialHandling::Disconnect => (), + InitialHandling::Join(new_player) => { + if self.player_count.try_add_player().is_err() { + self.write(ServerPlayPacket::Disconnect(Disconnect { + reason: Text::from("The server is full!").to_string(), + })) + .await + .ok(); + return; + } + + let username = new_player.username.clone(); + let _ = self.new_players.send_async(new_player).await; + self.split(username); + } + } + } + + pub fn options(&self) -> &Options { + &self.options + } + + pub fn player_count(&self) -> u32 { + self.player_count.get() + } + + #[allow(unused)] + pub fn enable_compression(&mut self, threshold: usize) { + self.reader.codec.enable_compression(threshold); + self.writer.codec.enable_compression(threshold); + + log::debug!("Enabled compression"); + } + + pub fn enable_encryption(&mut self, key: CryptKey) { + self.reader.codec.enable_encryption(key); + self.writer.codec.enable_encryption(key); + + log::debug!("Enabled encryption"); + } + + pub async fn read<P: Readable>(&mut self) -> anyhow::Result<P> { + self.reader.read().await + } + + pub async fn write(&mut self, packet: impl Writeable + Debug) -> anyhow::Result<()> { + self.writer.write(packet).await + } + + pub fn split(self, username: String) { + let Self { + reader, + writer, + player_count, + .. + } = self; + let reader = tokio::task::spawn(async move { reader.run().await }); + let writer = tokio::task::spawn(async move { writer.run().await }); + + tokio::task::spawn(async move { + let result = reader.race(writer).await.expect("task panicked"); + if let Err(e) = result { + let message = disconnected_message(e); + log::debug!("{} lost connection: {}", username, message); + } + player_count.remove_player(); + }); + } + + pub fn packets_to_send(&self) -> Sender<ServerPlayPacket> { + self.packets_to_send_tx.clone() + } + + pub fn received_packets(&self) -> Receiver<ClientPlayPacket> { + self.received_packets_rx.clone() + } +} + +struct Reader { + stream: OwnedReadHalf, + codec: MinecraftCodec, + buffer: [u8; 512], + received_packets: Sender<ClientPlayPacket>, +} + +impl Reader { + pub fn new(stream: OwnedReadHalf, received_packets: Sender<ClientPlayPacket>) -> Self { + Self { + stream, + codec: MinecraftCodec::new(), + buffer: [0; 512], + received_packets, + } + } + + pub async fn run(mut self) -> anyhow::Result<()> { + loop { + let packet = self.read::<ClientPlayPacket>().await?; + let result = self.received_packets.send_async(packet).await; + if result.is_err() { + // server dropped connection + return Ok(()); + } + } + } + + pub async fn read<P: Readable>(&mut self) -> anyhow::Result<P> { + // Keep reading bytes and trying to get the packet. + loop { + if let Some(packet) = self.codec.next_packet::<P>()? { + return Ok(packet); + } + + let duration = Duration::from_secs(10); + let read_bytes = timeout(duration, self.stream.read(&mut self.buffer)).await??; + if read_bytes == 0 { + return Err(io::Error::new(ErrorKind::UnexpectedEof, "read 0 bytes").into()); + } + + let bytes = &self.buffer[..read_bytes]; + self.codec.accept(bytes); + } + } +} + +struct Writer { + stream: OwnedWriteHalf, + codec: MinecraftCodec, + packets_to_send: Receiver<ServerPlayPacket>, + buffer: Vec<u8>, +} + +impl Writer { + pub fn new(stream: OwnedWriteHalf, packets_to_send: Receiver<ServerPlayPacket>) -> Self { + Self { + stream, + codec: MinecraftCodec::new(), + packets_to_send, + buffer: Vec::new(), + } + } + + pub async fn run(mut self) -> anyhow::Result<()> { + while let Ok(packet) = self.packets_to_send.recv_async().await { + self.write(packet).await?; + } + Ok(()) + } + + pub async fn write(&mut self, packet: impl Writeable + Debug) -> anyhow::Result<()> { + self.codec.encode(&packet, &mut self.buffer)?; + self.stream.write_all(&self.buffer).await?; + self.buffer.clear(); + Ok(()) + } +} + +fn disconnected_message(e: anyhow::Error) -> String { + if let Some(io_error) = e.downcast_ref::<io::Error>() { + if io_error.kind() == ErrorKind::UnexpectedEof { + return "disconnected".to_owned(); + } + } + format!("{:?}", e) +} diff --git a/feather/server/src/entities.rs b/feather/server/src/entities.rs new file mode 100644 index 000000000..67015afda --- /dev/null +++ b/feather/server/src/entities.rs @@ -0,0 +1,73 @@ +use base::{EntityKind, Position}; +use ecs::{EntityBuilder, EntityRef, SysResult}; +use quill_common::{components::OnGround, entity_init::EntityInit}; +use uuid::Uuid; + +use crate::{Client, NetworkId}; + +/// Component that sends the spawn packet for an entity +/// using its components. +pub struct SpawnPacketSender(fn(&EntityRef, &Client) -> SysResult); + +impl SpawnPacketSender { + pub fn send(&self, entity: &EntityRef, client: &Client) -> SysResult { + (self.0)(entity, client) + } +} + +/// Stores the [`Position`] of an entity on +/// the previous tick. Used to determine +/// when to send movement updates. +#[derive(Copy, Clone, Debug)] +pub struct PreviousPosition(pub Position); +/// Stores the [`OnGround`] status of an entity on +/// the previous tick. Used to determine +/// what movement packet to send. +#[derive(Copy, Clone, Debug)] +pub struct PreviousOnGround(pub OnGround); + +pub fn add_entity_components(builder: &mut EntityBuilder, init: &EntityInit) { + if !builder.has::<NetworkId>() { + builder.add(NetworkId::new()); + } + + // can't panic because this is only called after both position and onground is added to all entities. + // Position is added in the caller of this function and on_ground is added in the + // build default function. All entity builder functions call the build default function. + let prev_position = *builder.get::<Position>().unwrap(); + let on_ground = *builder.get::<OnGround>().unwrap(); + + builder + .add(PreviousPosition(prev_position)) + .add(PreviousOnGround(on_ground)); + add_spawn_packet(builder, init); +} + +fn add_spawn_packet(builder: &mut EntityBuilder, init: &EntityInit) { + // TODO: object entities spawned with Spawn Entity + // (minecarts, items, ...) + let spawn_packet = match init { + EntityInit::Player => spawn_player, + _ => spawn_living_entity, + }; + builder.add(SpawnPacketSender(spawn_packet)); +} + +fn spawn_player(entity: &EntityRef, client: &Client) -> SysResult { + let network_id = *entity.get::<NetworkId>()?; + let uuid = *entity.get::<Uuid>()?; + let pos = *entity.get::<Position>()?; + + client.send_player(network_id, uuid, pos); + Ok(()) +} + +fn spawn_living_entity(entity: &EntityRef, client: &Client) -> SysResult { + let network_id = *entity.get::<NetworkId>()?; + let uuid = *entity.get::<Uuid>()?; + let pos = *entity.get::<Position>()?; + let kind = *entity.get::<EntityKind>()?; + + client.send_living_entity(network_id, uuid, pos, kind); + Ok(()) +} diff --git a/feather/server/src/favicon.rs b/feather/server/src/favicon.rs new file mode 100644 index 000000000..2bb0a214a --- /dev/null +++ b/feather/server/src/favicon.rs @@ -0,0 +1,35 @@ +use std::fs; + +/// The favicon that appears in the server list on the client. +#[derive(Debug, Clone)] +pub struct Favicon { + base64_encoded: String, +} + +impl Favicon { + /// Creates a favicon from PNG image data. + /// + /// The data is not validated, but malformed + /// PNGs may cause the client to display an error. + pub fn from_png(png_bytes: &[u8]) -> Self { + // See: https://wiki.vg/Server_List_Ping#Response + let base64 = base64::encode(png_bytes); + let prefix = "data:image/png;base64,"; + let base64_encoded = format!("{}{}", prefix, base64); + Self { base64_encoded } + } + + /// Loads the favicon from its default path + /// in the current working directory, `server-icon.png`. + pub fn load_default() -> Option<Self> { + let path = "server-icon.png"; + let file_contents = fs::read(path).ok()?; + let favicon = Self::from_png(&file_contents); + Some(favicon) + } + + /// Gets base64-encoded PNG data for the `Response` packet. + pub fn base64_encoded(&self) -> &str { + &self.base64_encoded + } +} diff --git a/feather/server/src/initial_handler.rs b/feather/server/src/initial_handler.rs new file mode 100644 index 000000000..adb72127b --- /dev/null +++ b/feather/server/src/initial_handler.rs @@ -0,0 +1,327 @@ +//! Initial handling of a connection. + +use crate::{connection_worker::Worker, favicon::Favicon}; +use anyhow::bail; +use base::{ProfileProperty, Text}; +use flume::{Receiver, Sender}; +use md5::Digest; +use num_bigint::BigInt; +use once_cell::sync::Lazy; +use protocol::{ + codec::CryptKey, + packets::{ + client::{HandshakeState, Ping}, + server::{ + DisconnectLogin, EncryptionRequest, LoginSuccess, Pong, Response, SetCompression, + }, + }, + ClientHandshakePacket, ClientLoginPacket, ClientPlayPacket, ClientStatusPacket, + ServerLoginPacket, ServerPlayPacket, ServerStatusPacket, +}; +use rand::rngs::OsRng; +use rsa::{PaddingScheme, PublicKeyParts, RsaPrivateKey}; +use serde::{Deserialize, Serialize}; +use sha1::Sha1; +use std::convert::TryInto; +use uuid::Uuid; + +use self::proxy::ProxyData; + +const SERVER_NAME: &str = "Feather 1.16.5"; +const PROTOCOL_VERSION: i32 = 754; + +mod proxy; + +/// Information for a newly connected player. +#[derive(Debug)] +pub struct NewPlayer { + pub uuid: Uuid, + pub username: String, + pub profile: Vec<ProfileProperty>, + + pub received_packets: Receiver<ClientPlayPacket>, + pub packets_to_send: Sender<ServerPlayPacket>, +} + +/// Result of initial handling. +pub enum InitialHandling { + /// The client should be disconnected (sent when + /// the connection was just a "status" ping.) + Disconnect, + /// We should create a new player. + Join(NewPlayer), +} + +/// Handles a connection until the protocol state is switched to Play; +/// that is, until we send Login Success. Returns the client's information. +pub async fn handle(worker: &mut Worker) -> anyhow::Result<InitialHandling> { + // Get the handshake packet. + let handshake = worker.read::<ClientHandshakePacket>().await?; + + let ClientHandshakePacket::Handshake(handshake) = handshake; + + match handshake.next_state { + HandshakeState::Status => handle_status(worker).await, + HandshakeState::Login => { + if handshake.protocol_version < PROTOCOL_VERSION { + worker + .write(ServerLoginPacket::DisconnectLogin(DisconnectLogin { + reason: Text::from( + "Invalid protocol! The server is running on version 1.16!", + ) + .to_string(), + })) + .await + .ok(); + return Ok(InitialHandling::Disconnect); + } + let proxy_data = + if let Some(crate::options::ProxyMode::Bungeecord) = worker.options().proxy_mode { + Some(proxy::do_bungee_ip_forwarding(&handshake)?) + } else { + None + }; + handle_login(worker, proxy_data).await + } + } +} + +#[derive(Debug, Serialize)] +struct StatusResponse<'a> { + version: Version, + players: Players, + description: Text, + #[serde(skip_serializing_if = "Option::is_none")] + favicon: Option<&'a str>, +} + +#[derive(Debug, Serialize)] +struct Version { + name: &'static str, + protocol: i32, +} + +#[derive(Debug, Serialize)] +struct Players { + max: u32, + online: u32, +} + +async fn handle_status(worker: &mut Worker) -> anyhow::Result<InitialHandling> { + let _request = worker.read::<ClientStatusPacket>().await?; + + let payload = StatusResponse { + version: Version { + name: SERVER_NAME, + protocol: PROTOCOL_VERSION, + }, + players: Players { + max: worker.options().max_players, + online: worker.player_count(), + }, + description: Text::from(worker.options().motd.clone()), + favicon: worker + .options() + .favicon + .as_ref() + .map(Favicon::base64_encoded), + }; + let response = Response { + response: serde_json::to_string(&payload)?, + }; + worker + .write(&ServerStatusPacket::Response(response)) + .await?; + + match worker.read::<Ping>().await { + Ok(ping) => { + let pong = Pong { + payload: ping.payload, + }; + worker.write(&ServerStatusPacket::Pong(pong)).await?; + } + Err(e) => { + log::debug!("Didn't receive ping packet from status call: {}", e); + } + } + + Ok(InitialHandling::Disconnect) +} + +async fn handle_login( + worker: &mut Worker, + mut proxy_data: Option<ProxyData>, +) -> anyhow::Result<InitialHandling> { + let login_start = match worker.read::<ClientLoginPacket>().await? { + ClientLoginPacket::LoginStart(l) => l, + _ => bail!("expected login start"), + }; + log::debug!("{} is logging in", login_start.name); + + // Velocity IP forwarding runs after Login Start is received. + if let Some(crate::options::ProxyMode::Velocity) = worker.options().proxy_mode { + proxy_data = Some(proxy::do_velocity_ip_forwarding(worker).await?); + } + + if worker.options().online_mode { + enable_encryption(worker, login_start.name).await + } else { + let profile = match proxy_data { + Some(proxy_data) => AuthResponse { + id: proxy_data.uuid, + name: login_start.name.clone(), + properties: proxy_data.profile, + }, + None => offline_mode_profile(login_start.name), + }; + finish_login(worker, profile).await + } +} + +fn offline_mode_profile(username: String) -> AuthResponse { + // TODO: correct offline mode handling + AuthResponse { + id: offline_mode_uuid(&username), + name: username, + properties: Vec::new(), + } +} + +fn offline_mode_uuid(username: &str) -> Uuid { + // See: https://gist.github.com/games647/2b6a00a8fc21fd3b88375f03c9e2e603 + let mut hasher = md5::Md5::default(); + hasher.update(format!("OfflinePlayer:{}", username).as_bytes()); + let hash = hasher.finalize(); + + let mut builder = uuid::Builder::from_bytes(hash.try_into().unwrap()); + + builder + .set_variant(uuid::Variant::RFC4122) + .set_version(uuid::Version::Md5); + + builder.build() +} + +const RSA_BITS: usize = 1024; + +/// Cached RSA key used by this server instance. +static RSA_KEY: Lazy<RsaPrivateKey> = + Lazy::new(|| RsaPrivateKey::new(&mut OsRng, RSA_BITS).expect("failed to create RSA key")); +static RSA_KEY_ENCODED: Lazy<Vec<u8>> = Lazy::new(|| { + rsa_der::public_key_to_der(&RSA_KEY.n().to_bytes_be(), &RSA_KEY.e().to_bytes_be()) +}); + +async fn enable_encryption( + worker: &mut Worker, + username: String, +) -> anyhow::Result<InitialHandling> { + log::debug!("Authenticating {}", username); + let shared_secret = do_encryption_handshake(worker).await?; + worker.enable_encryption(shared_secret); + + let response = authenticate(shared_secret, username).await?; + + finish_login(worker, response).await +} + +async fn do_encryption_handshake(worker: &mut Worker) -> anyhow::Result<CryptKey> { + let verify_token: [u8; 16] = rand::random(); + let request = EncryptionRequest { + server_id: String::new(), // always empty + public_key: RSA_KEY_ENCODED.clone(), + verify_token: verify_token.to_vec(), + }; + worker + .write(&ServerLoginPacket::EncryptionRequest(request)) + .await?; + + let response = match worker.read::<ClientLoginPacket>().await? { + ClientLoginPacket::EncryptionResponse(r) => r, + _ => bail!("expected encryption response"), + }; + + // Decrypt shared secret and verify token. + let shared_secret = RSA_KEY.decrypt(PaddingScheme::PKCS1v15Encrypt, &response.shared_secret)?; + let received_verify_token = + RSA_KEY.decrypt(PaddingScheme::PKCS1v15Encrypt, &response.verify_token)?; + + if received_verify_token != verify_token { + bail!("verify tokens do not match"); + } + + Ok((&shared_secret[..]).try_into()?) +} + +#[derive(Debug, Deserialize)] +struct AuthResponse { + id: Uuid, + name: String, + properties: Vec<ProfileProperty>, +} + +async fn authenticate(shared_secret: CryptKey, username: String) -> anyhow::Result<AuthResponse> { + let server_hash = compute_server_hash(shared_secret); + + let response: AuthResponse = tokio::task::spawn_blocking(move || { + let url = format!( + "https://sessionserver.mojang.com/session/minecraft/hasJoined?username={}&serverId={}", + username, server_hash + ); + let response = ureq::get(&url).call()?; + + Result::<AuthResponse, anyhow::Error>::Ok(response.into_json()?) + }) + .await??; + + Ok(response) +} + +fn compute_server_hash(shared_secret: CryptKey) -> String { + let mut hasher = Sha1::new(); + hasher.update(b""); // server ID - always empty + hasher.update(&shared_secret); + hasher.update(&*RSA_KEY_ENCODED); + hexdigest(hasher.finalize().as_slice()) +} + +// Non-standard hex digest used by Minecraft. +fn hexdigest(bytes: &[u8]) -> String { + let bigint = BigInt::from_signed_bytes_be(bytes); + format!("{:x}", bigint) +} + +async fn finish_login( + worker: &mut Worker, + response: AuthResponse, +) -> anyhow::Result<InitialHandling> { + enable_compression(worker).await?; + + let success = LoginSuccess { + uuid: response.id, + username: response.name.clone(), + }; + worker + .write(&ServerLoginPacket::LoginSuccess(success)) + .await?; + + let new_player = NewPlayer { + username: response.name, + uuid: response.id, + profile: response.properties, + received_packets: worker.received_packets(), + packets_to_send: worker.packets_to_send(), + }; + log::debug!("Completed initial handling for {}", new_player.username); + Ok(InitialHandling::Join(new_player)) +} + +async fn enable_compression(worker: &mut Worker) -> anyhow::Result<()> { + if let Some(threshold) = worker.options().compression_threshold { + let packet = ServerLoginPacket::SetCompression(SetCompression { + threshold: threshold as i32, + }); + worker.write(&packet).await?; + worker.enable_compression(threshold); + } + Ok(()) +} diff --git a/feather/server/src/initial_handler/proxy.rs b/feather/server/src/initial_handler/proxy.rs new file mode 100644 index 000000000..f2a2775bb --- /dev/null +++ b/feather/server/src/initial_handler/proxy.rs @@ -0,0 +1,32 @@ +//! Proxy support for BungeeCord and Velocity. + +use base::ProfileProperty; +use protocol::packets::client::Handshake; +use uuid::Uuid; + +use crate::connection_worker::Worker; + +mod bungeecord; +mod velocity; + +/// IP forwarding data received from the proxy. +#[derive(Debug, PartialEq)] +pub struct ProxyData { + /// IP address of the proxy. + pub host: String, + /// IP address of the client. + pub client: String, + /// Client UUID. + pub uuid: Uuid, + /// Client profile properties (skin). + pub profile: Vec<ProfileProperty>, +} + +/// Runs proxy forwarding and returns the client's `ProxyData`. +pub fn do_bungee_ip_forwarding(handshake: &Handshake) -> anyhow::Result<ProxyData> { + bungeecord::extract(handshake) +} + +pub async fn do_velocity_ip_forwarding(worker: &mut Worker) -> anyhow::Result<ProxyData> { + velocity::run(worker).await +} diff --git a/feather/server/src/initial_handler/proxy/bungeecord.rs b/feather/server/src/initial_handler/proxy/bungeecord.rs new file mode 100644 index 000000000..4e576a10a --- /dev/null +++ b/feather/server/src/initial_handler/proxy/bungeecord.rs @@ -0,0 +1,172 @@ +#![allow(clippy::octal_escapes)] +use std::str::FromStr; + +use anyhow::bail; +use base::ProfileProperty; +use protocol::packets::client::Handshake; +use uuid::Uuid; + +use super::ProxyData; + +/// Tries to extract the player information that is sent in the `server_address` field of a +/// Handshake packet that originates from a BungeeCord style proxy. This is used to enable IP +/// forwarding for BungeeCord style proxies. +/// +/// The server address field should have 4 parts if a client is connecting via BungeeCord. The field +/// has the following format: +/// +/// format!("{}\0{}\0{}\0{}", host, address, uuid, mojang_response); +/// +/// | Variable | Definition | +/// |-----------------|-----------------------------------------------------| +/// | Host | The IP address of the BungeeCord instance | +/// | Address | The IP address of the connecting client | +/// | UUID | The UUID that is associated to the clients account | +/// | Mojang response | A JSON formatted version of the `properties` field +/// in [Mojangs response](https://wiki.vg/Protocol_Encryption#Server) | +#[allow(clippy::match_ref_pats)] +pub fn extract(packet: &Handshake) -> anyhow::Result<ProxyData> { + let parts: Vec<&str> = packet.server_address.split('\0').collect(); + match parts.as_slice() { + &[host, client, uuid, json_properties] => Ok(ProxyData { + host: host.to_owned(), + client: client.to_owned(), + uuid: Uuid::from_str(uuid)?, + profile: serde_json::from_str::<Vec<ProfileProperty>>(json_properties)?, + }), + _ => bail!("IP forwarding is not enabled on the proxy"), + } +} + +#[cfg(test)] +mod tests { + use base::ProfileProperty; + use protocol::packets::client::HandshakeState; + + use crate::initial_handler::PROTOCOL_VERSION; + + use super::*; + + #[test] + fn extract_bungeecord_data_normal() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\x00192.168.1.67\x00905c7e4fb96b45139645d123225575e2\x00[{\"name\":\"textures\",\"value\":\"textures_value\",\"signature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + assert_eq!( + extract(&handshake).unwrap(), + ProxyData { + host: "192.168.1.87".to_string(), + client: "192.168.1.67".to_string(), + uuid: Uuid::parse_str("905c7e4fb96b45139645d123225575e2").unwrap(), + profile: vec![ProfileProperty { + name: "textures".to_string(), + value: "textures_value".to_string(), + signature: "textures_signature".to_string(), + }], + } + ); + } + + #[test] + fn extract_bungeecord_data_too_short() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\x00192.168.1.67\x00905c7e4fb96b45139645d123225575e2" + .to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + extract(&handshake).unwrap_err(); + } + + #[test] + fn extract_bungeecord_data_too_long() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: + "192.168.1.87\x00192.168.1.67\x00905c7e4fb96b45139645d123225575e2\x00a\x00b" + .to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + extract(&handshake).unwrap_err(); + } + + #[test] + fn extract_bungeecord_data_localhost_host_ip() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "localhost\x00192.168.1.67\x00905c7e4fb96b45139645d123225575e2\x00[{\"name\":\"textures\",\"value\":\"textures_value\",\"signature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + assert_eq!( + extract(&handshake).unwrap(), + ProxyData { + host: "localhost".to_string(), + client: "192.168.1.67".to_string(), + uuid: Uuid::parse_str("905c7e4fb96b45139645d123225575e2").unwrap(), + profile: vec![ProfileProperty { + name: "textures".to_string(), + value: "textures_value".to_string(), + signature: "textures_signature".to_string(), + }], + } + ); + } + + #[test] + fn extract_bungeecord_data_localhost_client_ip() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\x00localhost\x00905c7e4fb96b45139645d123225575e2\x00[{\"name\":\"textures\",\"value\":\"textures_value\",\"signature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + assert_eq!( + extract(&handshake).unwrap(), + ProxyData { + host: "192.168.1.87".to_string(), + client: "localhost".to_string(), + uuid: Uuid::parse_str("905c7e4fb96b45139645d123225575e2").unwrap(), + profile: vec![ProfileProperty { + name: "textures".to_string(), + value: "textures_value".to_string(), + signature: "textures_signature".to_string(), + }], + } + ); + } + + #[test] + fn extract_bungeecord_data_invalid_uuid() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\x00192.168.1.67\x0005c7e4fb9675e2\x00[{\"name\":\"textures\",\"value\":\"textures_value\",\"signature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + extract(&handshake).unwrap_err(); + } + + #[test] + fn extract_bungeecord_data_invalid_properties() { + let handshake = Handshake { + protocol_version: PROTOCOL_VERSION, + server_address: "192.168.1.87\x00192.168.1.67\x00905c7e4fb96b45139645d123225575e2\x00[{\"name\":\"textures\",\"value\":\"textures_value\",\"sinature\":\"textures_signature\"}]".to_string(), + server_port: 25565, + next_state: HandshakeState::Login, + }; + + extract(&handshake).unwrap_err(); + } +} diff --git a/feather/server/src/initial_handler/proxy/velocity.rs b/feather/server/src/initial_handler/proxy/velocity.rs new file mode 100644 index 000000000..134ee556a --- /dev/null +++ b/feather/server/src/initial_handler/proxy/velocity.rs @@ -0,0 +1,123 @@ +use std::io::Cursor; + +use anyhow::anyhow; +use anyhow::bail; +use base::ProfileProperty; +use protocol::{ + io::VarIntPrefixedVec, packets::server::LoginPluginRequest, ClientLoginPacket, ProtocolVersion, + Readable, ServerLoginPacket, VarInt, +}; +use ring::{ + digest::{self}, + hmac::{self, Key}, +}; +use uuid::Uuid; + +use crate::connection_worker::Worker; + +use super::ProxyData; + +/// The plugin messaging channel used to receive the proxy data. +pub const CHANNEL: &str = "velocity:player_info"; + +/// Matches the version in VelocityConstants.java +const FORWARDING_VERSION: i32 = 1; + +const TAG_LENGTH: usize = digest::SHA256_OUTPUT_LEN; + +const MESSAGE_ID: i32 = 100000; // arbitrary + +/// Runs Velocity IP forwarding. +pub async fn run(worker: &mut Worker) -> anyhow::Result<ProxyData> { + send_plugin_message(worker).await?; + receive_response(worker).await +} + +async fn send_plugin_message(worker: &mut Worker) -> anyhow::Result<()> { + worker + .write(ServerLoginPacket::LoginPluginRequest(LoginPluginRequest { + message_id: MESSAGE_ID, + channel: CHANNEL.to_owned(), + data: Vec::new(), + })) + .await +} + +async fn receive_response(worker: &mut Worker) -> anyhow::Result<ProxyData> { + loop { + let response = worker.read::<ClientLoginPacket>().await?; + + match response { + ClientLoginPacket::LoginPluginResponse(packet) => { + if packet.message_id == MESSAGE_ID { + return read_player_info(&worker.options().velocity_secret, &packet.data); + } + } + _ => continue, + } + } +} + +fn read_player_info(key: &str, payload: &[u8]) -> anyhow::Result<ProxyData> { + let payload = verify_hmac(key, payload)?; + + let mut payload = Cursor::new(payload); + let mcversion = ProtocolVersion::V1_16_2; + + let version = VarInt::read(&mut payload, mcversion)?; + if version.0 != FORWARDING_VERSION { + bail!( + "Velocity version mismatch: Feather supports version {} but Velocity is version {}", + FORWARDING_VERSION, + version.0 + ); + } + + let client = String::read(&mut payload, mcversion)?; + let uuid = Uuid::read(&mut payload, mcversion)?; + let _name = String::read(&mut payload, mcversion)?; + let properties = VarIntPrefixedVec::<Property>::read(&mut payload, mcversion)?; + + Ok(ProxyData { + host: "".to_owned(), + client, + uuid, + profile: properties.0.iter().map(|prop| prop.0.clone()).collect(), + }) +} + +fn verify_hmac<'a>(key: &str, payload: &'a [u8]) -> anyhow::Result<&'a [u8]> { + if payload.len() < TAG_LENGTH { + bail!("player info payload too small (check that Velocity has IP forwarding enabled)"); + } + let (tag, payload) = payload.split_at(TAG_LENGTH); + + let algorithm = hmac::HMAC_SHA256; + hmac::verify(&Key::new(algorithm, key.as_bytes()), payload, tag).map_err(|_| anyhow!( + "failed to verify payload: check that velocity_key is set correctly in config.toml", + ))?; + + Ok(payload) +} + +#[derive(Debug, Clone)] +struct Property(ProfileProperty); + +impl Readable for Property { + fn read(buffer: &mut Cursor<&[u8]>, version: ProtocolVersion) -> anyhow::Result<Self> + where + Self: Sized, + { + let name = String::read(buffer, version)?; + let value = String::read(buffer, version)?; + let has_signature = bool::read(buffer, version)?; + let signature = has_signature + .then(|| String::read(buffer, version)) + .transpose()?; + Ok(Self(ProfileProperty { + name, + value, + signature: signature.unwrap_or_default(), + })) + } +} diff --git a/feather/server/src/lib.rs b/feather/server/src/lib.rs new file mode 100644 index 000000000..c1aec55dc --- /dev/null +++ b/feather/server/src/lib.rs @@ -0,0 +1,147 @@ +#![allow(clippy::unnecessary_wraps)] // systems are required to return Results + +use std::{sync::Arc, time::Instant}; + +use base::Position; +use chunk_subscriptions::ChunkSubscriptions; +use common::Game; +use ecs::SystemExecutor; +use flume::Receiver; +use initial_handler::NewPlayer; +use listener::Listener; + +mod chunk_subscriptions; +pub mod client; +pub mod config; +mod connection_worker; +mod entities; +pub mod favicon; +mod initial_handler; +mod listener; +mod network_id_registry; +mod options; +mod packet_handlers; +mod player_count; +mod systems; + +pub use client::{Client, ClientId, Clients}; +pub use network_id_registry::NetworkId; +pub use options::Options; +use player_count::PlayerCount; +use systems::view::WaitingChunks; + +/// A Minecraft server. +/// +/// Call [`link_with_game`](Server::link_with_game) to register the server +/// with a [`Game`](common::Game). This will +/// cause the server to serve the game to players. +/// +/// Uses asynchronous IO with Tokio. +pub struct Server { + options: Arc<Options>, + clients: Clients, + new_players: Receiver<NewPlayer>, + + waiting_chunks: WaitingChunks, + chunk_subscriptions: ChunkSubscriptions, + + last_keepalive_time: Instant, + + player_count: PlayerCount, +} + +impl Server { + /// Starts a server with the given `Options`. + /// + /// Must be called within the context of a Tokio runtime. + pub async fn bind(options: Options) -> anyhow::Result<Self> { + let options = Arc::new(options); + let player_count = PlayerCount::new(options.max_players); + + let (new_players_tx, new_players) = flume::bounded(4); + Listener::start(Arc::clone(&options), player_count.clone(), new_players_tx).await?; + + log::info!( + "Server is listening on {}:{}", + options.bind_address, + options.port + ); + + Ok(Self { + options, + clients: Clients::new(), + new_players, + waiting_chunks: WaitingChunks::default(), + chunk_subscriptions: ChunkSubscriptions::default(), + last_keepalive_time: Instant::now(), + player_count, + }) + } + + /// Links this server with a `Game` so that players connecting + /// to the server become part of this `Game`. + pub fn link_with_game(self, game: &mut Game, systems: &mut SystemExecutor<Game>) { + systems::register(self, game, systems); + game.add_entity_spawn_callback(entities::add_entity_components); + } + + /// Gets the number of online players. + pub fn player_count(&self) -> u32 { + self.player_count.get() + } +} + +/// Low-level functions, mostly used internally. +/// You may find these useful for some custom functionality. +impl Server { + /// Polls for newly connected players. Returns the IDs of the new clients. + pub fn accept_new_players(&mut self) -> Vec<ClientId> { + let mut clients = Vec::new(); + for player in self.new_players.clone().try_iter() { + if let Some(old_client) = self.clients.iter().find(|x| x.uuid() == player.uuid) { + old_client.disconnect("Logged in from another location!"); + } + let id = self.create_client(player); + clients.push(id); + } + clients + } + + /// Removes a client. + pub fn remove_client(&mut self, id: ClientId) { + let client = self.clients.remove(id); + if let Some(client) = client { + log::debug!("Removed client for {}", client.username()); + } + } + + fn create_client(&mut self, player: NewPlayer) -> ClientId { + log::debug!("Creating client for {}", player.username); + let client = Client::new(player, Arc::clone(&self.options)); + self.clients.insert(client) + } + + /// Invokes a callback on all clients. + pub fn broadcast_with(&self, mut callback: impl FnMut(&Client)) { + for client in self.clients.iter() { + callback(client); + } + } + + /// Sends a packet to all clients currently subscribed + /// to the given position. This function should be + /// used for entity updates, block updates, etc— + /// any packets that need to be sent only to nearby players. + pub fn broadcast_nearby_with(&self, position: Position, mut callback: impl FnMut(&Client)) { + for &client_id in self.chunk_subscriptions.subscriptions_for(position.chunk()) { + if let Some(client) = self.clients.get(client_id) { + callback(client); + } + } + } + + pub fn broadcast_keepalive(&mut self) { + self.broadcast_with(|client| client.send_keepalive()); + self.last_keepalive_time = Instant::now(); + } +} diff --git a/feather/server/src/listener.rs b/feather/server/src/listener.rs new file mode 100644 index 000000000..6e8cddbd2 --- /dev/null +++ b/feather/server/src/listener.rs @@ -0,0 +1,61 @@ +use std::{net::SocketAddr, sync::Arc}; + +use anyhow::Context; +use flume::Sender; +use tokio::net::{TcpListener, TcpStream}; + +use crate::{ + connection_worker::Worker, initial_handler::NewPlayer, options::Options, + player_count::PlayerCount, +}; + +/// Listens for and accepts incoming connections. +pub struct Listener { + listener: TcpListener, + options: Arc<Options>, + player_count: PlayerCount, + new_players: Sender<NewPlayer>, +} + +impl Listener { + pub async fn start( + options: Arc<Options>, + player_count: PlayerCount, + new_players: Sender<NewPlayer>, + ) -> anyhow::Result<()> { + let listener = TcpListener::bind(format!("{}:{}", options.bind_address, options.port)) + .await + .context("failed to bind to port - maybe a server is already running?")?; + + let listener = Listener { + listener, + options, + player_count, + new_players, + }; + tokio::task::spawn(async move { + listener.run().await; + }); + + Ok(()) + } + + async fn run(mut self) { + loop { + if let Ok((stream, addr)) = self.listener.accept().await { + self.accept(stream, addr).await; + } + } + } + + async fn accept(&mut self, stream: TcpStream, addr: SocketAddr) { + let worker = Worker::new( + stream, + addr, + Arc::clone(&self.options), + self.player_count.clone(), + self.new_players.clone(), + ); + worker.start(); + } +} diff --git a/feather/server/src/logging.rs b/feather/server/src/logging.rs new file mode 100644 index 000000000..0dd93e45a --- /dev/null +++ b/feather/server/src/logging.rs @@ -0,0 +1,47 @@ +use colored::Colorize; +use log::{Level, LevelFilter}; +use time::macros::format_description; +use time::OffsetDateTime; + +pub fn init(level: LevelFilter) { + fern::Dispatch::new() + .format(|out, message, record| { + let level_string = match record.level() { + Level::Error => record.level().to_string().red(), + Level::Warn => record.level().to_string().yellow(), + Level::Info => record.level().to_string().cyan(), + Level::Debug => record.level().to_string().purple(), + Level::Trace => record.level().to_string().normal(), + }; + let target = if !record.target().is_empty() { + record.target() + } else { + record.module_path().unwrap_or_default() + }; + + let datetime: OffsetDateTime = match OffsetDateTime::now_local() { + Ok(x) => x, + Err(_) => OffsetDateTime::now_utc(), + }; + out.finish(format_args!( + "{} {:<5} [{}] {}", + datetime + .format(format_description!( + "[year]-[month]-[day] [hour]:[minute]:[second],[subsecond digits:3]" + )) + .unwrap(), + level_string, + target, + message, + )); + }) + .level(level) + // cranelift_codegen spams debug-level logs + .level_for("cranelift_codegen", LevelFilter::Info) + .level_for("regalloc", LevelFilter::Off) + .level_for("wasmer_wasi::syscalls", LevelFilter::Info) + .level_for("wasmer_compiler_cranelift::translator", LevelFilter::Warn) + .chain(std::io::stdout()) + .apply() + .unwrap(); +} diff --git a/feather/server/src/main.rs b/feather/server/src/main.rs new file mode 100644 index 000000000..c3bf7ea16 --- /dev/null +++ b/feather/server/src/main.rs @@ -0,0 +1,107 @@ +use std::{cell::RefCell, rc::Rc, sync::Arc}; + +use anyhow::Context; +use base::anvil::level::SuperflatGeneratorOptions; +use common::{Game, TickLoop, World}; +use ecs::SystemExecutor; +use feather_server::{config::Config, Server}; +use plugin_host::PluginManager; +use worldgen::{ComposableGenerator, SuperflatWorldGenerator, VoidWorldGenerator, WorldGenerator}; + +mod logging; + +const PLUGINS_DIRECTORY: &str = "plugins"; +const CONFIG_PATH: &str = "config.toml"; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let feather_server::config::ConfigContainer { + config, + was_config_created, + } = feather_server::config::load(CONFIG_PATH).context("failed to load configuration file")?; + logging::init(config.log.level); + if was_config_created { + log::info!("Created default config"); + } + log::info!("Loaded config"); + + log::info!("Creating server"); + let options = config.to_options(); + let server = Server::bind(options).await?; + + let game = init_game(server, &config)?; + + run(game); + + Ok(()) +} + +fn init_game(server: Server, config: &Config) -> anyhow::Result<Game> { + let mut game = Game::new(); + init_systems(&mut game, server); + init_world_source(&mut game, config); + init_plugin_manager(&mut game)?; + Ok(game) +} + +fn init_systems(game: &mut Game, server: Server) { + let mut systems = SystemExecutor::new(); + + // Register common before server code, so + // that packet broadcasting happens after + // gameplay actions. + common::register(game, &mut systems); + server.link_with_game(game, &mut systems); + + print_systems(&systems); + + game.system_executor = Rc::new(RefCell::new(systems)); +} + +fn init_world_source(game: &mut Game, config: &Config) { + // Load chunks from the world save first, + // and fall back to generating a superflat + // world otherwise. This is a placeholder: + // we don't have proper world generation yet. + + let seed = 42; // FIXME: load from the level file + + let generator: Arc<dyn WorldGenerator> = match &config.world.generator[..] { + "flat" => Arc::new(SuperflatWorldGenerator::new( + SuperflatGeneratorOptions::default(), + )), + "void" => Arc::new(VoidWorldGenerator), + _ => Arc::new(ComposableGenerator::default_with_seed(seed)), + }; + game.world = World::with_gen_and_path(generator, config.world.name.clone()); +} + +fn init_plugin_manager(game: &mut Game) -> anyhow::Result<()> { + let mut plugin_manager = PluginManager::new(); + plugin_manager.load_dir(game, PLUGINS_DIRECTORY)?; + + let plugin_manager_rc = Rc::new(RefCell::new(plugin_manager)); + game.insert_resource(plugin_manager_rc); + Ok(()) +} + +fn print_systems(systems: &SystemExecutor<Game>) { + let systems: Vec<&str> = systems.system_names().collect(); + log::debug!("---SYSTEMS---\n{:#?}\n", systems); +} + +fn run(game: Game) { + let tick_loop = create_tick_loop(game); + log::debug!("Launching the game loop"); + tick_loop.run(); +} + +fn create_tick_loop(mut game: Game) -> TickLoop { + TickLoop::new(move || { + let systems = Rc::clone(&game.system_executor); + systems.borrow_mut().run(&mut game); + game.tick_count += 1; + + false + }) +} diff --git a/feather/server/src/network_id_registry.rs b/feather/server/src/network_id_registry.rs new file mode 100644 index 000000000..117c293a0 --- /dev/null +++ b/feather/server/src/network_id_registry.rs @@ -0,0 +1,17 @@ +use std::sync::atomic::{AtomicI32, Ordering}; + +/// An entity's ID used by the protocol +/// in `entity_id` fields. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct NetworkId(pub i32); + +impl NetworkId { + /// Creates a new, unique network ID. + pub(crate) fn new() -> Self { + static NEXT: AtomicI32 = AtomicI32::new(0); + // In theory, this can overflow if the server + // creates 4 billion entities. The hope is that + // old entities will have died out at that point. + Self(NEXT.fetch_add(1, Ordering::SeqCst)) + } +} diff --git a/feather/server/src/options.rs b/feather/server/src/options.rs new file mode 100644 index 000000000..f75fc203f --- /dev/null +++ b/feather/server/src/options.rs @@ -0,0 +1,44 @@ +use base::Gamemode; + +use crate::favicon::Favicon; + +/// Options for building a [`Server`](crate::Server). +#[derive(Debug, Clone)] +pub struct Options { + /// Port to listen on. + pub port: u16, + /// Addresses to bind to. + pub bind_address: String, + + /// The server favicon. + pub favicon: Option<Favicon>, + /// The server MOTD. + pub motd: String, + + /// Whether the server should authenticate players. + pub online_mode: bool, + + /// The maximum view distance, which determines + /// how far players can see. + pub view_distance: u32, + + /// Maximum number of players to allow on the server. + pub max_players: u32, + + /// The default gamemode for new players. + pub default_gamemode: Gamemode, + + /// Proxy IP forwarding mode + pub proxy_mode: Option<ProxyMode>, + // HMAC key used with Velocity IP forwarding. + pub velocity_secret: String, + + /// Packet size threshold at which to compress data + pub compression_threshold: Option<usize>, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ProxyMode { + Bungeecord, + Velocity, +} diff --git a/feather/server/src/packet_handlers.rs b/feather/server/src/packet_handlers.rs new file mode 100644 index 000000000..b0452c96a --- /dev/null +++ b/feather/server/src/packet_handlers.rs @@ -0,0 +1,152 @@ +use base::{Position, Text}; +use common::{chat::ChatKind, Game}; +use ecs::{Entity, EntityRef, SysResult}; +use interaction::{ + handle_held_item_change, handle_interact_entity, handle_player_block_placement, + handle_player_digging, +}; +use protocol::{ + packets::{ + client, + server::{Animation, Hand}, + }, + ClientPlayPacket, +}; +use quill_common::components::Name; + +use crate::{NetworkId, Server}; + +mod entity_action; +mod interaction; +pub mod inventory; +mod movement; + +/// Handles a packet received from a client. +pub fn handle_packet( + game: &mut Game, + server: &mut Server, + player_id: Entity, + packet: ClientPlayPacket, +) -> SysResult { + let player = game.ecs.entity(player_id)?; + match packet { + ClientPlayPacket::PlayerPosition(packet) => { + movement::handle_player_position(server, player, packet) + } + ClientPlayPacket::PlayerPositionAndRotation(packet) => { + movement::handle_player_position_and_rotation(server, player, packet) + } + ClientPlayPacket::PlayerRotation(packet) => { + movement::handle_player_rotation(server, player, packet) + } + ClientPlayPacket::PlayerMovement(packet) => { + movement::handle_player_movement(player, packet) + } + + ClientPlayPacket::Animation(packet) => handle_animation(server, player, packet), + + ClientPlayPacket::ChatMessage(packet) => handle_chat_message(game, player, packet), + + ClientPlayPacket::PlayerDigging(packet) => { + handle_player_digging(game, server, packet, player_id) + } + + ClientPlayPacket::CreativeInventoryAction(packet) => { + inventory::handle_creative_inventory_action(player, packet, server) + } + ClientPlayPacket::ClickWindow(packet) => { + inventory::handle_click_window(server, player, packet) + } + + ClientPlayPacket::PlayerBlockPlacement(packet) => { + handle_player_block_placement(game, server, packet, player_id) + } + + ClientPlayPacket::HeldItemChange(packet) => handle_held_item_change(player, packet), + ClientPlayPacket::InteractEntity(packet) => { + handle_interact_entity(game, server, packet, player_id) + } + + ClientPlayPacket::ClientSettings(packet) => handle_client_settings(server, player, packet), + + ClientPlayPacket::PlayerAbilities(packet) => { + movement::handle_player_abilities(game, player_id, packet) + } + + ClientPlayPacket::EntityAction(packet) => { + entity_action::handle_entity_action(game, player_id, packet) + } + + ClientPlayPacket::TeleportConfirm(_) + | ClientPlayPacket::QueryBlockNbt(_) + | ClientPlayPacket::SetDifficulty(_) + | ClientPlayPacket::ClientStatus(_) + | ClientPlayPacket::TabComplete(_) + | ClientPlayPacket::WindowConfirmation(_) + | ClientPlayPacket::ClickWindowButton(_) + | ClientPlayPacket::CloseWindow(_) + | ClientPlayPacket::PluginMessage(_) + | ClientPlayPacket::EditBook(_) + | ClientPlayPacket::QueryEntityNbt(_) + | ClientPlayPacket::GenerateStructure(_) + | ClientPlayPacket::KeepAlive(_) + | ClientPlayPacket::LockDifficulty(_) + | ClientPlayPacket::VehicleMove(_) + | ClientPlayPacket::SteerBoat(_) + | ClientPlayPacket::PickItem(_) + | ClientPlayPacket::CraftRecipeRequest(_) + | ClientPlayPacket::SteerVehicle(_) + | ClientPlayPacket::SetDisplayedRecipe(_) + | ClientPlayPacket::SetRecipeBookState(_) + | ClientPlayPacket::NameItem(_) + | ClientPlayPacket::ResourcePackStatus(_) + | ClientPlayPacket::AdvancementTab(_) + | ClientPlayPacket::SelectTrade(_) + | ClientPlayPacket::SetBeaconEffect(_) + | ClientPlayPacket::UpdateCommandBlock(_) + | ClientPlayPacket::UpdateCommandBlockMinecart(_) + | ClientPlayPacket::UpdateJigsawBlock(_) + | ClientPlayPacket::UpdateStructureBlock(_) + | ClientPlayPacket::UpdateSign(_) + | ClientPlayPacket::Spectate(_) + | ClientPlayPacket::UseItem(_) => Ok(()), + } +} + +fn handle_animation( + server: &mut Server, + player: EntityRef, + packet: client::Animation, +) -> SysResult { + let pos = *player.get::<Position>()?; + let network_id = *player.get::<NetworkId>()?; + + let animation = match packet.hand { + Hand::Main => Animation::SwingMainArm, + Hand::Off => Animation::SwingOffhand, + }; + + server.broadcast_nearby_with(pos, |client| { + client.send_entity_animation(network_id, animation.clone()) + }); + Ok(()) +} + +fn handle_chat_message(game: &Game, player: EntityRef, packet: client::ChatMessage) -> SysResult { + let name = player.get::<Name>()?; + let message = Text::translate_with("chat.type.text", vec![name.to_string(), packet.message]); + game.broadcast_chat(ChatKind::PlayerChat, message); + Ok(()) +} + +fn handle_client_settings( + server: &mut Server, + player: EntityRef, + packet: client::ClientSettings, +) -> SysResult { + let network_id = *player.get::<NetworkId>()?; + server.broadcast_with(|client| { + client.send_player_model_flags(network_id, packet.displayed_skin_parts) + }); + Ok(()) +} diff --git a/feather/server/src/packet_handlers/entity_action.rs b/feather/server/src/packet_handlers/entity_action.rs new file mode 100644 index 000000000..8de3210c2 --- /dev/null +++ b/feather/server/src/packet_handlers/entity_action.rs @@ -0,0 +1,65 @@ +use common::Game; +use ecs::{Entity, SysResult}; +use protocol::packets::client::{EntityAction, EntityActionKind}; +use quill_common::{ + components::{Sneaking, Sprinting}, + events::{SneakEvent, SprintEvent}, +}; + +/// From [wiki](https://wiki.vg/Protocol#Entity_Action) +/// Sent by the client to indicate that it has performed certain actions: +/// *) sneaking (crouching), +/// *) sprinting, +/// *) exiting a bed, +/// *) jumping with a horse, +/// *) opening a horse's inventory while riding it. +/// +pub fn handle_entity_action(game: &mut Game, player: Entity, packet: EntityAction) -> SysResult { + match packet.action_id { + EntityActionKind::StartSneaking => { + let is_sneaking = game.ecs.get_mut::<Sneaking>(player)?.0; + if !is_sneaking { + game.ecs + .insert_entity_event(player, SneakEvent::new(true))?; + game.ecs.get_mut::<Sneaking>(player)?.0 = true; + } + } + EntityActionKind::StopSneaking => { + let is_sneaking = game.ecs.get_mut::<Sneaking>(player)?.0; + if is_sneaking { + game.ecs + .insert_entity_event(player, SneakEvent::new(false))?; + game.ecs.get_mut::<Sneaking>(player)?.0 = false; + } + } + EntityActionKind::LeaveBed => { + //TODO issue #423 + // Note that the leave bed packet is not sent if the server changes night to day + // and all players are kicked out of the bed. We have to seperatly send out + // a notice that bed state might have changed. + } + EntityActionKind::StartSprinting | EntityActionKind::StopSprinting => { + let start_sprinting = matches!(packet.action_id, EntityActionKind::StartSprinting); + let is_sprinting = game.ecs.get_mut::<Sprinting>(player)?.0; + if is_sprinting != start_sprinting { + game.ecs + .insert_entity_event(player, SprintEvent::new(start_sprinting))?; + game.ecs.get_mut::<Sprinting>(player)?.0 = start_sprinting; + } + } + EntityActionKind::StartHorseJump => { + //TODO issue #423 + } + EntityActionKind::StopJorseJump => { + //TODO issue #423 + } + EntityActionKind::OpenHorseInventory => { + //TODO issue #423 + } + EntityActionKind::StartElytraFlight => { + //TODO issue #423 + } + } + + Ok(()) +} diff --git a/feather/server/src/packet_handlers/interaction.rs b/feather/server/src/packet_handlers/interaction.rs new file mode 100644 index 000000000..1c6f69d9c --- /dev/null +++ b/feather/server/src/packet_handlers/interaction.rs @@ -0,0 +1,259 @@ +use crate::{ClientId, NetworkId, Server}; +use base::inventory::{SLOT_HOTBAR_OFFSET, SLOT_OFFHAND}; +use common::entities::player::HotbarSlot; +use common::interactable::InteractableRegistry; +use common::{Game, Window}; +use ecs::{Entity, EntityRef, SysResult}; +use libcraft_core::{BlockFace as LibcraftBlockFace, Hand}; +use libcraft_core::{InteractionType, Vec3f}; +use protocol::packets::client::{ + BlockFace, HeldItemChange, InteractEntity, InteractEntityKind, PlayerBlockPlacement, + PlayerDigging, PlayerDiggingStatus, +}; +use quill_common::{ + events::{BlockInteractEvent, BlockPlacementEvent, InteractEntityEvent}, + EntityId, +}; +/// Handles the player block placement packet. Currently just removes the block client side for the player. +pub fn handle_player_block_placement( + game: &mut Game, + _server: &mut Server, + packet: PlayerBlockPlacement, + player: Entity, +) -> SysResult { + let hand = match packet.hand { + 0 => Hand::Main, + 1 => Hand::Offhand, + _ => { + let client_id = game.ecs.get::<ClientId>(player).unwrap(); + + let client = _server.clients.get(*client_id).unwrap(); + + client.disconnect("Malformed Packet!"); + + anyhow::bail!( + "Player sent a malformed `PlayerBlockPlacement` packet. {:?}", + packet + ) + } + }; + + let face = match packet.face { + BlockFace::North => LibcraftBlockFace::North, + BlockFace::South => LibcraftBlockFace::South, + BlockFace::East => LibcraftBlockFace::East, + BlockFace::West => LibcraftBlockFace::West, + BlockFace::Top => LibcraftBlockFace::Top, + BlockFace::Bottom => LibcraftBlockFace::Bottom, + }; + + let cursor_position = Vec3f::new( + packet.cursor_position_x, + packet.cursor_position_y, + packet.cursor_position_z, + ); + + let block_kind = { + let result = game.block(packet.position); + match result { + Some(block) => block.kind(), + None => { + let client_id = game.ecs.get::<ClientId>(player).unwrap(); + + let client = _server.clients.get(*client_id).unwrap(); + + client.disconnect("Attempted to interact with an unloaded block!"); + + anyhow::bail!( + "Player attempted to interact with an unloaded block. {:?}", + packet + ) + } + } + }; + + let interactable_registry = game + .resources + .get::<InteractableRegistry>() + .expect("Failed to get the interactable registry"); + + if interactable_registry.is_registered(block_kind) { + // Handle this as a block interaction + let event = BlockInteractEvent { + hand, + location: packet.position.into(), + face, + cursor_position, + inside_block: packet.inside_block, + }; + + game.ecs.insert_entity_event(player, event)?; + } else { + // Handle this as a block placement + let event = BlockPlacementEvent { + hand, + location: packet.position.into(), + face, + cursor_position, + inside_block: packet.inside_block, + }; + + game.ecs.insert_entity_event(player, event)?; + } + + Ok(()) +} + +/// Handles the Player Digging packet sent for the following +/// actions: +/// * Breaking blocks. +/// * Dropping items. +/// * Shooting arrows. +/// * Eating. +/// * Swapping items between the main and off hand. +pub fn handle_player_digging( + game: &mut Game, + server: &mut Server, + packet: PlayerDigging, + player: Entity, +) -> SysResult { + log::trace!("Got player digging with status {:?}", packet.status); + match packet.status { + PlayerDiggingStatus::StartDigging | PlayerDiggingStatus::CancelDigging => { + game.break_block(packet.position); + Ok(()) + } + PlayerDiggingStatus::SwapItemInHand => { + let window = game.ecs.get::<Window>(player)?; + + let hotbar_slot = game.ecs.get::<HotbarSlot>(player)?.get(); + + let hotbar_index = SLOT_HOTBAR_OFFSET + hotbar_slot; + let offhand_index = SLOT_OFFHAND; + + { + let mut hotbar_item = window.item(hotbar_index)?; + let mut offhand_item = window.item(offhand_index)?; + + std::mem::swap(&mut *hotbar_item, &mut *offhand_item); + } + + let client_id = *game.ecs.get::<ClientId>(player)?; + let client = server.clients.get(client_id).unwrap(); + + client.send_window_items(&window); + + Ok(()) + } + _ => Ok(()), + } +} + +pub fn handle_interact_entity( + game: &mut Game, + _server: &mut Server, + packet: InteractEntity, + player: Entity, +) -> SysResult { + let target = { + let mut found_entity = None; + for (entity, &network_id) in game.ecs.query::<&NetworkId>().iter() { + if network_id.0 == packet.entity_id { + found_entity = Some(entity); + break; + } + } + + match found_entity { + None => { + let client_id = game.ecs.get::<ClientId>(player).unwrap(); + + let client = _server.clients.get(*client_id).unwrap(); + + client.disconnect("Interacted with an invalid entity!"); + + anyhow::bail!("Player attempted to interact with an invalid entity.") + } + Some(entity) => entity, + } + }; + + let event = match packet.kind { + InteractEntityKind::Attack => InteractEntityEvent { + target: EntityId(target.id() as u64), + ty: InteractionType::Attack, + target_pos: None, + hand: None, + sneaking: packet.sneaking, + }, + InteractEntityKind::Interact => InteractEntityEvent { + target: EntityId(target.id() as u64), + ty: InteractionType::Interact, + target_pos: None, + hand: None, + sneaking: packet.sneaking, + }, + InteractEntityKind::InteractAt { + target_x, + target_y, + target_z, + hand, + } => { + let hand = match hand { + 0 => Hand::Main, + 1 => Hand::Offhand, + _ => unreachable!(), + }; + + InteractEntityEvent { + target: EntityId(target.id() as u64), + ty: InteractionType::Attack, + target_pos: Some(Vec3f::new( + target_x as f32, + target_y as f32, + target_z as f32, + )), + hand: Some(hand), + sneaking: packet.sneaking, + } + } + }; + + game.ecs.insert_entity_event(player, event)?; + + Ok(()) +} + +pub fn handle_held_item_change(player: EntityRef, packet: HeldItemChange) -> SysResult { + let new_id = packet.slot as usize; + let mut slot = player.get_mut::<HotbarSlot>()?; + + log::trace!("Got player slot change from {} to {}", slot.get(), new_id); + + slot.set(new_id)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use common::Game; + use protocol::packets::client::HeldItemChange; + + use super::*; + + #[test] + fn held_item_change() { + let mut game = Game::new(); + let entity = game.ecs.spawn((HotbarSlot::new(0),)); + let player = game.ecs.entity(entity).unwrap(); + + let packet = HeldItemChange { slot: 8 }; + + handle_held_item_change(player, packet).unwrap(); + + assert_eq!( + *game.ecs.get::<HotbarSlot>(entity).unwrap(), + HotbarSlot::new(8) + ); + } +} diff --git a/feather/server/src/packet_handlers/inventory.rs b/feather/server/src/packet_handlers/inventory.rs new file mode 100644 index 000000000..48a397197 --- /dev/null +++ b/feather/server/src/packet_handlers/inventory.rs @@ -0,0 +1,84 @@ +use anyhow::bail; +use base::Gamemode; +use common::{window::BackingWindow, Window}; +use ecs::{EntityRef, SysResult}; +use protocol::packets::client::{ClickWindow, CreativeInventoryAction}; + +use crate::{ClientId, Server}; + +pub fn handle_creative_inventory_action( + player: EntityRef, + packet: CreativeInventoryAction, + server: &mut Server, +) -> SysResult { + if *player.get::<Gamemode>()? != Gamemode::Creative { + bail!("cannot use Creative Inventory Action outside of creative mode"); + } + + if packet.slot != -1 { + let window = player.get::<Window>()?; + if !matches!(window.inner(), BackingWindow::Player { .. }) { + bail!("cannot use Creative Inventory Action in external inventories"); + } + + window + .inner() + .set_item(packet.slot as usize, packet.clicked_item)?; + + // Sends the client updates about window changes. + // Is required to make delete inventory button reflect in-game. + let client_id = *player.get::<ClientId>()?; + let client = server.clients.get(client_id).unwrap(); + client.send_window_items(&window); + } + + Ok(()) +} + +pub fn handle_click_window( + server: &mut Server, + player: EntityRef, + packet: ClickWindow, +) -> SysResult { + let result = _handle_click_window(&player, &packet); + + let client = server.clients.get(*player.get::<ClientId>()?).unwrap(); + client.confirm_window_action( + packet.window_id, + packet.action_number as i16, + result.is_ok(), + ); + + let window = player.get::<Window>()?; + + if packet.slot >= 0 { + client.set_slot(packet.slot, &*window.item(packet.slot as usize)?); + } + client.set_cursor_slot(window.cursor_item()); + + client.send_window_items(&*window); + + result +} + +fn _handle_click_window(player: &EntityRef, packet: &ClickWindow) -> SysResult { + let mut window = player.get_mut::<Window>()?; + match packet.mode { + 0 => match packet.button { + 0 => window.left_click(packet.slot as usize)?, + 1 => window.right_click(packet.slot as usize)?, + _ => bail!("unrecgonized click"), + }, + 1 => window.shift_click(packet.slot as usize)?, + 5 => match packet.button { + 0 => window.begin_left_mouse_paint(), + 4 => window.begin_right_mouse_paint(), + 1 | 5 => window.add_paint_slot(packet.slot as usize)?, + 2 | 6 => window.end_paint()?, + _ => bail!("unrecognized paint operation"), + }, + _ => bail!("unsupported window click mode"), + }; + + Ok(()) +} diff --git a/feather/server/src/packet_handlers/movement.rs b/feather/server/src/packet_handlers/movement.rs new file mode 100644 index 000000000..27b03ee23 --- /dev/null +++ b/feather/server/src/packet_handlers/movement.rs @@ -0,0 +1,138 @@ +use base::Position; +use common::Game; +use ecs::{Entity, EntityRef, SysResult}; +use protocol::packets::client::{ + PlayerAbilities, PlayerMovement, PlayerPosition, PlayerPositionAndRotation, PlayerRotation, +}; +use quill_common::{ + components::{CreativeFlying, OnGround}, + events::CreativeFlyingEvent, +}; + +use crate::{ClientId, Server}; + +/// If a player has been teleported by the server, +/// we don't want to override their position if +/// we receive a movement packet before the client +/// is aware of the position update. +fn should_skip_movement(server: &Server, player: &EntityRef) -> SysResult<bool> { + if let Some(client) = server.clients.get(*player.get::<ClientId>()?) { + let server_position = *player.get::<Position>()?; + let client_position = client.client_known_position(); + if let Some(client_position) = client_position { + if client_position != server_position { + // Player has been teleported by the server. + // Don't override. + return Ok(true); + } + } + } + Ok(false) +} + +pub fn handle_player_movement(player: EntityRef, packet: PlayerMovement) -> SysResult { + player.get_mut::<OnGround>()?.0 = packet.on_ground; + Ok(()) +} + +pub fn handle_player_position( + server: &Server, + player: EntityRef, + packet: PlayerPosition, +) -> SysResult { + if should_skip_movement(server, &player)? { + return Ok(()); + } + let mut pos = player.get_mut::<Position>()?; + pos.x = packet.x; + pos.y = packet.feet_y; + pos.z = packet.z; + player.get_mut::<OnGround>()?.0 = packet.on_ground; + update_client_position(server, player, *pos)?; + Ok(()) +} + +pub fn handle_player_position_and_rotation( + server: &Server, + player: EntityRef, + packet: PlayerPositionAndRotation, +) -> SysResult { + if should_skip_movement(server, &player)? { + return Ok(()); + } + let mut pos = player.get_mut::<Position>()?; + pos.x = packet.x; + pos.y = packet.feet_y; + pos.z = packet.z; + pos.yaw = packet.yaw; + pos.pitch = packet.pitch; + player.get_mut::<OnGround>()?.0 = packet.on_ground; + update_client_position(server, player, *pos)?; + Ok(()) +} + +pub fn handle_player_rotation( + server: &Server, + player: EntityRef, + packet: PlayerRotation, +) -> SysResult { + if should_skip_movement(server, &player)? { + return Ok(()); + } + let mut pos = player.get_mut::<Position>()?; + pos.yaw = packet.yaw; + pos.pitch = packet.pitch; + player.get_mut::<OnGround>()?.0 = packet.on_ground; + update_client_position(server, player, *pos)?; + Ok(()) +} + +fn update_client_position(server: &Server, player: EntityRef, pos: Position) -> SysResult { + if let Some(client) = server.clients.get(*player.get::<ClientId>()?) { + client.set_client_known_position(pos); + } + Ok(()) +} + +/// Handles the PlayerAbilities packet that signals that the client wants to +/// start/stop flying (like in creative mode). +pub fn handle_player_abilities( + game: &mut Game, + player: Entity, + packet: PlayerAbilities, +) -> SysResult { + let flying = game.ecs.get_mut::<CreativeFlying>(player)?.0; + + match packet.flags { + 0 => { + // Flying stopped + if flying { + // Then it used to fly, therefor we need to trigger a event + // The vanilla client is actually quite good at keeping track of sending + // this packet only when there is a change, so this if should basically + // always trigger. + game.ecs + .insert_entity_event(player, CreativeFlyingEvent::new(false))?; + + game.ecs.get_mut::<CreativeFlying>(player)?.0 = false; + } + } + 2 => { + // Flying started + if !flying { + // Then it used to not fly, therefor we need to trigger a event. + // The vanilla client is actually quite good at keeping track of sending + // this packet only when there is a change, so this if should basically + // always trigger. + game.ecs + .insert_entity_event(player, CreativeFlyingEvent::new(true))?; + game.ecs.get_mut::<CreativeFlying>(player)?.0 = true; + } + } + err => { + log::error!("Got a unexpected flag in the PlayerAbilities packet. The value was: {} and not 0 or 2.", err) + } + } + + Ok(()) +} diff --git a/feather/server/src/player_count.rs b/feather/server/src/player_count.rs new file mode 100644 index 000000000..cf10dba17 --- /dev/null +++ b/feather/server/src/player_count.rs @@ -0,0 +1,105 @@ +use std::sync::{ + atomic::{AtomicU32, Ordering}, + Arc, +}; + +#[derive(Debug)] +pub struct MaxPlayersReached; + +/// Maintains the server player count. +/// +/// Can be cloned to create a new handle. +#[derive(Clone)] +pub struct PlayerCount { + inner: Arc<Inner>, +} + +impl PlayerCount { + pub fn new(max_players: u32) -> Self { + Self { + inner: Arc::new(Inner { + count: AtomicU32::new(0), + max_players, + }), + } + } + + pub fn try_add_player(&self) -> Result<(), MaxPlayersReached> { + loop { + let current_count = self.inner.count.load(Ordering::SeqCst); + let new_count = current_count + 1; + if new_count > self.inner.max_players { + return Err(MaxPlayersReached); + } + + if self + .inner + .count + .compare_exchange(current_count, new_count, Ordering::SeqCst, Ordering::SeqCst) + .is_ok() + { + return Ok(()); + } + } + } + + pub fn remove_player(&self) { + self.inner.count.fetch_sub(1, Ordering::SeqCst); + } + + pub fn get(&self) -> u32 { + self.inner.count.load(Ordering::Acquire) + } +} + +struct Inner { + count: AtomicU32, + max_players: u32, +} + +#[cfg(test)] +mod tests { + use crossbeam_utils::thread; + + use super::*; + + #[test] + fn try_add() { + let count = PlayerCount::new(1); + assert_eq!(count.get(), 0); + count.try_add_player().unwrap(); + assert_eq!(count.get(), 1); + + for _ in 0..10 { + count.try_add_player().unwrap_err(); + assert_eq!(count.get(), 1); + } + } + + #[test] + fn no_race_conditions() { + let threads = 8; + let players_per_thread = 100000; + let max_players = threads * players_per_thread / 2; + + let count = PlayerCount::new(max_players); + + let num_added = AtomicU32::new(0); + + thread::scope(|s| { + for _ in 0..threads { + s.spawn(|_| { + for _ in 0..players_per_thread { + if count.try_add_player().is_ok() { + num_added.fetch_add(1, Ordering::SeqCst); + } + } + }); + } + }) + .unwrap(); + + assert_eq!(num_added.load(Ordering::SeqCst), max_players); + assert_eq!(count.get(), max_players); + } +} diff --git a/feather/server/src/systems.rs b/feather/server/src/systems.rs new file mode 100644 index 000000000..e364dc591 --- /dev/null +++ b/feather/server/src/systems.rs @@ -0,0 +1,87 @@ +//! Systems linking a `Server` and a `Game`. + +mod block; +mod chat; +mod entity; +mod gamemode; +mod particle; +mod player_join; +mod player_leave; +mod plugin_message; +mod tablist; +pub mod view; + +use std::time::{Duration, Instant}; + +use common::Game; +use ecs::{SysResult, SystemExecutor}; +use quill_common::components::Name; + +use crate::{client::ClientId, Server}; + +/// Registers systems for a `Server` with a `Game`. +pub fn register(server: Server, game: &mut Game, systems: &mut SystemExecutor<Game>) { + game.insert_resource(server); + + player_join::register(systems); + systems + .group::<Server>() + .add_system(handle_packets) + .add_system(send_keepalives); + view::register(game, systems); + crate::chunk_subscriptions::register(systems); + player_leave::register(systems); + tablist::register(systems); + block::register(systems); + entity::register(game, systems); + chat::register(game, systems); + particle::register(systems); + plugin_message::register(systems); + gamemode::register(systems); + + systems.group::<Server>().add_system(tick_clients); +} + +/// Polls for packets received from clients +/// and handles them. +fn handle_packets(game: &mut Game, server: &mut Server) -> SysResult { + let mut packets = Vec::new(); + + for (player, &client_id) in game.ecs.query::<&ClientId>().iter() { + if let Some(client) = server.clients.get(client_id) { + for packet in client.received_packets() { + packets.push((player, packet)); + } + } + } + + for (player, packet) in packets { + if let Err(e) = crate::packet_handlers::handle_packet(game, server, player, packet) { + log::warn!( + "Failed to handle packet from '{}': {:?}", + &**game.ecs.get::<Name>(player)?, + e + ); + } + } + + Ok(()) +} + +/// Sends out keepalive packets at an interval. +fn send_keepalives(_game: &mut Game, server: &mut Server) -> SysResult { + let interval = Duration::from_secs(5); + if server.last_keepalive_time + interval < Instant::now() { + server.broadcast_keepalive(); + } + Ok(()) +} + +/// Ticks `Client`s. +fn tick_clients(_game: &mut Game, server: &mut Server) -> SysResult { + for client in server.clients.iter() { + client.tick(); + } + + Ok(()) +} diff --git a/feather/server/src/systems/block.rs b/feather/server/src/systems/block.rs new file mode 100644 index 000000000..5544da2bd --- /dev/null +++ b/feather/server/src/systems/block.rs @@ -0,0 +1,82 @@ +//! Implements block change broadcasting. +//! +//! # Bulk updates +//! The protocol provides three methods to change blocks +//! on the client: +//! * The `BlockChange` packet to update a single block. +//! * The `MultiBlockChange` packet to update multiple blocks +//! within a single chunk section. +//! * The `ChunkData` packet to overwrite entire chunk sections +//! at once. +//! +//! Feather is optimized for bulk block updates to cater to plugins +//! like WorldEdit. This module chooses the optimal packet from +//! the above three options to achieve ideal performance. + +use ahash::AHashMap; +use base::{chunk::SECTION_VOLUME, position, ChunkPosition, CHUNK_WIDTH}; +use common::{events::BlockChangeEvent, Game}; +use ecs::{SysResult, SystemExecutor}; + +use crate::Server; + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems + .group::<Server>() + .add_system(broadcast_block_changes); +} + +fn broadcast_block_changes(game: &mut Game, server: &mut Server) -> SysResult { + for (_, event) in game.ecs.query::<&BlockChangeEvent>().iter() { + broadcast_block_change(event, game, server); + } + Ok(()) +} + +/// Threshold at which to switch from block change to chunk +// overwrite packets. +const CHUNK_OVERWRITE_THRESHOLD: usize = SECTION_VOLUME / 2; + +fn broadcast_block_change(event: &BlockChangeEvent, game: &Game, server: &mut Server) { + if event.count() >= CHUNK_OVERWRITE_THRESHOLD { + broadcast_block_change_chunk_overwrite(event, game, server); + } else { + broadcast_block_change_simple(event, game, server); + } +} + +fn broadcast_block_change_chunk_overwrite( + event: &BlockChangeEvent, + game: &Game, + server: &mut Server, +) { + let mut sections: AHashMap<ChunkPosition, Vec<usize>> = AHashMap::new(); + for (chunk, section, _) in event.iter_affected_chunk_sections() { + sections.entry(chunk).or_default().push(section + 1); // + 1 to account for the void air chunk + } + + for (chunk_pos, sections) in sections { + let chunk = game.world.chunk_map().chunk_handle_at(chunk_pos); + if let Some(chunk) = chunk { + let position = position!( + (chunk_pos.x * CHUNK_WIDTH as i32) as f64, + 0.0, + (chunk_pos.z * CHUNK_WIDTH as i32) as f64, + ); + server.broadcast_nearby_with(position, |client| { + client.overwrite_chunk_sections(&chunk, sections.clone()); + }) + } + } +} + +fn broadcast_block_change_simple(event: &BlockChangeEvent, game: &Game, server: &mut Server) { + for pos in event.iter_changed_blocks() { + let new_block = game.block(pos); + if let Some(new_block) = new_block { + server.broadcast_nearby_with(pos.position(), |client| { + client.send_block_change(pos, new_block) + }); + } + } +} diff --git a/feather/server/src/systems/chat.rs b/feather/server/src/systems/chat.rs new file mode 100644 index 000000000..d19aa64ed --- /dev/null +++ b/feather/server/src/systems/chat.rs @@ -0,0 +1,58 @@ +use common::{chat::ChatPreference, ChatBox, Game}; +use ecs::{EntityBuilder, SysResult, SystemExecutor}; + +use crate::{ClientId, Server}; + +/// Marker component for the console entity. +struct Console; + +pub fn register(game: &mut Game, systems: &mut SystemExecutor<Game>) { + // Create the console entity so the console can receive messages + let mut console = EntityBuilder::new(); + console.add(Console).add(ChatBox::new(ChatPreference::All)); + + // We can use the raw spawn method because + // the console isn't a "normal" entity. + game.ecs.spawn(console.build()); + + systems.add_system(flush_console_chat_box); + systems.group::<Server>().add_system(flush_chat_boxes); + systems.group::<Server>().add_system(flush_title_chat_boxes); +} + +/// Flushes players' chat mailboxes and sends the needed packets. +fn flush_chat_boxes(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (&client_id, mailbox)) in game.ecs.query::<(&ClientId, &mut ChatBox)>().iter() { + if let Some(client) = server.clients.get(client_id) { + for message in mailbox.drain() { + client.send_chat_message(message); + } + } + } + + Ok(()) +} + +/// Prints chat messages to the console. +fn flush_console_chat_box(game: &mut Game) -> SysResult { + for (_, (_console, mailbox)) in game.ecs.query::<(&Console, &mut ChatBox)>().iter() { + for message in mailbox.drain() { + // TODO: properly display chat message + log::info!("{:?}", message.text()); + } + } + + Ok(()) +} + +fn flush_title_chat_boxes(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (&client_id, mailbox)) in game.ecs.query::<(&ClientId, &mut ChatBox)>().iter() { + if let Some(client) = server.clients.get(client_id) { + for message in mailbox.drain_titles() { + client.send_title(message); + } + } + } + + Ok(()) +} diff --git a/feather/server/src/systems/entity.rs b/feather/server/src/systems/entity.rs new file mode 100644 index 000000000..49aed542f --- /dev/null +++ b/feather/server/src/systems/entity.rs @@ -0,0 +1,109 @@ +//! Sends entity-related packets to clients. +//! Spawn packets, position updates, equipment, animations, etc. + +use base::{ + metadata::{EntityBitMask, Pose, META_INDEX_ENTITY_BITMASK, META_INDEX_POSE}, + EntityMetadata, Position, +}; +use common::Game; +use ecs::{SysResult, SystemExecutor}; +use quill_common::{ + components::{OnGround, Sprinting}, + events::{SneakEvent, SprintEvent}, +}; + +use crate::{ + entities::{PreviousOnGround, PreviousPosition}, + NetworkId, Server, +}; + +mod spawn_packet; + +pub fn register(game: &mut Game, systems: &mut SystemExecutor<Game>) { + spawn_packet::register(game, systems); + systems + .group::<Server>() + .add_system(send_entity_movement) + .add_system(send_entity_sneak_metadata) + .add_system(send_entity_sprint_metadata); +} + +/// Sends entity movement packets. +fn send_entity_movement(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (&position, prev_position, &on_ground, &network_id, prev_on_ground)) in game + .ecs + .query::<( + &Position, + &mut PreviousPosition, + &OnGround, + &NetworkId, + &mut PreviousOnGround, + )>() + .iter() + { + if position != prev_position.0 { + server.broadcast_nearby_with(position, |client| { + client.update_entity_position( + network_id, + position, + *prev_position, + on_ground, + *prev_on_ground, + ); + }); + prev_position.0 = position; + } + if on_ground != prev_on_ground.0 { + prev_on_ground.0 = on_ground; + } + } + Ok(()) +} + +/// Sends [SendEntityMetadata](protocol::packets::server::play::SendEntityMetadata) packet for when an entity is sneaking. +fn send_entity_sneak_metadata(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (&position, &SneakEvent { is_sneaking }, is_sprinting, &network_id)) in game + .ecs + .query::<(&Position, &SneakEvent, &Sprinting, &NetworkId)>() + .iter() + { + let mut metadata = EntityMetadata::entity_base(); + let mut bit_mask = EntityBitMask::empty(); + + // The Entity can sneak and sprint at the same time, what happens is that when it stops sneaking you immediately start running again. + bit_mask.set(EntityBitMask::CROUCHED, is_sneaking); + bit_mask.set(EntityBitMask::SPRINTING, is_sprinting.0); + metadata.set(META_INDEX_ENTITY_BITMASK, bit_mask.bits()); + + if is_sneaking { + metadata.set(META_INDEX_POSE, Pose::Sneaking); + } else { + metadata.set(META_INDEX_POSE, Pose::Standing); + } + + server.broadcast_nearby_with(position, |client| { + client.send_entity_metadata(network_id, metadata.clone()); + }); + } + Ok(()) +} + +/// Sends [SendEntityMetadata](protocol::packets::server::play::SendEntityMetadata) packet for when an entity is sprinting. +fn send_entity_sprint_metadata(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (&position, &SprintEvent { is_sprinting }, &network_id)) in game + .ecs + .query::<(&Position, &SprintEvent, &NetworkId)>() + .iter() + { + let mut metadata = EntityMetadata::entity_base(); + let mut bit_mask = EntityBitMask::empty(); + + bit_mask.set(EntityBitMask::SPRINTING, is_sprinting); + metadata.set(META_INDEX_ENTITY_BITMASK, bit_mask.bits()); + + server.broadcast_nearby_with(position, |client| { + client.send_entity_metadata(network_id, metadata.clone()); + }); + } + Ok(()) +} diff --git a/feather/server/src/systems/entity/spawn_packet.rs b/feather/server/src/systems/entity/spawn_packet.rs new file mode 100644 index 000000000..23cb0b523 --- /dev/null +++ b/feather/server/src/systems/entity/spawn_packet.rs @@ -0,0 +1,126 @@ +use ahash::AHashSet; +use anyhow::Context; +use base::Position; +use common::{ + events::{ChunkCrossEvent, ViewUpdateEvent}, + Game, +}; +use ecs::{SysResult, SystemExecutor}; +use quill_common::events::{EntityCreateEvent, EntityRemoveEvent}; + +use crate::{entities::SpawnPacketSender, ClientId, NetworkId, Server}; + +pub fn register(_game: &mut Game, systems: &mut SystemExecutor<Game>) { + systems + .group::<Server>() + .add_system(update_visible_entities) + .add_system(send_entities_when_created) + .add_system(unload_entities_when_removed) + .add_system(update_entities_on_chunk_cross); +} + +/// System to spawn entities on clients when they become visible, +/// and despawn entities when they become invisible, based on the client's view. +pub fn update_visible_entities(game: &mut Game, server: &mut Server) -> SysResult { + for (player, (event, &client_id)) in game.ecs.query::<(&ViewUpdateEvent, &ClientId)>().iter() { + let client = match server.clients.get(client_id) { + Some(client) => client, + None => continue, + }; + + // Send newly visible entities + for &new_chunk in &event.new_chunks { + for &entity_id in game.chunk_entities.entities_in_chunk(new_chunk) { + if entity_id != player { + let entity_ref = game.ecs.entity(entity_id)?; + if let Ok(spawn_packet) = entity_ref.get::<SpawnPacketSender>() { + spawn_packet + .send(&entity_ref, client) + .context("failed to send spawn packet")?; + } + } + } + } + + // Unload entities no longer visible + for &old_chunk in &event.old_chunks { + for &entity_id in game.chunk_entities.entities_in_chunk(old_chunk) { + if entity_id != player { + if let Ok(network_id) = game.ecs.get::<NetworkId>(entity_id) { + client.unload_entity(*network_id); + } + } + } + } + } + + Ok(()) +} + +/// System to send an entity to clients when it is created. +fn send_entities_when_created(game: &mut Game, server: &mut Server) -> SysResult { + for (entity, (_event, &position, spawn_packet)) in game + .ecs + .query::<(&EntityCreateEvent, &Position, &SpawnPacketSender)>() + .iter() + { + let entity_ref = game.ecs.entity(entity)?; + server.broadcast_nearby_with(position, |client| { + spawn_packet + .send(&entity_ref, client) + .expect("failed to create spawn packet") + }); + } + + Ok(()) +} + +/// System to unload an entity on clients when it is removed. +fn unload_entities_when_removed(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (_event, &position, &network_id)) in game + .ecs + .query::<(&EntityRemoveEvent, &Position, &NetworkId)>() + .iter() + { + server.broadcast_nearby_with(position, |client| client.unload_entity(network_id)); + } + + Ok(()) +} + +/// System to send/unsend entities on clients when the entity changes chunks. +fn update_entities_on_chunk_cross(game: &mut Game, server: &mut Server) -> SysResult { + for (entity, (event, spawn_packet, &network_id)) in game + .ecs + .query::<(&ChunkCrossEvent, &SpawnPacketSender, &NetworkId)>() + .iter() + { + let old_clients: AHashSet<_> = server + .chunk_subscriptions + .subscriptions_for(event.old_chunk) + .iter() + .copied() + .collect(); + let new_clients: AHashSet<_> = server + .chunk_subscriptions + .subscriptions_for(event.new_chunk) + .iter() + .copied() + .collect(); + + for left_client in old_clients.difference(&new_clients) { + if let Some(client) = server.clients.get(*left_client) { + client.unload_entity(network_id); + } + } + + let entity_ref = game.ecs.entity(entity)?; + for send_client in new_clients.difference(&old_clients) { + if let Some(client) = server.clients.get(*send_client) { + spawn_packet.send(&entity_ref, client)?; + } + } + } + + Ok(()) +} diff --git a/feather/server/src/systems/gamemode.rs b/feather/server/src/systems/gamemode.rs new file mode 100644 index 000000000..8c9581bd1 --- /dev/null +++ b/feather/server/src/systems/gamemode.rs @@ -0,0 +1,194 @@ +use base::anvil::player::PlayerAbilities; +use base::Gamemode; +use common::Game; +use ecs::{SysResult, SystemExecutor}; +use quill_common::components::{ + CanBuild, CanCreativeFly, CreativeFlying, CreativeFlyingSpeed, Instabreak, Invulnerable, + PreviousGamemode, WalkSpeed, +}; +use quill_common::events::{ + BuildingAbilityEvent, CreativeFlyingEvent, FlyingAbilityEvent, GamemodeEvent, InstabreakEvent, + InvulnerabilityEvent, +}; + +use crate::{ClientId, Server}; + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems.group::<Server>().add_system(gamemode_change); +} + +fn gamemode_change(game: &mut Game, server: &mut Server) -> SysResult { + let mut may_fly_changes = Vec::new(); + let mut fly_changes = Vec::new(); + let mut instabreak_changes = Vec::new(); + let mut build_changes = Vec::new(); + let mut invulnerability_changes = Vec::new(); + for ( + entity, + ( + event, + &client_id, + &walk_speed, + &fly_speed, + mut may_fly, + mut is_flying, + mut instabreak, + mut may_build, + mut invulnerable, + gamemode, + prev_gamemode, + ), + ) in game + .ecs + .query::<( + &GamemodeEvent, + &ClientId, + &WalkSpeed, + &CreativeFlyingSpeed, + &mut CanCreativeFly, + &mut CreativeFlying, + &mut Instabreak, + &mut CanBuild, + &mut Invulnerable, + &mut Gamemode, + &mut PreviousGamemode, + )>() + .iter() + { + if **event == *gamemode { + continue; + } + *prev_gamemode = PreviousGamemode(Some(*gamemode)); + *gamemode = **event; + match gamemode { + Gamemode::Creative => { + if !**instabreak { + instabreak_changes.push((entity, true)); + instabreak.0 = true; + } + if !**may_fly { + may_fly_changes.push((entity, true)); + may_fly.0 = true; + } + if !**may_build { + build_changes.push((entity, true)); + may_build.0 = true; + } + if !**invulnerable { + invulnerability_changes.push((entity, true)); + invulnerable.0 = true; + } + } + Gamemode::Spectator => { + if !**is_flying { + fly_changes.push((entity, true)); + is_flying.0 = true; + } + if **instabreak { + instabreak_changes.push((entity, false)); + instabreak.0 = false; + } + if !**may_fly { + may_fly_changes.push((entity, true)); + may_fly.0 = true; + } + if **may_build { + build_changes.push((entity, false)); + may_build.0 = false; + } + if !**invulnerable { + invulnerability_changes.push((entity, true)); + invulnerable.0 = true; + } + } + Gamemode::Survival => { + if **is_flying { + fly_changes.push((entity, false)); + is_flying.0 = false; + } + if **instabreak { + instabreak_changes.push((entity, false)); + instabreak.0 = false; + } + if **may_fly { + may_fly_changes.push((entity, false)); + may_fly.0 = false; + } + if !**may_build { + build_changes.push((entity, true)); + may_build.0 = true; + } + if **invulnerable { + invulnerability_changes.push((entity, false)); + invulnerable.0 = false; + } + } + Gamemode::Adventure => { + if **is_flying { + fly_changes.push((entity, false)); + is_flying.0 = false; + } + if **instabreak { + instabreak_changes.push((entity, false)); + instabreak.0 = false; + } + if **may_fly { + may_fly_changes.push((entity, false)); + may_fly.0 = false; + } + if **may_build { + build_changes.push((entity, false)); + may_build.0 = false; + } + if **invulnerable { + invulnerability_changes.push((entity, false)); + invulnerable.0 = false; + } + } + } + server + .clients + .get(client_id) + .unwrap() + .change_gamemode(**event); + server + .clients + .get(client_id) + .unwrap() + .send_abilities(&PlayerAbilities { + walk_speed, + fly_speed, + may_fly: *may_fly, + is_flying: *is_flying, + may_build: *may_build, + instabreak: *instabreak, + invulnerable: *invulnerable, + }); + } + for (entity, flying) in fly_changes { + game.ecs + .insert_entity_event(entity, CreativeFlyingEvent::new(flying)) + .unwrap(); + } + for (entity, instabreak) in instabreak_changes { + game.ecs + .insert_entity_event(entity, InstabreakEvent(instabreak)) + .unwrap(); + } + for (entity, may_fly) in may_fly_changes { + game.ecs + .insert_entity_event(entity, FlyingAbilityEvent(may_fly)) + .unwrap(); + } + for (entity, build) in build_changes { + game.ecs + .insert_entity_event(entity, BuildingAbilityEvent(build)) + .unwrap(); + } + for (entity, invulnerable) in invulnerability_changes { + game.ecs + .insert_entity_event(entity, InvulnerabilityEvent(invulnerable)) + .unwrap(); + } + Ok(()) +} diff --git a/feather/server/src/systems/particle.rs b/feather/server/src/systems/particle.rs new file mode 100644 index 000000000..a30cdd0cc --- /dev/null +++ b/feather/server/src/systems/particle.rs @@ -0,0 +1,26 @@ +use crate::Server; +use base::{Particle, Position}; +use common::Game; +use ecs::{SysResult, SystemExecutor}; + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems.group::<Server>().add_system(send_particle_packets); +} + +fn send_particle_packets(game: &mut Game, server: &mut Server) -> SysResult { + let mut entities = Vec::new(); + + for (entity, (&particle, &position)) in game.ecs.query::<(&Particle, &Position)>().iter() { + server.broadcast_nearby_with(position, |client| { + client.send_particle(&particle, &position); + }); + + entities.push(entity); + } + + for entity in entities { + game.ecs.despawn(entity)?; + } + + Ok(()) +} diff --git a/feather/server/src/systems/player_join.rs b/feather/server/src/systems/player_join.rs new file mode 100644 index 000000000..f8e01b195 --- /dev/null +++ b/feather/server/src/systems/player_join.rs @@ -0,0 +1,162 @@ +use libcraft_items::InventorySlot; +use log::debug; + +use base::anvil::player::PlayerAbilities; +use base::{Gamemode, Inventory, ItemStack, Position, Text}; +use common::{ + chat::{ChatKind, ChatPreference}, + entities::player::HotbarSlot, + view::View, + window::BackingWindow, + ChatBox, Game, Window, +}; +use ecs::{SysResult, SystemExecutor}; +use quill_common::components::{ + CanBuild, CanCreativeFly, CreativeFlying, CreativeFlyingSpeed, Health, Instabreak, + Invulnerable, PreviousGamemode, WalkSpeed, +}; +use quill_common::events::GamemodeEvent; +use quill_common::{components::Name, entity_init::EntityInit}; + +use crate::{ClientId, NetworkId, Server}; + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems.group::<Server>().add_system(poll_new_players); +} + +/// Polls for new clients and sends them the necessary packets +/// to join the game. +fn poll_new_players(game: &mut Game, server: &mut Server) -> SysResult { + for client_id in server.accept_new_players() { + accept_new_player(game, server, client_id)?; + } + Ok(()) +} + +fn accept_new_player(game: &mut Game, server: &mut Server, client_id: ClientId) -> SysResult { + let client = server.clients.get_mut(client_id).unwrap(); + let player_data = game.world.load_player_data(client.uuid()); + let mut builder = game.create_entity_builder( + player_data + .as_ref() + .map(|data| Position { + x: data.animal.base.position[0], + y: data.animal.base.position[1], + z: data.animal.base.position[2], + yaw: data.animal.base.rotation[0], + pitch: data.animal.base.rotation[1], + }) + .unwrap_or_default(), + EntityInit::Player, + ); + client.set_network_id(*builder.get::<NetworkId>().unwrap()); + + if player_data.is_err() { + debug!("{} is a new player", client.username()) + } + let gamemode = player_data + .as_ref() + .map(|data| Gamemode::from_id(data.gamemode as u8).expect("Unsupported gamemode")) + .unwrap_or(server.options.default_gamemode); + let previous_gamemode = player_data + .as_ref() + .map(|data| PreviousGamemode::from_id(data.previous_gamemode as i8)) + .unwrap_or(PreviousGamemode(None)); + + client.send_join_game(gamemode, previous_gamemode); + client.send_brand(); + + // Abilities + let abilities = player_abilities_or_default( + player_data.as_ref().map(|data| data.abilities.clone()).ok(), + gamemode, + ); + client.send_abilities(&abilities); + + let hotbar_slot = player_data + .as_ref() + .map(|data| HotbarSlot::new(data.held_item as usize)) + .unwrap_or_else(|_e| HotbarSlot::new(0)); + client.set_hotbar_slot(hotbar_slot.get() as u8); + + let inventory = Inventory::player(); + let window = Window::new(BackingWindow::Player { + player: inventory.new_handle(), + }); + if let Ok(data) = player_data.as_ref() { + for inventory_slot in data.inventory.iter() { + let net_slot = inventory_slot.convert_index(); + let slot = match net_slot { + Some(slot) => slot, + None => { + log::error!("Failed to convert saved slot into network slot"); + continue; + } + }; + + // This can't fail since the earlier match filters out all incorrect indexes. + window + .set_item(slot, InventorySlot::Filled(ItemStack::from(inventory_slot))) + .unwrap(); + } + } + + client.send_window_items(&window); + + builder + .add(client_id) + .add(View::new( + Position::default().chunk(), + server.options.view_distance, + )) + .add(gamemode) + .add(previous_gamemode) + .add(Name::new(client.username())) + .add(client.uuid()) + .add(client.profile().to_vec()) + .add(ChatBox::new(ChatPreference::All)) + .add(inventory) + .add(window) + .add(hotbar_slot) + .add(Health( + player_data + .as_ref() + .map(|data| data.animal.health) + .unwrap_or(20.0), + )) + .add(abilities.walk_speed) + .add(abilities.fly_speed) + .add(abilities.is_flying) + .add(abilities.may_fly) + .add(abilities.may_build) + .add(abilities.instabreak) + .add(abilities.invulnerable); + + builder.add(GamemodeEvent(gamemode)); + + game.spawn_entity(builder); + + broadcast_player_join(game, client.username()); + + Ok(()) +} + +fn broadcast_player_join(game: &mut Game, username: &str) { + let message = Text::translate_with("multiplayer.player.joined", vec![username.to_owned()]); + game.broadcast_chat(ChatKind::System, message); +} + +fn player_abilities_or_default( + data: Option<PlayerAbilities>, + gamemode: Gamemode, +) -> PlayerAbilities { + data.unwrap_or(PlayerAbilities { + walk_speed: WalkSpeed::default(), + fly_speed: CreativeFlyingSpeed::default(), + may_fly: CanCreativeFly(matches!(gamemode, Gamemode::Creative | Gamemode::Spectator)), + is_flying: CreativeFlying(matches!(gamemode, Gamemode::Spectator)), + may_build: CanBuild(!matches!(gamemode, Gamemode::Adventure)), + instabreak: Instabreak(matches!(gamemode, Gamemode::Creative)), + invulnerable: Invulnerable(matches!(gamemode, Gamemode::Creative | Gamemode::Spectator)), + }) +} diff --git a/feather/server/src/systems/player_leave.rs b/feather/server/src/systems/player_leave.rs new file mode 100644 index 000000000..8034d0b0a --- /dev/null +++ b/feather/server/src/systems/player_leave.rs @@ -0,0 +1,153 @@ +use num_traits::cast::ToPrimitive; + +use base::anvil::entity::{AnimalData, BaseEntityData}; +use base::anvil::player::{InventorySlot, PlayerAbilities, PlayerData}; +use base::{Gamemode, Inventory, Position, Text}; +use common::entities::player::HotbarSlot; +use common::{chat::ChatKind, Game}; +use ecs::{SysResult, SystemExecutor}; +use quill_common::components::{ + CanBuild, CanCreativeFly, CreativeFlying, CreativeFlyingSpeed, Health, Instabreak, + Invulnerable, Name, PreviousGamemode, WalkSpeed, +}; + +use crate::{ClientId, Server}; + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems + .group::<Server>() + .add_system(remove_disconnected_clients); +} + +fn remove_disconnected_clients(game: &mut Game, server: &mut Server) -> SysResult { + let mut entities_to_remove = Vec::new(); + for ( + player, + ( + &client_id, + name, + position, + gamemode, + previous_gamemode, + health, + walk_speed, + fly_speed, + can_fly, + is_flying, + can_build, + instabreak, + invulnerable, + hotbar_slot, + inventory, + ), + ) in game + .ecs + .query::<( + &ClientId, + &Name, + &Position, + &Gamemode, + &PreviousGamemode, + &Health, + &WalkSpeed, + &CreativeFlyingSpeed, + &CanCreativeFly, + &CreativeFlying, + &CanBuild, + &Instabreak, + &Invulnerable, + &HotbarSlot, + &Inventory, + )>() + .iter() + { + let client = server.clients.get(client_id).unwrap(); + if client.is_disconnected() { + entities_to_remove.push(player); + broadcast_player_leave(game, name); + game.world + .save_player_data( + client.uuid(), + &create_player_data( + *position, + *gamemode, + *previous_gamemode, + *health, + PlayerAbilities { + walk_speed: *walk_speed, + fly_speed: *fly_speed, + may_fly: *can_fly, + is_flying: *is_flying, + may_build: *can_build, + instabreak: *instabreak, + invulnerable: *invulnerable, + }, + *hotbar_slot, + inventory, + ), + ) + .unwrap_or_else(|e| panic!("Couldn't save data for {}: {}", client.username(), e)); + server.remove_client(client_id); + } + } + + for player in entities_to_remove { + game.remove_entity(player)?; + } + + Ok(()) +} + +fn broadcast_player_leave(game: &Game, username: &Name) { + let message = Text::translate_with("multiplayer.player.left", vec![username.to_string()]); + game.broadcast_chat(ChatKind::System, message); +} + +fn create_player_data( + position: Position, + gamemode: Gamemode, + previous_gamemode: PreviousGamemode, + health: Health, + abilities: PlayerAbilities, + hotbar_slot: HotbarSlot, + inventory: &Inventory, +) -> PlayerData { + PlayerData { + animal: AnimalData { + base: BaseEntityData { + position: [position.x, position.y, position.z].into(), + rotation: [position.yaw, position.pitch].into(), + velocity: [0.0, 0.0, 0.0].into(), + }, + health: *health, + }, + gamemode: gamemode.to_i32().unwrap(), + previous_gamemode: previous_gamemode.id() as i32, + inventory: inventory + .to_vec() + .iter() + .enumerate() + // Here we filter out all empty slots. + .filter_map(|(slot, item)| { + match item { + libcraft_items::InventorySlot::Filled(item) => { + let res = InventorySlot::from_network_index(slot, item); + match res { + Some(i) => Some(i), + None => { + log::error!("Failed to convert the slot into anvil format."); + None + } + } + } + libcraft_items::InventorySlot::Empty => { + // Empty items are filtered out. + None + } + } + }) + .collect(), + held_item: hotbar_slot.get() as i32, + abilities, + } +} diff --git a/feather/server/src/systems/plugin_message.rs b/feather/server/src/systems/plugin_message.rs new file mode 100644 index 000000000..3b426cf3b --- /dev/null +++ b/feather/server/src/systems/plugin_message.rs @@ -0,0 +1,19 @@ +use crate::{ClientId, Server}; +use common::{events::PluginMessageEvent, Game}; +use ecs::{SysResult, SystemExecutor}; + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems + .group::<Server>() + .add_system(send_plugin_message_packets); +} + +fn send_plugin_message_packets(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (&client_id, event)) in game.ecs.query::<(&ClientId, &PluginMessageEvent)>().iter() { + if let Some(client) = server.clients.get(client_id) { + client.send_plugin_message(event.channel.clone(), event.data.clone()); + } + } + + Ok(()) +} diff --git a/feather/server/src/systems/tablist.rs b/feather/server/src/systems/tablist.rs new file mode 100644 index 000000000..047ac19c6 --- /dev/null +++ b/feather/server/src/systems/tablist.rs @@ -0,0 +1,72 @@ +//! Sends tablist info to clients via the Player Info packet. + +use uuid::Uuid; + +use base::{Gamemode, ProfileProperty}; +use common::Game; +use ecs::{SysResult, SystemExecutor}; +use quill_common::events::{EntityRemoveEvent, GamemodeEvent, PlayerJoinEvent}; +use quill_common::{components::Name, entities::Player}; + +use crate::{ClientId, Server}; + +pub fn register(systems: &mut SystemExecutor<Game>) { + systems + .group::<Server>() + .add_system(remove_tablist_players) + .add_system(add_tablist_players) + .add_system(change_tablist_player_gamemode); +} + +fn remove_tablist_players(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (_event, _player, &uuid)) in game + .ecs + .query::<(&EntityRemoveEvent, &Player, &Uuid)>() + .iter() + { + server.broadcast_with(|client| client.remove_tablist_player(uuid)); + } + Ok(()) +} + +fn add_tablist_players(game: &mut Game, server: &mut Server) -> SysResult { + for (player, (_, &client_id, &uuid, name, &gamemode, profile)) in game + .ecs + .query::<( + &PlayerJoinEvent, + &ClientId, + &Uuid, + &Name, + &Gamemode, + &Vec<ProfileProperty>, + )>() + .iter() + { + // Add this player to other players' tablists + server.broadcast_with(|client| { + client.add_tablist_player(uuid, name.to_string(), profile, gamemode) + }); + + // Add other players to this player's tablist + for (other_player, (&uuid, name, &gamemode, profile)) in game + .ecs + .query::<(&Uuid, &Name, &Gamemode, &Vec<ProfileProperty>)>() + .iter() + { + if let Some(client) = server.clients.get(client_id) { + if other_player != player { + client.add_tablist_player(uuid, name.to_string(), profile, gamemode); + } + } + } + } + Ok(()) +} + +fn change_tablist_player_gamemode(game: &mut Game, server: &mut Server) -> SysResult { + for (_, (event, &uuid)) in game.ecs.query::<(&GamemodeEvent, &Uuid)>().iter() { + // Change this player's gamemode in players' tablists + server.broadcast_with(|client| client.change_player_tablist_gamemode(uuid, **event)); + } + Ok(()) +} diff --git a/feather/server/src/systems/view.rs b/feather/server/src/systems/view.rs new file mode 100644 index 000000000..5d43a3eee --- /dev/null +++ b/feather/server/src/systems/view.rs @@ -0,0 +1,112 @@ +//! Sends and unloads entities and chunks for a client. +//! +//! The entities and chunks visible to each client are +//! determined based on the player's [`common::view::View`]. + +use ahash::AHashMap; +use base::{ChunkPosition, Position}; +use common::{ + events::{ChunkLoadEvent, ViewUpdateEvent}, + Game, +}; +use ecs::{Entity, SysResult, SystemExecutor}; + +use crate::{Client, ClientId, Server}; + +pub fn register(_game: &mut Game, systems: &mut SystemExecutor<Game>) { + systems + .group::<Server>() + .add_system(send_new_chunks) + .add_system(send_loaded_chunks); +} + +/// Stores the players waiting on chunks that are currently being loaded. +#[derive(Default)] +pub struct WaitingChunks(AHashMap<ChunkPosition, Vec<Entity>>); + +impl WaitingChunks { + pub fn drain_players_waiting_for(&mut self, chunk: ChunkPosition) -> Vec<Entity> { + self.0.remove(&chunk).unwrap_or_default() + } + + pub fn insert(&mut self, player: Entity, chunk: ChunkPosition) { + self.0.entry(chunk).or_default().push(player); + } +} + +fn send_new_chunks(game: &mut Game, server: &mut Server) -> SysResult { + for (player, (&client_id, event, &position)) in game + .ecs + .query::<(&ClientId, &ViewUpdateEvent, &Position)>() + .iter() + { + // As ecs removes the client one tick after it gets removed here, it can + // happen that a client is still listed in the ecs but actually removed here so + // we need to check if the client is actually still there. + if let Some(client) = server.clients.get(client_id) { + client.update_own_chunk(event.new_view.center()); + update_chunks( + game, + player, + client, + event, + position, + &mut server.waiting_chunks, + )?; + } + } + Ok(()) +} + +fn update_chunks( + game: &Game, + player: Entity, + client: &Client, + event: &ViewUpdateEvent, + position: Position, + waiting_chunks: &mut WaitingChunks, +) -> SysResult { + // Send chunks that are in the new view but not the old view. + for &pos in &event.new_chunks { + if let Some(chunk) = game.world.chunk_map().chunk_handle_at(pos) { + client.send_chunk(&chunk); + } else { + waiting_chunks.insert(player, pos); + } + } + + // Unsend the chunks that are in the old view but not the new view. + for &pos in &event.old_chunks { + client.unload_chunk(pos); + } + + spawn_client_if_needed(client, position); + + Ok(()) +} + +/// Sends newly loaded chunks to players currently +/// waiting for those chunks to load. +fn send_loaded_chunks(game: &mut Game, server: &mut Server) -> SysResult { + for (_, event) in game.ecs.query::<&ChunkLoadEvent>().iter() { + for player in server + .waiting_chunks + .drain_players_waiting_for(event.position) + { + if let Ok(client_id) = game.ecs.get::<ClientId>(player) { + if let Some(client) = server.clients.get(*client_id) { + client.send_chunk(&event.chunk); + spawn_client_if_needed(client, *game.ecs.get::<Position>(player)?); + } + } + } + } + Ok(()) +} + +fn spawn_client_if_needed(client: &Client, pos: Position) { + if !client.knows_own_position() && client.known_chunks() >= 9 * 9 { + log::debug!("Sent all chunks to {}; now spawning", client.username()); + client.update_own_position(pos); + } +} diff --git a/feather/utils/Cargo.toml b/feather/utils/Cargo.toml new file mode 100644 index 000000000..a8e34a1ab --- /dev/null +++ b/feather/utils/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "feather-utils" +version = "0.1.0" +authors = [ "caelunshun <caelunshun@gmail.com>" ] +edition = "2018" + +[dependencies] + +[dev-dependencies] diff --git a/feather/utils/src/lib.rs b/feather/utils/src/lib.rs new file mode 100644 index 000000000..ead41e358 --- /dev/null +++ b/feather/utils/src/lib.rs @@ -0,0 +1,9 @@ +//! Assorted utilities not directly related to Minecraft/Feather. + +/// Swap-removes an item from a vector by equality. +pub fn vec_remove_item<T: PartialEq>(vec: &mut Vec<T>, item: &T) { + let index = vec.iter().position(|x| x == item); + if let Some(index) = index { + vec.swap_remove(index); + } +} diff --git a/feather/worldgen/Cargo.toml b/feather/worldgen/Cargo.toml new file mode 100644 index 000000000..ac61648e3 --- /dev/null +++ b/feather/worldgen/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "feather-worldgen" +version = "0.6.0" +authors = [ "caelunshun <caelunshun@gmail.com>" ] +edition = "2018" + +[dependencies] +base = { path = "../base", package = "feather-base" } +bitvec = "0.21" +log = "0.4" +num-traits = "0.2" +once_cell = "1" +rand = "0.7" +rand_xorshift = "0.2" +simdnoise = { git = "https://github.com/jackmott/rust-simd-noise", rev = "3a4f3e6" } # needed for https://github.com/jackmott/rust-simd-noise/pull/31 and https://github.com/jackmott/rust-simd-noise/pull/36 +smallvec = "1" +strum = "0.21" + +[dev-dependencies] +approx = "0.3" diff --git a/server/src/worldgen/biomes/distorted_voronoi.rs b/feather/worldgen/src/biomes/distorted_voronoi.rs similarity index 66% rename from server/src/worldgen/biomes/distorted_voronoi.rs rename to feather/worldgen/src/biomes/distorted_voronoi.rs index e8fda1ba7..20f3d31d1 100644 --- a/server/src/worldgen/biomes/distorted_voronoi.rs +++ b/feather/worldgen/src/biomes/distorted_voronoi.rs @@ -1,10 +1,9 @@ -use crate::worldgen::voronoi::VoronoiGrid; -use crate::worldgen::{BiomeGenerator, ChunkBiomes}; -use feather_core::{Biome, ChunkPosition}; -use num_traits::FromPrimitive; +use crate::voronoi::VoronoiGrid; +use crate::BiomeGenerator; +use base::chunk::BiomeStore; +use base::{Biome, ChunkPosition}; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; -use strum::EnumCount; /// Biome grid generator based on a distorted Voronoi /// noise. @@ -12,10 +11,10 @@ use strum::EnumCount; pub struct DistortedVoronoiBiomeGenerator; impl BiomeGenerator for DistortedVoronoiBiomeGenerator { - fn generate_for_chunk(&self, chunk: ChunkPosition, seed: u64) -> ChunkBiomes { + fn generate_for_chunk(&self, chunk: ChunkPosition, seed: u64) -> BiomeStore { let mut voronoi = VoronoiGrid::new(384, seed); - let mut biomes = ChunkBiomes::from_array([Biome::Plains; 16 * 16]); // Will be overridden + let mut biomes = BiomeStore::default(); // Will be overridden // Noise is used to distort each coordinate. /*let x_noise = @@ -27,8 +26,8 @@ impl BiomeGenerator for DistortedVoronoiBiomeGenerator { .with_seed(seed as i32 + 2) .generate_scaled(-4.0, 4.0);*/ - for x in 0..16 { - for z in 0..16 { + for x in 0..4 { + for z in 0..4 { // Apply distortion to coordinate before passing to voronoi // generator. //let distort_x = x_noise[(z << 4) | x] as i32 * 8; @@ -38,8 +37,8 @@ impl BiomeGenerator for DistortedVoronoiBiomeGenerator { let distort_z = 0; let (closest_x, closest_y) = voronoi.get( - (chunk.x * 16) + x as i32 + distort_x, - (chunk.z * 16) + z as i32 + distort_z, + (chunk.x * 16) + x as i32 * 4 + distort_x, + (chunk.z * 16) + z as i32 * 4 + distort_z, ); // Shift around the closest_x and closest_y values @@ -50,11 +49,13 @@ impl BiomeGenerator for DistortedVoronoiBiomeGenerator { let mut rng = XorShiftRng::seed_from_u64(combined as u64); loop { - let shifted: u64 = rng.gen(); + let shifted: u32 = rng.gen(); - let biome = Biome::from_u64(shifted % Biome::count() as u64).unwrap(); + let biome = Biome::from_id(shifted % 60).unwrap(); if is_biome_allowed(biome) { - biomes.set_biome_at(x, z, biome); + for y in 0..64 { + biomes.set(x, y, z, biome); + } break; } } @@ -67,16 +68,19 @@ impl BiomeGenerator for DistortedVoronoiBiomeGenerator { /// Returns whether the given biome is allowed in the overworld. fn is_biome_allowed(biome: Biome) -> bool { - match biome { + !matches!( + biome, Biome::TheEnd - | Biome::TheVoid - | Biome::Nether - | Biome::SmallEndIslands - | Biome::EndBarrens - | Biome::EndHighlands - | Biome::EndMidlands => false, - _ => true, - } + | Biome::TheVoid + | Biome::NetherWastes + | Biome::CrimsonForest + | Biome::WarpedForest + | Biome::BasaltDeltas + | Biome::SmallEndIslands + | Biome::EndBarrens + | Biome::EndHighlands + | Biome::EndMidlands + ) } #[cfg(test)] @@ -95,15 +99,17 @@ mod tests { println!("{:?}", biomes); let mut num_plains = 0; - for x in 0..16 { - for z in 0..16 { - if biomes.biome_at(x, z) == Biome::Plains { - num_plains += 1; + for x in 0..4 { + for z in 0..4 { + for y in 0..64 { + if biomes.get(x, y, z) == Biome::Plains { + num_plains += 1; + } } } } - assert_ne!(num_plains, 16 * 16); + assert_ne!(num_plains, 4 * 64 * 4); } #[test] @@ -119,9 +125,11 @@ mod tests { for _ in 0..5 { let next = gen.generate_for_chunk(chunk, seed); - for x in 0..16 { - for z in 0..16 { - assert_eq!(first.biome_at(x, z), next.biome_at(x, z)); + for x in 0..4 { + for z in 0..4 { + for y in 0..64 { + assert_eq!(first.get(x, y, z), next.get(x, y, z)); + } } } } diff --git a/server/src/worldgen/biomes/mod.rs b/feather/worldgen/src/biomes/mod.rs similarity index 100% rename from server/src/worldgen/biomes/mod.rs rename to feather/worldgen/src/biomes/mod.rs diff --git a/server/src/worldgen/biomes/two_level.rs b/feather/worldgen/src/biomes/two_level.rs similarity index 56% rename from server/src/worldgen/biomes/two_level.rs rename to feather/worldgen/src/biomes/two_level.rs index 0581d887d..a14ae3fe4 100644 --- a/server/src/worldgen/biomes/two_level.rs +++ b/feather/worldgen/src/biomes/two_level.rs @@ -1,19 +1,27 @@ -use crate::worldgen::voronoi::VoronoiGrid; -use crate::worldgen::{voronoi, BiomeGenerator, ChunkBiomes}; -use feather_core::{Biome, ChunkPosition}; +use crate::voronoi::VoronoiGrid; +use crate::{voronoi, BiomeGenerator}; +use base::chunk::BiomeStore; +use base::{Biome, ChunkPosition}; +use once_cell::sync::Lazy; -lazy_static! { - /// Array of biome groups, each containing biomes - /// which may appear next to each other. This is used in the - /// two-level biome generator. - static ref BIOME_GROUPS: Vec<Vec<Biome>> = { +/// Array of biome groups, each containing biomes +/// which may appear next to each other. This is used in the +/// two-level biome generator. +static BIOME_GROUPS: Lazy<Vec<Vec<Biome>>> = Lazy::new(|| { + vec![ + vec![Biome::SnowyTundra, Biome::SnowyTaiga], vec![ - vec![Biome::SnowyTundra, Biome::SnowyTaiga], - vec![Biome::Plains, Biome::BirchForest, Biome::Forest, Biome::Taiga, Biome::Mountains, Biome::Swamp, Biome::DarkForest], - vec![Biome::Savanna, Biome::Desert], - ] - }; -} + Biome::Plains, + Biome::BirchForest, + Biome::Forest, + Biome::Taiga, + Biome::Mountains, + Biome::Swamp, + Biome::DarkForest, + ], + vec![Biome::Savanna, Biome::Desert], + ] +}); /// Biome grid generator which works using two layers /// of Voronoi. The first layer defines the biome group, @@ -24,24 +32,24 @@ lazy_static! { pub struct TwoLevelBiomeGenerator; impl BiomeGenerator for TwoLevelBiomeGenerator { - fn generate_for_chunk(&self, chunk: ChunkPosition, seed: u64) -> ChunkBiomes { + fn generate_for_chunk(&self, chunk: ChunkPosition, seed: u64) -> BiomeStore { // Voronoi used to determine biome group let mut group_voronoi = VoronoiGrid::new(1024, seed); // Voronoi used to determine biome within group let mut local_voronoi = VoronoiGrid::new(256, seed + 1); - let mut biomes = ChunkBiomes::from_array([Biome::Plains; 16 * 16]); // Will be overridden + let mut biomes = BiomeStore::default(); // Will be overridden let num_groups = BIOME_GROUPS.len(); // TODO: distort voronoi - for x in 0..16 { - for z in 0..16 { + for x in 0..4 { + for z in 0..4 { // Compute biome group let possible_biomes = { let (closest_x, closest_z) = - group_voronoi.get(chunk.x * 16 + x, chunk.z * 16 + z); + group_voronoi.get(chunk.x * 16 + x * 4, chunk.z * 16 + z * 4); let group_index = voronoi::shuffle(closest_x, closest_z, 0, num_groups); @@ -51,15 +59,16 @@ impl BiomeGenerator for TwoLevelBiomeGenerator { // Compute biome within group let biome = { let (closest_x, closest_z) = - local_voronoi.get(chunk.x * 16 + x, chunk.z * 16 + z); + local_voronoi.get(chunk.x * 16 + x * 4, chunk.z * 16 + z * 4); let biome_index = voronoi::shuffle(closest_x, closest_z, 0, possible_biomes.len()); possible_biomes[biome_index] }; - - biomes.set_biome_at(x as usize, z as usize, biome); + for y in 0..64 { + biomes.set(x as usize, y, z as usize, biome); + } } } diff --git a/server/src/worldgen/composition.rs b/feather/worldgen/src/composition.rs similarity index 68% rename from server/src/worldgen/composition.rs rename to feather/worldgen/src/composition.rs index d8e518dfe..61bc6e14c 100644 --- a/server/src/worldgen/composition.rs +++ b/feather/worldgen/src/composition.rs @@ -1,10 +1,10 @@ //! Composition generator, used to populate chunks with blocks //! based on the density and biome values. -use crate::worldgen::{block_index, util, ChunkBiomes, CompositionGenerator, SEA_LEVEL}; +use crate::{block_index, util, CompositionGenerator, SEA_LEVEL}; +use base::{chunk::BiomeStore, Biome, BlockId, Chunk, ChunkPosition}; +use bitvec::order::LocalBits; use bitvec::slice::BitSlice; -use feather_blocks::{GrassBlockData, MyceliumData, WaterData}; -use feather_core::{Biome, Block, Chunk, ChunkPosition}; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; use std::cmp::min; @@ -19,8 +19,8 @@ impl CompositionGenerator for BasicCompositionGenerator { &self, chunk: &mut Chunk, _pos: ChunkPosition, - biomes: &ChunkBiomes, - density: &BitSlice, + biomes: &BiomeStore, + density: &BitSlice<LocalBits, u8>, seed: u64, ) { // For each column in the chunk, go from top to @@ -29,7 +29,14 @@ impl CompositionGenerator for BasicCompositionGenerator { // stone. for x in 0..16 { for z in 0..16 { - basic_composition_for_column(x, z, chunk, density, seed, biomes.biome_at(x, z)); + basic_composition_for_column( + x, + z, + chunk, + density, + seed, + biomes.get_at_block(x, 0, z), + ); } } } @@ -39,7 +46,7 @@ fn basic_composition_for_column( x: usize, z: usize, chunk: &mut Chunk, - density: &BitSlice, + density: &BitSlice<LocalBits, u8>, seed: u64, biome: Biome, ) { @@ -50,7 +57,7 @@ fn basic_composition_for_solid_biome( x: usize, z: usize, chunk: &mut Chunk, - density: &BitSlice, + density: &BitSlice<LocalBits, u8>, seed: u64, biome: Biome, ) { @@ -62,7 +69,7 @@ fn basic_composition_for_solid_biome( let mut topsoil_remaining = -1; let mut water_level = 0; // `level` block data starts at 0 and skips to min(8+n, 15) for each level of water downward for y in (0..256).rev() { - let mut block = Block::Air; + let mut block = BlockId::air(); let is_solid = density[block_index(x, y, z)]; @@ -70,7 +77,7 @@ fn basic_composition_for_solid_biome( if biome == Biome::Ocean { if y <= SEA_LEVEL && !is_solid { - block = Block::Water(WaterData { level: water_level }); + block = BlockId::water().with_water_level(water_level); if water_level == 0 { water_level = 8; } else { @@ -84,7 +91,7 @@ fn basic_composition_for_solid_biome( if !skip { if y <= rng.gen_range(0, 4) { - block = Block::Bedrock; + block = BlockId::bedrock(); } else { block = if is_solid { if topsoil_remaining == -1 { @@ -95,62 +102,63 @@ fn basic_composition_for_solid_biome( topsoil_remaining -= 1; block } else { - Block::Stone + BlockId::stone() } } else { topsoil_remaining = -1; - Block::Air + BlockId::air() }; } } - if block != Block::Air { + if !block.is_air() { chunk.set_block_at(x, y, z, block); } } } /// Returns the top soil block for the given biome. -fn top_soil_block(biome: Biome) -> Block { +fn top_soil_block(biome: Biome) -> BlockId { match biome { Biome::SnowyTundra | Biome::IceSpikes | Biome::SnowyTaiga | Biome::SnowyTaigaMountains - | Biome::SnowyBeach => Block::GrassBlock(GrassBlockData { snowy: true }), - Biome::GravellyMountains | Biome::ModifiedGravellyMountains => Block::Gravel, - Biome::StoneShore => Block::Stone, - Biome::Beach | Biome::Desert | Biome::DesertHills | Biome::DesertLakes => Block::Sand, - Biome::MushroomFields | Biome::MushroomFieldShore => { - Block::Mycelium(MyceliumData { snowy: false }) - } + | Biome::SnowyBeach => BlockId::grass_block().with_snowy(true), + Biome::GravellyMountains | Biome::ModifiedGravellyMountains => BlockId::gravel(), + Biome::StoneShore => BlockId::stone(), + Biome::Beach | Biome::Desert | Biome::DesertHills | Biome::DesertLakes => BlockId::sand(), + Biome::MushroomFields | Biome::MushroomFieldShore => BlockId::mycelium(), + Biome::Badlands | Biome::ErodedBadlands | Biome::WoodedBadlandsPlateau | Biome::BadlandsPlateau | Biome::ModifiedBadlandsPlateau - | Biome::ModifiedWoodedBadlandsPlateau => Block::RedSand, - Biome::Ocean => Block::Sand, - _ => Block::GrassBlock(GrassBlockData::default()), + | Biome::ModifiedWoodedBadlandsPlateau => BlockId::red_sand(), + Biome::Ocean => BlockId::sand(), + _ => BlockId::grass_block(), } } /// Returns the block under the top soil block for the given biome. -fn underneath_top_soil_block(biome: Biome) -> Block { +fn underneath_top_soil_block(biome: Biome) -> BlockId { match biome { - Biome::SnowyBeach => Block::SnowBlock, - Biome::GravellyMountains | Biome::ModifiedGravellyMountains => Block::Gravel, - Biome::StoneShore => Block::Stone, - Biome::Beach | Biome::Desert | Biome::DesertHills | Biome::DesertLakes => Block::Sandstone, - Biome::MushroomFields | Biome::MushroomFieldShore => Block::Dirt, + Biome::SnowyBeach => BlockId::snow_block(), + Biome::GravellyMountains | Biome::ModifiedGravellyMountains => BlockId::gravel(), + Biome::StoneShore => BlockId::stone(), + Biome::Beach | Biome::Desert | Biome::DesertHills | Biome::DesertLakes => { + BlockId::sandstone() + } + Biome::MushroomFields | Biome::MushroomFieldShore => BlockId::dirt(), Biome::Badlands | Biome::ErodedBadlands | Biome::WoodedBadlandsPlateau | Biome::BadlandsPlateau | Biome::ModifiedBadlandsPlateau - | Biome::ModifiedWoodedBadlandsPlateau => Block::RedSandstone, - Biome::Ocean => Block::Sand, - _ => Block::Dirt, + | Biome::ModifiedWoodedBadlandsPlateau => BlockId::red_sandstone(), + Biome::Ocean => BlockId::sand(), + _ => BlockId::dirt(), } } @@ -178,24 +186,21 @@ mod tests { basic_composition_for_column(x, z, &mut chunk, &density[..], 435, Biome::Plains); for y in 4..=28 { - assert_eq!(chunk.block_at(x, y, z), Block::Stone); + assert_eq!(chunk.block_at(x, y, z).unwrap(), BlockId::stone()); } for y in 29..=31 { - assert_eq!(chunk.block_at(x, y, z), Block::Dirt); + assert_eq!(chunk.block_at(x, y, z).unwrap(), BlockId::dirt()); } for y in 33..40 { - assert_eq!(chunk.block_at(x, y, z), Block::Air); + assert_eq!(chunk.block_at(x, y, z).unwrap(), BlockId::air()); } for y in 40..=60 { - assert_eq!(chunk.block_at(x, y, z), Block::Stone); + assert_eq!(chunk.block_at(x, y, z).unwrap(), BlockId::stone()); } - assert_eq!( - chunk.block_at(x, 64, z), - Block::GrassBlock(GrassBlockData::default()) - ); + assert_eq!(chunk.block_at(x, 64, z).unwrap(), BlockId::grass_block()); } } diff --git a/server/src/worldgen/density_map/density.rs b/feather/worldgen/src/density_map/density.rs similarity index 85% rename from server/src/worldgen/density_map/density.rs rename to feather/worldgen/src/density_map/density.rs index ede7066ba..3d09f0f4f 100644 --- a/server/src/worldgen/density_map/density.rs +++ b/feather/worldgen/src/density_map/density.rs @@ -3,9 +3,11 @@ //! Over the 2D height map generator, this has the advantage that terrain //! is more interesting; overhangs and the like will be able to generate. -use crate::worldgen::{block_index, noise, DensityMapGenerator, NearbyBiomes, NoiseLerper}; +use crate::{block_index, noise, DensityMapGenerator, NearbyBiomes, NoiseLerper}; +use base::{Biome, ChunkPosition}; +use bitvec::order::LocalBits; use bitvec::vec::BitVec; -use feather_core::{Biome, ChunkPosition}; +use once_cell::sync::Lazy; use simdnoise::NoiseBuilder; /// A density map generator using 3D Perlin noise. @@ -24,10 +26,15 @@ use simdnoise::NoiseBuilder; pub struct DensityMapGeneratorImpl; impl DensityMapGenerator for DensityMapGeneratorImpl { - fn generate_for_chunk(&self, chunk: ChunkPosition, biomes: &NearbyBiomes, seed: u64) -> BitVec { + fn generate_for_chunk( + &self, + chunk: ChunkPosition, + biomes: &NearbyBiomes, + seed: u64, + ) -> BitVec<LocalBits, u8> { let mut density = BitVec::from_vec(vec![0u8; 16 * 256 * 16 / 8]); - let uninterpolated_densities = generate_density(chunk, &biomes, seed); + let uninterpolated_densities = generate_density(chunk, biomes, seed); let noise = NoiseLerper::new(&uninterpolated_densities) .with_offset(chunk.x, chunk.z) .generate(); @@ -99,7 +106,7 @@ fn generate_density(chunk: ChunkPosition, biomes: &NearbyBiomes, seed: u64) -> V let height_noise = NoiseBuilder::fbm_2d_offset(x_offset, len, z_offset, len) .with_seed(noise_seed + 3) .with_octaves(2) - .with_freq(0.001) + .with_freq(0.08) .generate() .0; @@ -109,9 +116,9 @@ fn generate_density(chunk: ChunkPosition, biomes: &NearbyBiomes, seed: u64) -> V for subx in 0..DENSITY_WIDTH { for subz in 0..DENSITY_WIDTH { // TODO: average nearby biome parameters - let (amplitude, midpoint) = column_parameters(&biomes, subx, subz); + let (amplitude, midpoint) = column_parameters(biomes, subx, subz); - let height = height_noise[(subz * len) + subx] * 25.0; + let height = height_noise[(subz * len) + subx] * 3.0; // Loop through Y axis of this subchunk column. for suby in 0..DENSITY_HEIGHT { @@ -139,7 +146,8 @@ fn generate_density(chunk: ChunkPosition, biomes: &NearbyBiomes, seed: u64) -> V let density_2 = density_noise_2[index] * 50.0; // Average between two density values based on choice weight. - result[index] = lerp(density_1, density_2, choice) + height_offset + height; + result[index] = + lerp(density_1, density_2, choice) * 0.2 + height_offset * 2.0 + height; } } } @@ -147,23 +155,21 @@ fn generate_density(chunk: ChunkPosition, biomes: &NearbyBiomes, seed: u64) -> V result } -lazy_static! { - /// Elevation height field, used to weight - /// the averaging of nearby biome heights. - static ref ELEVATION_WEIGHT: [[f32; 19]; 19] = { - let mut array = [[0.0; 19]; 19]; - for (x, values) in array.iter_mut().enumerate() { - for (z, value) in values.iter_mut().enumerate() { - let mut x_squared = x as i32 - 9; - x_squared *= x_squared; - let mut z_sqaured = z as i32 - 9; - z_sqaured *= z_sqaured; - *value = 10.0 / (x_squared as f32 + z_sqaured as f32 + 0.2).sqrt(); - } +/// Elevation height field, used to weight +/// the averaging of nearby biome heights. +static ELEVATION_WEIGHT: Lazy<[[f32; 19]; 19]> = Lazy::new(|| { + let mut array = [[0.0; 19]; 19]; + for (x, values) in array.iter_mut().enumerate() { + for (z, value) in values.iter_mut().enumerate() { + let mut x_squared = x as i32 - 9; + x_squared *= x_squared; + let mut z_sqaured = z as i32 - 9; + z_sqaured *= z_sqaured; + *value = 10.0 / (x_squared as f32 + z_sqaured as f32 + 0.2).sqrt(); } - array - }; -} + } + array +}); /// Computes the target amplitude and midpoint for the /// given column, using a 9x9 grid of biomes @@ -186,7 +192,7 @@ fn column_parameters(biomes: &NearbyBiomes, x: usize, z: usize) -> (f32, f32) { let abs_x = x + block_x; let abs_z = z + block_z; - let biome = biomes.biome_at(abs_x, abs_z); + let biome = biomes.get_at_block(abs_x, 0, abs_z); let (amplitude, midpoint) = biome_parameters(biome); let weight = ELEVATION_WEIGHT[(block_x + 9) as usize][(block_z + 9) as usize]; diff --git a/server/src/worldgen/density_map/height.rs b/feather/worldgen/src/density_map/height.rs similarity index 80% rename from server/src/worldgen/density_map/height.rs rename to feather/worldgen/src/density_map/height.rs index 129158fef..c38bac35e 100644 --- a/server/src/worldgen/density_map/height.rs +++ b/feather/worldgen/src/density_map/height.rs @@ -1,9 +1,10 @@ //! Implements a basic height map generator using 2D Perlin noise. //! A superior generator would use 3D noise to allow for overhangs. -use crate::worldgen::{block_index, DensityMapGenerator, NearbyBiomes, OCEAN_DEPTH, SKY_LIMIT}; +use crate::{block_index, DensityMapGenerator, NearbyBiomes, OCEAN_DEPTH, SKY_LIMIT}; +use base::{Biome, ChunkPosition}; +use bitvec::order::LocalBits; use bitvec::vec::BitVec; -use feather_core::{Biome, ChunkPosition}; use simdnoise::NoiseBuilder; use std::cmp::min; @@ -13,7 +14,12 @@ use std::cmp::min; pub struct HeightMapGenerator; impl DensityMapGenerator for HeightMapGenerator { - fn generate_for_chunk(&self, chunk: ChunkPosition, biomes: &NearbyBiomes, seed: u64) -> BitVec { + fn generate_for_chunk( + &self, + chunk: ChunkPosition, + biomes: &NearbyBiomes, + seed: u64, + ) -> BitVec<LocalBits, u8> { let x_offset = (chunk.x * 16) as f32; let y_offset = (chunk.z * 16) as f32; @@ -29,7 +35,7 @@ impl DensityMapGenerator for HeightMapGenerator { let mut density_map = BitVec::from_vec(vec![0u8; 16 * 256 * 16 / 8]); for x in 0..16 { for z in 0..16 { - let biome = biomes.biome_at(x, z); + let biome = biomes.get_at_block(x, 0, z); let index = (z << 4) | x; let mut elevation = elevation[index].abs() * 400.0; let detail = detail[index] * 50.0; diff --git a/server/src/worldgen/density_map/mod.rs b/feather/worldgen/src/density_map/mod.rs similarity index 100% rename from server/src/worldgen/density_map/mod.rs rename to feather/worldgen/src/density_map/mod.rs diff --git a/server/src/worldgen/finishers/clumped.rs b/feather/worldgen/src/finishers/clumped.rs similarity index 83% rename from server/src/worldgen/finishers/clumped.rs rename to feather/worldgen/src/finishers/clumped.rs index 74e48a6c0..af8880f05 100644 --- a/server/src/worldgen/finishers/clumped.rs +++ b/feather/worldgen/src/finishers/clumped.rs @@ -1,7 +1,6 @@ -use crate::worldgen::util::shuffle_seed_for_chunk; -use crate::worldgen::{ChunkBiomes, FinishingGenerator, TopBlocks}; -use feather_blocks::Block; -use feather_core::{Biome, Chunk}; +use crate::util::shuffle_seed_for_chunk; +use crate::{BiomeStore, FinishingGenerator, TopBlocks}; +use base::{Biome, BlockId, Chunk}; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; use std::{cmp, iter}; @@ -14,7 +13,7 @@ impl FinishingGenerator for ClumpedFoliageFinisher { fn generate_for_chunk( &self, chunk: &mut Chunk, - biomes: &ChunkBiomes, + biomes: &BiomeStore, top_blocks: &TopBlocks, seed: u64, ) { @@ -29,7 +28,7 @@ impl FinishingGenerator for ClumpedFoliageFinisher { for x in 0..16 { for z in 0..16 { - let biome = biomes.biome_at(x, z); + let biome = biomes.get_at_block(x, 0, z); if let Some(block) = biome_clump_block(biome) { if rng.gen_range(0, 48) == 0 { @@ -42,7 +41,7 @@ impl FinishingGenerator for ClumpedFoliageFinisher { let pos_x = cmp::max(0, cmp::min(x as i32 + offset_x, 15)) as usize; let pos_z = cmp::max(0, cmp::min(z as i32 + offset_z, 15)) as usize; - if chunk.biome_at(pos_x, pos_z) != biome { + if chunk.biomes().get_at_block(pos_x, 0, pos_z) != biome { return; // Don't generate block outside this biome } @@ -56,7 +55,7 @@ impl FinishingGenerator for ClumpedFoliageFinisher { } } -fn biome_clump_block(biome: Biome) -> Option<Block> { +fn biome_clump_block(biome: Biome) -> Option<BlockId> { match biome { Biome::Plains | Biome::SunflowerPlains @@ -70,7 +69,7 @@ fn biome_clump_block(biome: Biome) -> Option<Block> { | Biome::BirchForest | Biome::TallBirchForest | Biome::BirchForestHills - | Biome::Swamp => Some(Block::Grass), + | Biome::Swamp => Some(BlockId::grass()), _ => None, } } diff --git a/server/src/worldgen/finishers/mod.rs b/feather/worldgen/src/finishers/mod.rs similarity index 100% rename from server/src/worldgen/finishers/mod.rs rename to feather/worldgen/src/finishers/mod.rs diff --git a/server/src/worldgen/finishers/single.rs b/feather/worldgen/src/finishers/single.rs similarity index 65% rename from server/src/worldgen/finishers/single.rs rename to feather/worldgen/src/finishers/single.rs index dc313c2c8..74bcaf005 100644 --- a/server/src/worldgen/finishers/single.rs +++ b/feather/worldgen/src/finishers/single.rs @@ -1,7 +1,7 @@ -use crate::worldgen::util::shuffle_seed_for_chunk; -use crate::worldgen::{ChunkBiomes, FinishingGenerator, TopBlocks}; -use feather_blocks::{Block, WaterData}; -use feather_core::{Biome, Chunk}; +use crate::util::shuffle_seed_for_chunk; +use crate::{FinishingGenerator, TopBlocks}; +use base::chunk::BiomeStore; +use base::{Biome, BlockId, Chunk}; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -13,17 +13,18 @@ impl FinishingGenerator for SingleFoliageFinisher { fn generate_for_chunk( &self, chunk: &mut Chunk, - biomes: &ChunkBiomes, + biomes: &BiomeStore, top_blocks: &TopBlocks, seed: u64, ) { let mut rng = XorShiftRng::seed_from_u64(shuffle_seed_for_chunk(seed, chunk.position())); for x in 0..16 { for z in 0..16 { - let biome = biomes.biome_at(x, z); + let biome = biomes.get_at_block(x, 0, z); if let Some(foliage) = biome_foliage(biome) { - if chunk.block_at(x, top_blocks.top_block_at(x, z), z) == foliage.required + if chunk.block_at(x, top_blocks.top_block_at(x, z), z).unwrap() + == foliage.required && rng.gen_range(0, 192) == 0 { chunk.set_block_at(x, top_blocks.top_block_at(x, z) + 1, z, foliage.block); @@ -37,24 +38,21 @@ impl FinishingGenerator for SingleFoliageFinisher { struct Foliage { /// The block required at the top of the column /// for the foliage to generate. - required: Block, + required: BlockId, /// The foliage block. - block: Block, + block: BlockId, } impl Foliage { - fn new(required: Block, block: Block) -> Self { + fn new(required: BlockId, block: BlockId) -> Self { Self { required, block } } } fn biome_foliage(biome: Biome) -> Option<Foliage> { match biome { - Biome::Desert => Some(Foliage::new(Block::Sand, Block::DeadBush)), - Biome::Swamp => Some(Foliage::new( - Block::Water(WaterData::default()), - Block::LilyPad, - )), + Biome::Desert => Some(Foliage::new(BlockId::sand(), BlockId::dead_bush())), + Biome::Swamp => Some(Foliage::new(BlockId::water(), BlockId::lily_pad())), _ => None, } } diff --git a/feather/worldgen/src/finishers/snow.rs b/feather/worldgen/src/finishers/snow.rs new file mode 100644 index 000000000..164d74970 --- /dev/null +++ b/feather/worldgen/src/finishers/snow.rs @@ -0,0 +1,39 @@ +use crate::{FinishingGenerator, TopBlocks}; +use base::{chunk::BiomeStore, Biome, BlockId, Chunk}; + +/// Finisher for generating snow on top of snow biomes. +#[derive(Default)] +pub struct SnowFinisher; + +impl FinishingGenerator for SnowFinisher { + fn generate_for_chunk( + &self, + chunk: &mut Chunk, + biomes: &BiomeStore, + top_blocks: &TopBlocks, + _seed: u64, + ) { + for x in 0..16 { + for z in 0..16 { + if !is_snowy_biome(biomes.get_at_block(x, 0, z)) { + continue; + } + + chunk + .set_block_at(x, top_blocks.top_block_at(x, z) + 1, z, BlockId::snow()) + .unwrap(); + } + } + } +} + +fn is_snowy_biome(biome: Biome) -> bool { + matches!( + biome, + Biome::SnowyTundra + | Biome::IceSpikes + | Biome::SnowyTaiga + | Biome::SnowyTaigaMountains + | Biome::SnowyBeach + ) +} diff --git a/server/src/worldgen/mod.rs b/feather/worldgen/src/lib.rs similarity index 66% rename from server/src/worldgen/mod.rs rename to feather/worldgen/src/lib.rs index 1753f3bcb..36a421ee5 100644 --- a/server/src/worldgen/mod.rs +++ b/feather/worldgen/src/lib.rs @@ -1,10 +1,10 @@ +#![forbid(unsafe_code)] + //! World generation for Feather. //! //! Generation is primarily based around the `ComposableGenerator`, //! which allows configuration of a world generator pipeline. -use feather_core::{Biome, Block, Chunk, ChunkPosition}; - mod biomes; mod composition; mod density_map; @@ -14,18 +14,19 @@ mod superflat; mod util; pub mod voronoi; -use crate::worldgen::finishers::{ClumpedFoliageFinisher, SingleFoliageFinisher, SnowFinisher}; +use base::chunk::BiomeStore; +use base::{Biome, BlockId, Chunk, ChunkPosition}; pub use biomes::{DistortedVoronoiBiomeGenerator, TwoLevelBiomeGenerator}; -use bitvec::slice::BitSlice; use bitvec::vec::BitVec; +use bitvec::{order::LocalBits, slice::BitSlice}; pub use composition::BasicCompositionGenerator; pub use density_map::{DensityMapGeneratorImpl, HeightMapGenerator}; +use finishers::{ClumpedFoliageFinisher, SingleFoliageFinisher, SnowFinisher}; pub use noise::NoiseLerper; use num_traits::ToPrimitive; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; use smallvec::SmallVec; -use std::fmt; pub use superflat::SuperflatWorldGenerator; /// Sea-level height. @@ -40,9 +41,9 @@ pub trait WorldGenerator: Send + Sync { fn generate_chunk(&self, position: ChunkPosition) -> Chunk; } -pub struct EmptyWorldGenerator {} +pub struct VoidWorldGenerator; -impl WorldGenerator for EmptyWorldGenerator { +impl WorldGenerator for VoidWorldGenerator { fn generate_chunk(&self, position: ChunkPosition) -> Chunk { Chunk::new(position) } @@ -132,24 +133,19 @@ impl WorldGenerator for ComposableGenerator { biomes.push(self.biome.generate_for_chunk(pos, biome_seed)); } } - let biomes = NearbyBiomes::from_vec(biomes); + let biomes = NearbyBiomes::from_slice(&biomes[..]).unwrap(); let density_map = self.density_map .generate_for_chunk(position, &biomes, seed_shuffler.gen()); let mut chunk = Chunk::new(position); - - for x in 0..16 { - for z in 0..16 { - chunk.set_biome_at(x, z, biomes.biome_at(x, z)); - } - } + *chunk.biomes_mut() = *biomes.center(); self.composition.generate_for_chunk( &mut chunk, position, - &biomes.biomes[4], // Center chunk + &biomes.biome_stores[4], // Center chunk density_map.as_bitslice(), seed_shuffler.gen(), ); @@ -160,7 +156,7 @@ impl WorldGenerator for ComposableGenerator { for x in 0..16 { for z in 0..16 { for y in (0..256).rev() { - if chunk.block_at(x, y, z) != Block::Air { + if chunk.block_at(x, y, z).unwrap() != BlockId::air() { top_blocks.set_top_block_at(x, z, y); break; } @@ -168,31 +164,18 @@ impl WorldGenerator for ComposableGenerator { } } + chunk.recalculate_heightmaps(); + // Finishers. for finisher in &self.finishers { finisher.generate_for_chunk( &mut chunk, - &biomes.biomes[4], + &biomes.biome_stores[4], &top_blocks, seed_shuffler.gen(), ); } - // TODO: correct lighting. - // Fill chunk with 15 light levels. - chunk - .sections_mut() - .into_iter() - .filter(|section| section.is_some()) - .map(|section| section.unwrap()) - .for_each(|section| { - let sky_light = section.sky_light_mut(); - - (0..4096).for_each(|index| { - sky_light.set(index, 15); - }) - }); - chunk } } @@ -201,7 +184,7 @@ impl WorldGenerator for ComposableGenerator { pub trait BiomeGenerator: Send + Sync { /// Generates the biomes for a given chunk. /// This function should be deterministic. - fn generate_for_chunk(&self, chunk: ChunkPosition, seed: u64) -> ChunkBiomes; + fn generate_for_chunk(&self, chunk: ChunkPosition, seed: u64) -> BiomeStore; } /// A generator which generates the density map for a chunk. @@ -211,7 +194,12 @@ pub trait DensityMapGenerator: Send + Sync { /// A compact array of booleans is returned, indexable /// by (y << 8) | (x << 4) | z. Those set to `true` will /// contain solid blacks; those set to `false` will be air. - fn generate_for_chunk(&self, chunk: ChunkPosition, biomes: &NearbyBiomes, seed: u64) -> BitVec; + fn generate_for_chunk( + &self, + chunk: ChunkPosition, + biomes: &NearbyBiomes, + seed: u64, + ) -> BitVec<LocalBits, u8>; } /// A generator which populates the given chunk using blocks @@ -223,8 +211,8 @@ pub trait CompositionGenerator: Send + Sync { &self, chunk: &mut Chunk, pos: ChunkPosition, - biomes: &ChunkBiomes, - density: &BitSlice, + biomes: &BiomeStore, + density: &BitSlice<LocalBits, u8>, seed: u64, ); } @@ -238,7 +226,7 @@ pub trait FinishingGenerator: Send + Sync { fn generate_for_chunk( &self, chunk: &mut Chunk, - biomes: &ChunkBiomes, + biomes: &BiomeStore, top_blocks: &TopBlocks, seed: u64, ); @@ -274,48 +262,87 @@ impl TopBlocks { self.top_blocks[x + (z << 4)] = top as u8; } } - /// Represents the biomes in a 3x3 grid of chunks, /// centered on the chunk currently being generated. pub struct NearbyBiomes { /// 2D array of chunk biomes. The chunk biomes /// for a given chunk position relative to the center /// chunk can be obtained using (x + 1) + (z + 1) * 3. - pub biomes: Vec<ChunkBiomes>, + pub biome_stores: [BiomeStore; 3 * 3], } impl NearbyBiomes { - pub fn from_vec(biomes: Vec<ChunkBiomes>) -> Self { - Self { biomes } + pub fn from_slice(biome_store_slice: &[BiomeStore]) -> Option<Self> { + let mut biome_stores = [BiomeStore::new(Biome::Badlands); 9]; + if biome_store_slice.len() != biome_stores.len() { + return None; + } + + biome_stores.clone_from_slice(biome_store_slice); + Some(Self { biome_stores }) } - /// Gets the biome at the given column position. + /// Gets the biome at the given coordinates. /// - /// The column position is an offset from the - /// bottom-left corner of the center chunk. - pub fn biome_at<N: ToPrimitive>(&self, x: N, z: N) -> Biome { - let (index, local_x, local_z) = self.index(x, z); + /// # Panics + /// Panics if `x >= 16`, `z >= 16`, or `y >= 256`. + pub fn get_at_block<N: ToPrimitive>(&self, x: N, y: N, z: N) -> Biome { + let (index, local_x, local_y, local_z) = self.index(x, y, z); - self.biomes[index].biome_at(local_x, local_z) + self.biome_stores[index].get_at_block(local_x, local_y, local_z) } - pub fn set_biome_at<N: ToPrimitive>(&mut self, x: N, z: N, biome: Biome) { - let (index, local_x, local_z) = self.index(x, z); + /// Gets the biome at the given coordinates, in multiples + /// of 4 blocks. + /// + /// # Panics + /// Panics if `x >= 4`, `z >= 4`, or `y >= 64`. + pub fn get<N: ToPrimitive>(&self, x: N, y: N, z: N) -> Biome { + let (index, local_x, local_y, local_z) = self.index( + x.to_isize().unwrap() * 4, + y.to_isize().unwrap() * 4, + z.to_isize().unwrap() * 4, + ); - self.biomes[index].set_biome_at(local_x, local_z, biome); + self.biome_stores[index].get(local_x / 4, local_y / 4, local_z / 4) } - fn index<N: ToPrimitive>(&self, ox: N, oz: N) -> (usize, usize, usize) { + /// Sets the biome at the given coordinates, in multiples + /// of 4 blocks. + /// + /// # Panics + /// Panics if `x >= 4`, `z >= 4`, or `y >= 64`. + pub fn set<N: ToPrimitive>(&mut self, x: N, y: N, z: N, biome: Biome) { + let (index, local_x, local_y, local_z) = self.index( + x.to_isize().unwrap() * 4, + y.to_isize().unwrap() * 4, + z.to_isize().unwrap() * 4, + ); + + self.biome_stores[index].set(local_x / 4, local_y / 4, local_z / 4, biome); + } + pub fn center(&self) -> &BiomeStore { + &self.biome_stores[4] + } + pub fn center_mut(&mut self) -> &mut BiomeStore { + &mut self.biome_stores[4] + } + /// Returns a tuple of (chunk_index, local_x, local_y, local_z) + fn index<N: ToPrimitive>(&self, ox: N, oy: N, oz: N) -> (usize, usize, usize, usize) { + // FIXME: Does this function need to so complicated? let ox = ox.to_isize().unwrap(); + let oy = oy.to_isize().unwrap(); let oz = oz.to_isize().unwrap(); + let x = ox + 16; let z = oz + 16; let chunk_x = (x / 16) as usize; let chunk_z = (z / 16) as usize; - let mut local_x = (ox % 16).abs() as usize; - let mut local_z = (oz % 16).abs() as usize; + let mut local_x = (ox % 16).unsigned_abs(); + let local_y = (oy % 16).unsigned_abs(); + let mut local_z = (oz % 16).unsigned_abs(); if ox < 0 { local_x = 16 - local_x; @@ -324,69 +351,16 @@ impl NearbyBiomes { local_z = 16 - local_z; } - (chunk_x + chunk_z * 3, local_x, local_z) - } -} - -/// Represents the biomes of a chunk. -pub struct ChunkBiomes { - /// 2D array of biome values. The biome for a given - /// column local to the chunk can be indexed using - /// (x << 4) | z. - biomes: [Biome; 16 * 16], -} - -impl ChunkBiomes { - /// Creates a `ChunkBiomes` wrapping the given array of biomes. - #[inline] - pub fn from_array(biomes: [Biome; 16 * 16]) -> Self { - Self { biomes } - } - - /// Gets the biome for the given column index. - /// - /// # Panics - /// Panics if `x >= 16 | z >= 16`. - pub fn biome_at(&self, x: usize, z: usize) -> Biome { - assert!(x < 16 && z < 16); - - let index = Self::index(x, z); - self.biomes[index] - } - - /// Sets the biome for the given column index. - /// - /// # Panics - /// Panics if `x >= 16 | z >= 16`. - pub fn set_biome_at(&mut self, x: usize, z: usize, biome: Biome) { - assert!(x < 16 && z < 16); - - let index = Self::index(x, z); - self.biomes[index] = biome; - } - - fn index(x: usize, z: usize) -> usize { - (x << 4) | z - } -} - -impl fmt::Debug for ChunkBiomes { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - for i in 0..256 { - write!(f, "{:?}, ", self.biomes[i])?; - } - - Ok(()) + (chunk_x + chunk_z * 3, local_x, local_y, local_z) } } - /// A biome generator which always generates plains. #[derive(Debug, Default)] pub struct StaticBiomeGenerator; impl BiomeGenerator for StaticBiomeGenerator { - fn generate_for_chunk(&self, _chunk: ChunkPosition, _seed: u64) -> ChunkBiomes { - ChunkBiomes::from_array([Biome::Plains; 16 * 16]) + fn generate_for_chunk(&self, _chunk: ChunkPosition, _seed: u64) -> BiomeStore { + BiomeStore::new(Biome::Plains) } } @@ -419,18 +393,24 @@ mod tests { fn test_chunks_eq(a: &Chunk, b: &Chunk) { for x in 0..16 { for z in 0..16 { - assert_eq!(a.biome_at(x, z), b.biome_at(x, z)); for y in 0..256 { assert_eq!(a.block_at(x, y, z), b.block_at(x, y, z)); } } } + for x in 0..4 { + for z in 0..4 { + for y in 0..64 { + assert_eq!(a.biomes().get(x, y, z), b.biomes().get(x, y, z)); + } + } + } } #[test] - pub fn test_worldgen_empty() { + pub fn test_worldgen_void() { let chunk_pos = ChunkPosition { x: 1, z: 2 }; - let generator = EmptyWorldGenerator {}; + let generator = VoidWorldGenerator; let chunk = generator.generate_chunk(chunk_pos); // No sections have been generated @@ -440,15 +420,15 @@ mod tests { #[test] fn test_chunk_biomes() { - let biomes = [Biome::Plains; 16 * 16]; - - let mut biomes = ChunkBiomes::from_array(biomes); - - for x in 0..16 { - for z in 0..16 { - assert_eq!(biomes.biome_at(x, z), Biome::Plains); - biomes.set_biome_at(x, z, Biome::Ocean); - assert_eq!(biomes.biome_at(x, z), Biome::Ocean); + let mut biomes = BiomeStore::new(Biome::Plains); + + for x in 0..4 { + for z in 0..4 { + for y in 0..64 { + assert_eq!(biomes.get(x, y, z), Biome::Plains); + biomes.set(x, y, z, Biome::Ocean); + assert_eq!(biomes.get(x, y, z), Biome::Ocean); + } } } } @@ -459,9 +439,11 @@ mod tests { let biomes = gen.generate_for_chunk(ChunkPosition::new(0, 0), 0); - for x in 0..16 { - for z in 0..16 { - assert_eq!(biomes.biome_at(x, z), Biome::Plains); + for x in 0..4 { + for z in 0..4 { + for y in 0..64 { + assert_eq!(biomes.get(x, y, z), Biome::Plains); + } } } } @@ -469,21 +451,21 @@ mod tests { #[test] fn test_nearby_biomes() { let biomes = vec![ - ChunkBiomes::from_array([Biome::Plains; 256]), - ChunkBiomes::from_array([Biome::Swamp; 256]), - ChunkBiomes::from_array([Biome::Savanna; 256]), - ChunkBiomes::from_array([Biome::BirchForest; 256]), - ChunkBiomes::from_array([Biome::DarkForest; 256]), - ChunkBiomes::from_array([Biome::Mountains; 256]), - ChunkBiomes::from_array([Biome::Ocean; 256]), - ChunkBiomes::from_array([Biome::Desert; 256]), - ChunkBiomes::from_array([Biome::Taiga; 256]), + BiomeStore::new(Biome::Plains), + BiomeStore::new(Biome::Swamp), + BiomeStore::new(Biome::Savanna), + BiomeStore::new(Biome::BirchForest), + BiomeStore::new(Biome::DarkForest), + BiomeStore::new(Biome::Mountains), + BiomeStore::new(Biome::Ocean), + BiomeStore::new(Biome::Desert), + BiomeStore::new(Biome::Taiga), ]; - let biomes = NearbyBiomes::from_vec(biomes); + let biomes = NearbyBiomes::from_slice(&biomes[..]).unwrap(); - assert_eq!(biomes.biome_at(0, 0), Biome::DarkForest); - assert_eq!(biomes.biome_at(16, 16), Biome::Taiga); - assert_eq!(biomes.biome_at(-1, -1), Biome::Plains); - assert_eq!(biomes.biome_at(-1, 0), Biome::BirchForest); + assert_eq!(biomes.get_at_block(0, 0, 0), Biome::DarkForest); + assert_eq!(biomes.get_at_block(16, 0, 16), Biome::Taiga); + assert_eq!(biomes.get_at_block(-1, 0, -1), Biome::Plains); + assert_eq!(biomes.get_at_block(-1, 0, 0), Biome::BirchForest); } } diff --git a/server/src/worldgen/noise.rs b/feather/worldgen/src/noise.rs similarity index 96% rename from server/src/worldgen/noise.rs rename to feather/worldgen/src/noise.rs index d12e45ec4..bdc98392a 100644 --- a/server/src/worldgen/noise.rs +++ b/feather/worldgen/src/noise.rs @@ -73,13 +73,17 @@ impl<'a> NoiseLerper<'a> { // default to a scalar impl. // TODO: support SSE41, other SIMD instruction sets - if is_x86_feature_detected!("avx2") { - self.generate_avx2() - } else { - self.generate_fallback() + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + if is_x86_feature_detected!("avx2") { + return self.generate_avx2(); + } } + + self.generate_fallback() } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn generate_avx2(&self) -> Vec<f32> { // TODO: implement this. (Premature optimization is bad!) self.generate_fallback() @@ -219,7 +223,7 @@ mod tests { assert_eq!(chunk.len(), 16 * 256 * 16); for x in chunk { - assert_float_eq!(x, 0.0); + approx::assert_relative_eq!(x, 0.0); } } } diff --git a/feather/worldgen/src/superflat.rs b/feather/worldgen/src/superflat.rs new file mode 100644 index 000000000..69aaf2c0a --- /dev/null +++ b/feather/worldgen/src/superflat.rs @@ -0,0 +1,85 @@ +use base::{anvil::level::SuperflatGeneratorOptions, Biome, BlockId, Chunk, ChunkPosition}; + +use crate::WorldGenerator; + +pub struct SuperflatWorldGenerator { + pub options: SuperflatGeneratorOptions, +} + +impl SuperflatWorldGenerator { + pub fn new(options: SuperflatGeneratorOptions) -> Self { + Self { options } + } +} + +impl WorldGenerator for SuperflatWorldGenerator { + fn generate_chunk(&self, position: ChunkPosition) -> Chunk { + let biome = Biome::from_name(self.options.biome.as_str()).unwrap_or(Biome::Plains); + let mut chunk = Chunk::new_with_default_biome(position, biome); + + let mut y_counter = 0; + for layer in self.options.clone().layers { + if layer.height == 0 { + continue; + } + // FIXME: get rid of this hack by having a consistent naming convention - Item::name() returns `stone` but BlockId::from_identifier requires `minecraft:stone` + let layer_block = BlockId::from_identifier(&format!("minecraft:{}", layer.block)); + if let Some(layer_block) = layer_block { + for y in y_counter..(y_counter + layer.height) { + for x in 0..16 { + for z in 0..16 { + chunk.set_block_at(x as usize, y as usize, z as usize, layer_block); + } + } + } + } else { + // Skip this layer + log::warn!("Failed to generate layer: unknown block {}", layer.block); + } + + y_counter += layer.height; + } + + chunk.recalculate_heightmaps(); + + chunk + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + pub fn test_worldgen_flat() { + let options = SuperflatGeneratorOptions { + biome: Biome::Mountains.name().to_owned(), + ..Default::default() + }; + + let chunk_pos = ChunkPosition { x: 1, z: 2 }; + let generator = SuperflatWorldGenerator { options }; + let chunk = generator.generate_chunk(chunk_pos); + + assert_eq!(chunk.position(), chunk_pos); + for x in 0usize..16 { + for z in 0usize..16 { + for (y, block) in &[ + (0usize, BlockId::bedrock()), + (1usize, BlockId::dirt()), + (2usize, BlockId::dirt()), + (3usize, BlockId::grass_block()), + ] { + assert_eq!(chunk.block_at(x, *y, z).unwrap(), *block); + } + for y in 4..256 { + assert_eq!( + chunk.block_at(x as usize, y as usize, z as usize).unwrap(), + BlockId::air() + ); + } + assert_eq!(chunk.biomes().get_at_block(x, 0, z), Biome::Mountains); + } + } + } +} diff --git a/server/src/worldgen/util.rs b/feather/worldgen/src/util.rs similarity index 95% rename from server/src/worldgen/util.rs rename to feather/worldgen/src/util.rs index ff4072a4d..5ba8edccd 100644 --- a/server/src/worldgen/util.rs +++ b/feather/worldgen/src/util.rs @@ -1,6 +1,6 @@ //! Utilities for world generation. -use feather_core::ChunkPosition; +use base::ChunkPosition; /// Deterministically a seed for the given chunk. This allows /// different seeds to be used for different chunk. diff --git a/server/src/worldgen/voronoi.rs b/feather/worldgen/src/voronoi.rs similarity index 100% rename from server/src/worldgen/voronoi.rs rename to feather/worldgen/src/voronoi.rs diff --git a/generator/Cargo.toml b/generator/Cargo.toml deleted file mode 100644 index 0543cbb9d..000000000 --- a/generator/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "feather-generator" -version = "0.5.0" -authors = ["caelunshun <caelunshun@gmail.com>"] -edition = "2018" -description = "Code generators for Feather" - -[dependencies] -byteorder = "1.3" -clap = { version = "2.33", features = ["yaml"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -simple_logger = "1.3" -log = "0.4" -failure = "0.1" -derive_deref = "1.1" -indexmap = { version = "1.2", features = ["serde-1"] } -quote = "1.0.2" -syn = { version = "1.0", features = ["full"] } -heck = "0.3" -proc-macro2 = "1.0" diff --git a/generator/biomes.sh b/generator/biomes.sh deleted file mode 100755 index 573f382a2..000000000 --- a/generator/biomes.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -cargo run --release --bin feather-generator -- biomes -i data/registries.json -o ../core/src/biomes.rs \ No newline at end of file diff --git a/generator/block_format.md b/generator/block_format.md deleted file mode 100644 index 814e2e924..000000000 --- a/generator/block_format.md +++ /dev/null @@ -1,40 +0,0 @@ -This is the documentation for the block data files generated by the blocks script. - -`feather_blocks`, the crate used by Feather which contains the `Block` enum -and block data structs, reads from `block_data_1.xx.x.dat` files to find -block state ID mappings for a given version. The generator in `generator` -is responsible for generating these files. - -The `Block` enum in `feather_blocks` only contains the block types -in the "native" version, currently 1.13.2. This means that only blocks -from the native version are supported, but block state IDs for these -blocks can be found for any version for which block data files are -generated. - -The following is the file format used for the block data files. - -#### Variable types - -* u8, u16, u32, u64 - unsigned integer types, little-endian -* i8, i16, i32, i64 - signed integer types, little-endian -* string - length (u32) followed by `length` UTF-8 bytes' -* boolean - `u8`, either 0 for `false` or 1 for `true` -* array of X - length of array (number of values, not bytes) as a `u32`, followed by `length` X values - -#### File format - -* Header - * Raw bytes corresponding to FEATHER_BLOCK_DATA_FILE in ASCII - * Version name: `string` (e.g. "1.14.4") - * Protocol version: `u32` (e.g. 498 for 1.14.4) - * Is this a native mappings file? `bool` -* State ID mappings - * Array of struct, stored in order of block types - * `if !native_mappings:` - * Native block state ID for block: `u16` - * `else:` - * Name of this block type, e.g. `minecraft:stone` - * Array of struct - property key-value pairs - * Name of property - e.g. `facing` - * Value of property for this block state - e.g. `west` - * Block state ID for block in this version: `u16` \ No newline at end of file diff --git a/generator/blocks.sh b/generator/blocks.sh deleted file mode 100755 index be074feed..000000000 --- a/generator/blocks.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -echo "Generating block ID mappings and code" - -GENERATOR="cargo run --release --bin feather-generator -- " - -${GENERATOR} native-block-mappings -i data/blocks/1.13.2.json -o ../blocks/data/1.13.2.dat -v 1.13.2 -p 404 -#${GENERATOR} block-mappings -i data/blocks/1.14.4.json -n data/blocks/1.13.2.json -o ../blocks/data/1.14.4.dat -v 1.14.4 -p 498 -${GENERATOR} block-rust -i data/blocks/1.13.2.json -o ../blocks/src/blocks.rs \ No newline at end of file diff --git a/generator/item_format.md b/generator/item_format.md deleted file mode 100644 index 6bda71f4b..000000000 --- a/generator/item_format.md +++ /dev/null @@ -1,13 +0,0 @@ -See block_format.md for more information on data types. - -* Header - * Raw bytes corresponding to "FEATHER_ITEM_DATA_FILE" in ASCII - -* Protocol ID mappings - * Array of struct - * `if native_mappings:` - * String name of this item, e.g. "minecraft:iron_sword" - * Protocol ID (`i32`) - * `else:` - * Native ID for this item (`i32`) - * Protocol ID of this item for this version (`i32`) \ No newline at end of file diff --git a/generator/items.sh b/generator/items.sh deleted file mode 100755 index a05da6aae..000000000 --- a/generator/items.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -GENERATOR="cargo run --release --bin feather-generator -- " - -${GENERATOR} item-mappings -i data/items/1.13.2.json -o ../items/data/1.13.2.dat -${GENERATOR} item-rust -i data/items/1.13.2.json -o ../items/src/item.rs - -${GENERATOR} items-to-blocks --items data/items/1.13.2.json --blocks data/blocks/1.13.2.json --output ../item_block/src/mappings.rs \ No newline at end of file diff --git a/generator/src/biome.rs b/generator/src/biome.rs deleted file mode 100644 index 8b32d75a4..000000000 --- a/generator/src/biome.rs +++ /dev/null @@ -1,126 +0,0 @@ -//! Generation of biome mappings from 1.14 registry report. - -use failure::Error; -use heck::CamelCase; -use indexmap::IndexMap; -use proc_macro2::{Ident, Span}; -use serde_json::Value; -use std::fs::File; -use std::io::{Read, Write}; -use std::process::Command; - -#[derive(Deserialize, Clone)] -pub struct BiomeReport { - #[serde(flatten)] - biomes: IndexMap<String, Biome>, -} - -#[derive(Deserialize, Clone)] -pub struct Biome { - protocol_id: i32, -} - -fn load_report(path: &str) -> Result<BiomeReport, Error> { - let mut file = File::open(path)?; - - let json: Value = { - let mut string = String::new(); - file.read_to_string(&mut string)?; - serde_json::from_str(&string)? - }; - - // Hack to get around the format of the registries.json - // file. - let biome_report: BiomeReport = { - let top = &json["minecraft:biome"]; - let entries = &top["entries"]; - - let as_string = serde_json::to_string(entries)?; - serde_json::from_str(&as_string)? - }; - - Ok(biome_report) -} - -pub fn generate_rust(input: &str, output: &str) -> Result<(), Error> { - let report = load_report(input)?; - - let mut enum_variants = vec![]; - let mut to_protocol_id_match_arms = vec![]; - let mut from_protocol_id_match_arms = vec![]; - let mut to_identifier_match_arms = vec![]; - let mut from_identifier_match_arms = vec![]; - - // These biomes don't exist in 1.13.2, only in 1.14. - let exclude = ["minecraft:bamboo_jungle", "minecraft:bamboo_jungle_hills"]; - - for (name, biome) in report.biomes { - if exclude.iter().any(|e| e == &name) { - continue; - } - let protocol_id = biome.protocol_id; - - let ident = Ident::new(&name[10..].to_camel_case(), Span::call_site()); - - enum_variants.push(quote! { - #ident, - }); - - to_protocol_id_match_arms.push(quote! { - Biome::#ident => #protocol_id, - }); - - from_protocol_id_match_arms.push(quote! { - #protocol_id => Some(Biome::#ident), - }); - - to_identifier_match_arms.push(quote! { - Biome::#ident => #name, - }); - - from_identifier_match_arms.push(quote! { - #name => Some(Biome::#ident), - }); - } - - let code = quote! { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumCount, FromPrimitive, ToPrimitive)] - pub enum Biome { - #(#enum_variants)* - } - - impl Biome { - pub fn protocol_id(self) -> i32 { - match self { - #(#to_protocol_id_match_arms)* - } - } - - pub fn from_protocol_id(protocol_id: i32) -> Option<Self> { - match protocol_id { - #(#from_protocol_id_match_arms)* - _ => None, - } - } - - pub fn identifier(self) -> &'static str { - match self { - #(#to_identifier_match_arms)* - } - } - - pub fn from_identifier(identifier: &str) -> Option<Self> { - match identifier { - #(#from_identifier_match_arms)* - _ => None, - } - } - } - }; - let mut file = File::create(output)?; - file.write_all(code.to_string().as_bytes())?; - - Command::new("rustfmt").arg(output).output()?; - - Ok(()) -} diff --git a/generator/src/block_data.rs b/generator/src/block_data.rs deleted file mode 100644 index 1f235211d..000000000 --- a/generator/src/block_data.rs +++ /dev/null @@ -1,205 +0,0 @@ -use super::WriteExt; -use byteorder::{LittleEndian, WriteBytesExt}; -use failure::Error; -use indexmap::IndexMap; -use std::collections::HashMap; -use std::fs::File; -use std::io::{BufReader, BufWriter, Write}; - -/// The block state ID to use when a block -/// in the native file was not found -/// in the input file. This would happen -/// when the input file is an older version -/// than the native version. -pub const DEFAULT_STATE_ID: u16 = 1; // Stone - -/// Deserializable struct representing a block -/// data report from Vanilla. -#[derive(Clone, Debug, Deserialize, Deref, DerefMut)] -pub struct BlockReport { - #[serde(flatten)] - pub blocks: IndexMap<String, Block>, -} - -/// A block entry in the data report. -#[derive(Clone, Debug, Deserialize)] -pub struct Block { - pub states: Vec<State>, - pub properties: Option<BlockProperties>, -} - -/// List of block properties. -#[derive(Clone, Debug, Deserialize, Deref, DerefMut)] -pub struct BlockProperties { - #[serde(flatten)] - pub props: HashMap<String, Vec<String>>, -} - -/// A block state from the data report. -#[derive(Clone, Debug, Deserialize)] -pub struct State { - pub id: u16, - #[serde(default)] - pub default: bool, - pub properties: Option<StateProperties>, -} - -/// Properties of a block state from the data report. -#[derive(Clone, Debug, Deserialize, Deref, DerefMut, Default)] -pub struct StateProperties { - #[serde(flatten)] - pub props: HashMap<String, String>, -} - -pub fn generate_mappings_file( - input: &str, - output: &str, - native_input: &str, - proto: u32, - version: &str, -) -> Result<(), Error> { - info!( - "Generating mappings file {} using input report {} and native report {}", - output, input, native_input - ); - - let in_file = File::open(input)?; - let out_file = File::create(output)?; - let native_file = File::open(native_input)?; - - info!("Parsing data files"); - - let report: BlockReport = serde_json::from_reader(BufReader::new(&in_file))?; - let native_report: BlockReport = serde_json::from_reader(BufReader::new(&native_file))?; - - info!("Parsing successful"); - - let mut out = BufWriter::new(&out_file); - - // Write header to output file - // See block_format.md - write_header(&mut out, version, proto, false)?; - - // Go through native block types and attempt - // to find corresponding state ID in report. - // If it doesn't exist, just set to `DEFAULT_STATE_ID`. - let mut state_bufs = vec![]; - for (string_id, block) in &native_report.blocks { - for state in &block.states { - let mut state_buf = vec![]; - - let props = state.properties.clone().unwrap_or_default(); - let props = props.props; - - // Try to find corresponding state ID, defaulting to `DEFAULT_STATE_ID` - let state_id = find_state_in_report(&report, string_id.as_str(), &props) - .unwrap_or(DEFAULT_STATE_ID); - - state_buf.write_u16::<LittleEndian>(state.id)?; // Native ID - state_buf.write_u16::<LittleEndian>(state_id)?; - state_bufs.push(state_buf); - } - } - - out.write_u32::<LittleEndian>(state_bufs.len() as u32)?; - for buf in state_bufs { - out.write_all(&buf)?; - } - - out.flush()?; - - info!("Mappings file generated successfully"); - Ok(()) -} - -pub fn generate_native_mappings_file( - input: &str, - output: &str, - proto: u32, - version: &str, -) -> Result<(), Error> { - info!( - "Generating native mappings file {} using input report {}", - output, input - ); - - let in_file = File::open(input)?; - let out_file = File::create(output)?; - - info!("Parsing data file"); - - let report: BlockReport = serde_json::from_reader(BufReader::new(&in_file))?; - - info!("Parsing successful"); - - let mut out = BufWriter::new(&out_file); - - write_header(&mut out, version, proto, true)?; - - let mut count = 0; - let mut buf = vec![]; - // Go through blocks and write to mappings - // file. - for (block_name, block) in &report.blocks { - for state in &block.states { - // Write name - buf.write_string(block_name.as_str())?; - - // Write properties - let len = { - if let Some(props) = state.properties.as_ref() { - props.props.len() - } else { - 0 - } - }; - - buf.write_u32::<LittleEndian>(len as u32)?; - if let Some(props) = state.properties.as_ref() { - for (name, value) in &props.props { - buf.write_string(name.as_str())?; - buf.write_string(value.as_str())?; - } - } - - // Write ID - buf.write_u16::<LittleEndian>(state.id)?; - - count += 1; - } - } - - out.write_u32::<LittleEndian>(count)?; - out.write_all(&buf)?; - - info!("Mappings file generated successfully"); - Ok(()) -} - -fn find_state_in_report( - report: &BlockReport, - name: &str, - props: &HashMap<String, String>, -) -> Option<u16> { - let block = report.blocks.get(name)?; - - let state = block.states.iter().find(|state| match &state.properties { - None => props.is_empty(), - Some(state_props) => props == &state_props.props, - })?; - - Some(state.id) -} - -fn write_header<W: Write>( - out: &mut W, - version: &str, - proto: u32, - native: bool, -) -> Result<(), Error> { - out.write_all(b"FEATHER_BLOCK_DATA_FILE")?; - out.write_string(version)?; - out.write_u32::<LittleEndian>(proto)?; - out.write_u8(native as u8)?; - Ok(()) -} diff --git a/generator/src/cli.yml b/generator/src/cli.yml deleted file mode 100644 index 6378ecbc1..000000000 --- a/generator/src/cli.yml +++ /dev/null @@ -1,136 +0,0 @@ -name: blocks_generator -version: "0.1.0" -author: "caelunshun <caelunshun@gmail.com>" -about: "Generates block state ID mappings and Rust Block enum for various Minecraft versions" - -subcommands: - - block-mappings: - about: "Generates a block state ID mapping file from the given data report" - args: - - input: - short: i - help: "blocks.json data report generated by Vanilla" - required: true - takes_value: true - - output: - short: o - help: "output file to write data to" - required: true - takes_value: true - - native: - short: n - help: "the data report corresponding to the server's native version to refer to" - required: true - takes_value: true - - proto: - short: p - help: "the protocol version ID corresponding to the input file's version" - required: true - takes_value: true - - ver: - short: v - help: "the name of the Minecraft version of the input file" - required: true - takes_value: true - - - native-block-mappings: - about: "Generates a native block state ID mapping file from the server's native data report" - args: - - input: - short: i - help: "blocks.json data report corresponding to the server's native version" - required: true - takes_value: true - - output: - short: o - help: "output file to write mappings to" - required: true - takes_value: true - - proto: - short: p - help: "the protocol version ID corresponding to the input file's version" - required: true - takes_value: true - - ver: - short: v - help: "the name of the Minecraft version of the input file" - required: true - takes_value: true - - - block-rust: - about: "Generates Rust enum and block data structs for the server's native version" - args: - - input: - short: i - help: "blocks.json report corresponding to the server's native version" - required: true - takes_value: true - - output: - short: o - help: "Rust file to write code to. This file will be OVERWRITTEN" - required: true - takes_value: true - - - item-mappings: - about: "Generates native item protocol ID mappings" - args: - - input: - short: i - help: "items.json report corresponding to the server's native version" - required: true - takes_value: true - - output: - short: o - help: "output file to write mappings to" - required: true - takes_value: true - - - item-rust: - about: "Generates Rust code for native item ID mappings" - args: - - input: - short: i - help: "items.json report" - required: true - takes_value: true - - output: - short: o - help: "output file to write code to" - required: true - takes_value: true - - - items-to-blocks: - about: "Generates mappings from items to blocks" - args: - - items: - long: items - help: "Item report" - required: true - takes_value: true - - blocks: - long: blocks - help: "Blocks report" - required: true - takes_value: true - - output: - long: output - short: o - help: "Rust output file" - required: true - takes_value: true - - - biomes: - about: "Generates biome mappings" - args: - - input: - long: input - short: i - required: true - takes_value: true - help: "1.14 registries.json report" - - output: - long: output - short: o - required: true - takes_value: true - help: "Output file to write code to" \ No newline at end of file diff --git a/generator/src/item/mappings.rs b/generator/src/item/mappings.rs deleted file mode 100644 index d47e01c5b..000000000 --- a/generator/src/item/mappings.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::item::ItemReport; -use crate::WriteExt; -use byteorder::{LittleEndian, WriteBytesExt}; -use failure::Error; -use std::io::Write; - -pub fn generate_mappings_file( - report: ItemReport, - write_string_ids: bool, -) -> Result<Vec<u8>, Error> { - let mut buf = Vec::new(); - - buf.write_all(b"FEATHER_ITEM_DATA_FILE")?; - - // TODO handle non-native files - assert!(write_string_ids, "unimplemented"); - - let len = report.mappings.len(); - buf.write_u32::<LittleEndian>(len as u32)?; - - for (item_name, item) in report.mappings { - let id = item.protocol_id; - buf.write_string(&item_name)?; - buf.write_i32::<LittleEndian>(id)?; - } - - Ok(buf) -} diff --git a/generator/src/item/mod.rs b/generator/src/item/mod.rs deleted file mode 100644 index 7f4dbddb1..000000000 --- a/generator/src/item/mod.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! Handles item ID mapping generation. - -use failure::Error; -use indexmap::IndexMap; -use std::fs::File; -use std::io::{Read, Write}; -use std::process::Command; - -mod mappings; -mod rust; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ItemReport { - #[serde(flatten)] - pub mappings: IndexMap<String, Item>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Item { - pub protocol_id: i32, -} - -pub fn load_report(path: &str) -> Result<ItemReport, Error> { - let mut file = File::open(path)?; - - let mut string = String::new(); - file.read_to_string(&mut string)?; - - let report = serde_json::from_str(&string)?; - - Ok(report) -} - -pub fn generate_mappings_file(input: &str, output: &str) -> Result<(), Error> { - info!("Parsing data file"); - let report = load_report(input)?; - info!("Data file parsed successfully"); - - info!("Generating mappings file {}", output); - - let buf = mappings::generate_mappings_file(report, true)?; - let mut file = File::create(output)?; - file.write_all(&buf)?; - - info!("Success"); - - Ok(()) -} - -pub fn generate_rust(input: &str, output: &str) -> Result<(), Error> { - info!("Parsing data file"); - let report = load_report(input)?; - info!("Data file parsed successfully"); - - info!("Generating Rust code"); - let buf = rust::generate_rust(report)?; - let mut file = File::create(output)?; - file.write_all(buf.as_bytes())?; - info!("Generated code"); - - info!("Formatting code with rustfmt"); - Command::new("rustfmt").arg(output).output()?; - info!("Success"); - - Ok(()) -} diff --git a/generator/src/item/rust.rs b/generator/src/item/rust.rs deleted file mode 100644 index 366289172..000000000 --- a/generator/src/item/rust.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Generates Rust code for `Item` enum. - -use crate::item::ItemReport; -use failure::Error; -use heck::CamelCase; -use proc_macro2::{Ident, Span}; - -pub fn generate_rust(report: ItemReport) -> Result<String, Error> { - let mut enum_variants = vec![]; - let mut from_identifier_arms = vec![]; - let mut to_identifier_arms = vec![]; - - for (identifier, _) in report.mappings { - let variant_name = ident(&variant_name(&identifier)); - enum_variants.push(quote! { - #variant_name - }); - - from_identifier_arms.push(quote! { - #identifier => Some(Item::#variant_name) - }); - - to_identifier_arms.push(quote! { - Item::#variant_name => #identifier - }); - } - - let result = quote! { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToPrimitive, FromPrimitive)] - pub enum Item { - #(#enum_variants, )* - } - - impl Item { - pub fn from_identifier(identifier: &str) -> Option<Self> { - match identifier { - #(#from_identifier_arms, )* - _ => None, - } - } - - pub fn identifier(self) -> &'static str { - match self { - #(#to_identifier_arms, )* - } - } - } - }; - - Ok(result.to_string()) -} - -/// Strips away the "minecraft:" prefix from a item string ID. -fn strip_prefix(val: &str) -> String { - val[10..].to_string() -} - -/// Returns the enum variant name for the given item identifier. -fn variant_name(identifier: &str) -> String { - strip_prefix(identifier).to_camel_case() -} - -fn ident(s: &str) -> Ident { - Ident::new(s, Span::call_site()) -} diff --git a/generator/src/item_to_block/mod.rs b/generator/src/item_to_block/mod.rs deleted file mode 100644 index dc4beab32..000000000 --- a/generator/src/item_to_block/mod.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Handles mapping from items to blocks and vice versa. -//! This functionality is used to perform block placements -//! and breaks. - -use crate::item::ItemReport; -use crate::rust::{correct_variable_name, PropValueType}; -use crate::{Block, BlockReport, State}; -use failure::Error; -use heck::CamelCase; -use proc_macro2::{Ident, Span, TokenStream}; -use std::fs::File; -use std::io::{Read, Write}; -use std::process::Command; -use std::str::FromStr; -use syn::{Lit, LitBool}; - -/// Given a block report and an item report, generates -/// mappings from items to blocks and writes them to -/// the file with the given path. -pub fn generate_mappings(blocks: &str, items: &str, output_path: &str) -> Result<(), Error> { - let blocks = { - let mut file = File::open(blocks)?; - let mut string = String::new(); - file.read_to_string(&mut string)?; - serde_json::from_str(&string)? - }; - - let items = { - let mut file = File::open(items)?; - let mut string = String::new(); - file.read_to_string(&mut string)?; - serde_json::from_str(&string)? - }; - - let mut output = File::create(output_path)?; - - _internal_generate_mappings(&blocks, &items, &mut output)?; - - Command::new("rustfmt").arg(output_path).output()?; - - Ok(()) -} - -fn _internal_generate_mappings( - blocks: &BlockReport, - items: &ItemReport, - output: &mut File, -) -> Result<(), Error> { - let mut item_to_block_match_arms = vec![]; - let mut block_to_item_match_arms = vec![]; - - // Go through item report and find blocks with the same - // name as the item. - for (name, _) in &items.mappings { - if let Some(match_arm) = block_state_by_name(&blocks, name.as_str()) { - item_to_block_match_arms.push(match_arm); - - let variant_ident = Ident::new(&block_variant(name), Span::call_site()); - - if blocks.blocks[name].properties.is_some() { - block_to_item_match_arms.push(quote! { - Block::#variant_ident(_) => Some(Item::#variant_ident) - }); - } else { - block_to_item_match_arms.push(quote! { - Block::#variant_ident => Some(Item::#variant_ident) - }); - } - } - } - - let result = quote! { - use feather_items::Item; - use feather_blocks::*; - - pub fn item_to_block(item: Item) -> Option<Block> { - match item { - #(#item_to_block_match_arms ,)* - _ => None, - } - } - - pub fn block_to_item(block: Block) -> Option<Item> { - match block { - #(#block_to_item_match_arms ,)* - _ => None, - } - } - }; - - output.write_all(result.to_string().as_bytes())?; - output.flush()?; - - Ok(()) -} - -fn block_state_by_name(blocks: &BlockReport, original_name: &str) -> Option<TokenStream> { - let name = block_variant(original_name); - - if let Some(block) = blocks.blocks.get(original_name) { - // The block state corresponding to the item is labeled - // in the report as "default." - let state = default_state(&block); - - let item_block_ident = Ident::new(&name, Span::call_site()); - - if block.states.len() == 1 { - Some(quote! { - Item::#item_block_ident => Some(Block::#item_block_ident) - }) - } else { - // Need to declare properties of block state - let mut props = vec![]; - let state_props = state.properties.as_ref().unwrap(); // we know the block has properties, since it has multiple states - - for (prop_name, prop_value) in &state_props.props { - let ty = PropValueType::guess_from_value(prop_value); - - let enum_name = format!("{}{}", name.to_camel_case(), prop_name.to_camel_case()); - let enum_name = Ident::new(&enum_name, Span::call_site()); - - let field_name = - Ident::new(correct_variable_name(prop_name.as_str()), Span::call_site()); - - let entry = if ty == PropValueType::Enum { - let variant = prop_value.to_camel_case(); - let variant = Ident::new(&variant, Span::call_site()); - quote! { - #field_name: #enum_name::#variant - } - } else if ty == PropValueType::Bool { - let value = Lit::Bool(LitBool { - value: bool::from_str(prop_value).unwrap(), - span: Span::call_site(), - }); - quote! { - #field_name: #value - } - } else { - let value = i32::from_str(prop_value).unwrap(); - quote! { - #field_name: #value - } - }; - props.push(entry); - } - - let data_struct_ident = format!("{}Data", name.to_camel_case()); - let data_struct_ident = Ident::new(&data_struct_ident, Span::call_site()); - - Some(quote! { - Item::#item_block_ident => Some(Block::#item_block_ident(#data_struct_ident { - #(#props ,)* - })) - }) - } - } else { - None - } -} - -fn block_variant(name: &str) -> String { - name[10..].to_camel_case() -} - -fn default_state(block: &Block) -> State { - block - .states - .iter() - .find(|state| state.default) - .unwrap() - .clone() -} diff --git a/generator/src/main.rs b/generator/src/main.rs deleted file mode 100644 index f999b200e..000000000 --- a/generator/src/main.rs +++ /dev/null @@ -1,134 +0,0 @@ -//! This program is used to generate a bunch of code, including block state ID mappings -//! and corresponding Rust code. It reads from vanilla block.json -//! files. See `block_format.md` for more information. - -#![forbid(unsafe_code, warnings)] - -#[macro_use] -extern crate serde; -#[macro_use] -extern crate derive_deref; -#[macro_use] -extern crate clap; -#[macro_use] -extern crate log; -#[macro_use] -extern crate quote; - -mod biome; -mod block_data; -mod item; -mod item_to_block; -mod rust; -mod util; - -pub use block_data::{ - Block, BlockProperties, BlockReport, State, StateProperties, DEFAULT_STATE_ID, -}; -use byteorder::{LittleEndian, WriteBytesExt}; -use clap::App; -use failure::Error; -use heck::CamelCase; -use proc_macro2::TokenStream; -use quote::quote; -use std::fs::File; -use std::io::{BufReader, Write}; -use std::process::exit; -use std::str::FromStr; -use syn::export::Span; -use syn::Ident; - -fn main() { - simple_logger::init_with_level(log::Level::Info).unwrap(); - - if let Err(e) = run() { - error!("An error occurred: {}", e); - exit(1); - } -} - -fn run() -> Result<(), Error> { - let yaml = load_yaml!("cli.yml"); - let matches = App::from_yaml(yaml).get_matches(); - - match matches.subcommand_name() { - Some("block-mappings") => { - let args = matches.subcommand_matches("block-mappings").unwrap(); - block_data::generate_mappings_file( - args.value_of("input").unwrap(), - args.value_of("output").unwrap(), - args.value_of("native").unwrap(), - u32::from_str(args.value_of("proto").unwrap())?, - args.value_of("ver").unwrap(), - )?; - } - Some("native-block-mappings") => { - let args = matches.subcommand_matches("native-block-mappings").unwrap(); - block_data::generate_native_mappings_file( - args.value_of("input").unwrap(), - args.value_of("output").unwrap(), - u32::from_str(args.value_of("proto").unwrap())?, - args.value_of("ver").unwrap(), - )?; - } - Some("block-rust") => { - let args = matches.subcommand_matches("block-rust").unwrap(); - rust::generate_rust_code( - args.value_of("input").unwrap(), - args.value_of("output").unwrap(), - )?; - } - Some("item-mappings") => { - let args = matches.subcommand_matches("item-mappings").unwrap(); - item::generate_mappings_file( - args.value_of("input").unwrap(), - args.value_of("output").unwrap(), - )?; - } - Some("item-rust") => { - let args = matches.subcommand_matches("item-rust").unwrap(); - item::generate_rust( - args.value_of("input").unwrap(), - args.value_of("output").unwrap(), - )?; - } - Some("items-to-blocks") => { - let args = matches.subcommand_matches("items-to-blocks").unwrap(); - item_to_block::generate_mappings( - args.value_of("blocks").unwrap(), - args.value_of("items").unwrap(), - args.value_of("output").unwrap(), - )?; - } - Some("biomes") => { - let args = matches.subcommand_matches("biomes").unwrap(); - biome::generate_rust( - args.value_of("input").unwrap(), - args.value_of("output").unwrap(), - )?; - } - Some(s) => { - error!("Invalid subcommand {}", s); - return Ok(()); - } - None => { - error!("No subcommand specified"); - return Ok(()); - } - } - - Ok(()) -} - -pub trait WriteExt { - fn write_string(&mut self, x: &str) -> std::io::Result<()>; -} - -impl<W: Write> WriteExt for W { - fn write_string(&mut self, x: &str) -> std::io::Result<()> { - self.write_u32::<LittleEndian>(x.len() as u32)?; - self.write_all(x.as_bytes())?; - - Ok(()) - } -} diff --git a/generator/src/rust.rs b/generator/src/rust.rs deleted file mode 100644 index 73815f2c1..000000000 --- a/generator/src/rust.rs +++ /dev/null @@ -1,780 +0,0 @@ -//! Yeah... don't even try reading this. -//! It's probably the messiest code I've ever -//! written - but at least it works. - -use super::*; -use quote::ToTokens; -use std::process::Command; -use syn::LitInt; - -pub fn generate_rust_code(input: &str, output: &str) -> Result<(), Error> { - info!( - "Writing Rust `Block` enum and data structs to {} using native input report {}", - output, input, - ); - - let in_file = File::open(input)?; - let mut out_file = File::create(output)?; - - info!("Parsing data file"); - let report: BlockReport = serde_json::from_reader(BufReader::new(&in_file))?; - info!("Parsing successful"); - - let mut enum_entries = vec![]; - //let mut name_fn_entries = vec![]; - //let mut from_name_and_props_fn_entries = vec![]; - let mut data_structs = vec![]; - let mut property_enums = vec![]; - - let mut native_type_id_entries = vec![]; - - info!("Generating code"); - - for (count, (block_name, block)) in report.blocks.iter().enumerate() { - generate_block_code( - block, - block_name, - &mut property_enums, - &mut data_structs, - &mut enum_entries, - &mut native_type_id_entries, - count, - ); - } - - let internal_id_data_offset_fn = generate_internal_id_data_offset_fn(&report); - let internal_id_offsets = generate_internal_id_offsets(&report); - let internal_state_id_fn = generate_internal_state_id_fn(); - let name_and_props_mappings = generate_name_and_props_mappings(&report); - let from_name_and_default_props_fn = generate_from_and_default_props_fn(&report); - let from_internal_state_id_fn = generate_from_internal_state_id_fn(&report); - - let block = quote! { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] - pub enum Block { - #(#enum_entries),* - } - - impl Block { - fn internal_type_id(&self) -> usize { - match self { - #(#native_type_id_entries),* - } - } - #internal_id_data_offset_fn - #internal_state_id_fn - #name_and_props_mappings - #from_name_and_default_props_fn - #from_internal_state_id_fn - } - }; - - let value = quote! { - pub trait Value { - fn value(&self) -> usize; - fn from_value(val: usize) -> Option<Self> - where Self: Sized; - } - - impl Value for i32 { - fn value(&self) -> usize { - *self as usize - } - - fn from_value(val: usize) -> Option<Self> { - Some(val as i32) - } - } - - impl Value for bool { - fn value(&self) -> usize { - match *self { - true => 1, - false => 0, - } - } - - fn from_value(val: usize) -> Option<Self> { - match val { - 0 => Some(false), - 1 => Some(true), - _ => None, - } - } - } - }; - - let from_snake_case = quote! { - pub trait FromSnakeCase { - fn from_snake_case(val: &str) -> Option<Self> - where Self: Sized; - } - - impl FromSnakeCase for i32 { - fn from_snake_case(val: &str) -> Option<Self> { - use std::str::FromStr; - match i32::from_str(val) { - Ok(x) => Some(x), - Err(_) => None, - } - } - } - - impl FromSnakeCase for bool { - fn from_snake_case(val: &str) -> Option<Self> { - use std::str::FromStr; - match bool::from_str(val) { - Ok(x) => Some(x), - Err(_) => None, - } - } - } - }; - - let to_snake_case = quote! { - pub trait ToSnakeCase { - fn to_snake_case(&self) -> String; - } - - impl ToSnakeCase for i32 { - fn to_snake_case(&self) -> String { - self.to_string() - } - } - - impl ToSnakeCase for bool { - fn to_snake_case(&self) -> String { - self.to_string() - } - } - }; - - let result = quote! { - use feather_codegen::{ToSnakeCase, FromSnakeCase}; - use std::collections::HashMap; - use num_traits::FromPrimitive; - - #internal_id_offsets - - #block - #value - #from_snake_case - #to_snake_case - #(#data_structs)* - #(#property_enums)* - }; - - out_file.write_all(b"//! This file was generated by /generators/blocks\n")?; - out_file.write_all(result.to_string().as_bytes())?; - out_file.flush()?; - - info!("Successfully wrote code to {}", output); - - info!("Formatting code with rustfmt"); - - run_rustfmt(output)?; - - info!("Success"); - - Ok(()) -} - -fn run_rustfmt(file: &str) -> Result<(), Error> { - Command::new("rustfmt").args(&[file]).output()?; - - Ok(()) -} - -fn generate_block_code( - block: &Block, - block_name: &str, - property_enums: &mut Vec<TokenStream>, - data_structs: &mut Vec<TokenStream>, - enum_entries: &mut Vec<TokenStream>, - native_type_id_entries: &mut Vec<TokenStream>, - count: usize, -) { - let variant_name = block_name[10..].to_camel_case(); - let variant_ident = Ident::new(&variant_name, Span::call_site()); - - // If block has properties, we need to create a - // data struct for the block and include it in the - // enum variant. - if block.properties.is_some() { - create_block_data_struct(&variant_name, &block, property_enums, data_structs); - let data_struct_ident = Ident::new(&format!("{}Data", variant_name), Span::call_site()); - enum_entries.push(quote! { - #variant_ident(#data_struct_ident) - }); - native_type_id_entries.push(quote! { - Block::#variant_ident(_) => #count - }); - } else { - enum_entries.push(quote! { - #variant_ident - }); - - native_type_id_entries.push(quote! { - Block::#variant_ident => #count - }); - } -} - -fn create_block_data_struct( - variant_name: &str, - block: &Block, - property_enums: &mut Vec<TokenStream>, - data_structs: &mut Vec<TokenStream>, -) { - let mut data_struct_entries = vec![]; - let mut from_map_entries = vec![]; - let mut to_map_entries = vec![]; - let mut default_impl_entries = vec![]; - - let props = &block.properties.as_ref().unwrap(); - let states = &block.states; - - for (prop_name_str, possible_values) in &props.props { - let ty = PropValueType::guess_from_value(&possible_values[0]); - - // If type is a custom enum, create the enum type - if ty == PropValueType::Enum { - create_property_enum(variant_name, prop_name_str, possible_values, property_enums); - } - - let enum_name = format!("{}{}", variant_name, prop_name_str.to_camel_case()); - - let ty_ident = Ident::new( - match ty { - PropValueType::Bool => "bool", - PropValueType::I32 => "i32", - PropValueType::Enum => &enum_name, - }, - Span::call_site(), - ); - - let field_name = Ident::new( - correct_variable_name(prop_name_str.as_str()), - Span::call_site(), - ); - - let entry = quote! { - pub #field_name: #ty_ident - }; - data_struct_entries.push(entry); - - from_map_entries.push(quote! { - #field_name: #ty_ident::from_snake_case(map.get(#prop_name_str)?)? - }); - - to_map_entries.push(quote! { - m.insert(#prop_name_str.to_string(), self.#field_name.to_snake_case()); - }); - - // Find default state and create an entry in the Default impl for it - let default_state = states.iter().find(|state| state.default).unwrap(); - - let default_value = { - let value_str = &default_state.properties.as_ref().unwrap().props[prop_name_str]; - - value_from_string(ty, variant_name, prop_name_str, value_str) - }; - - default_impl_entries.push(quote! { - #field_name: #default_value, - }); - } - - let data_ident = Ident::new(&format!("{}Data", variant_name), Span::call_site()); - - let value_impl = generate_value_implementation(&data_ident, props, &variant_name); - - let data_struct = quote! { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] - pub struct #data_ident { - #(#data_struct_entries),* - } - - impl #data_ident { - pub fn from_map(map: &HashMap<String, String>) -> Option<Self> { - Some(Self { - #(#from_map_entries),* - }) - } - - pub fn to_map(&self) -> HashMap<String, String> { - let mut m = HashMap::new(); - #(#to_map_entries)* - m - } - } - - impl Default for #data_ident { - fn default() -> Self { - Self { - #(#default_impl_entries)* - } - } - } - - #value_impl - }; - - data_structs.push(data_struct); -} - -fn value_from_string( - value_ty: PropValueType, - variant_name: &str, - prop_name: &str, - value_str: &str, -) -> Box<dyn ToTokens> { - match value_ty { - PropValueType::I32 => Box::new(LitInt::new(value_str, Span::call_site())), - PropValueType::Bool => Box::new(Ident::new(value_str, Span::call_site())), - PropValueType::Enum => { - let enum_ident = enum_ident(variant_name, prop_name); - let value_ident = Ident::new(&value_str.to_camel_case(), Span::call_site()); - Box::new(quote! { - #enum_ident::#value_ident - }) - } - } -} - -fn enum_ident(variant_name: &str, prop_name: &str) -> Ident { - Ident::new( - &format!("{}{}", variant_name, prop_name.to_camel_case()), - Span::call_site(), - ) -} - -fn create_property_enum( - variant_name: &str, - prop_name: &str, - possible_values: &[String], - property_enums: &mut Vec<TokenStream>, -) { - let enum_ident = enum_ident(variant_name, prop_name); - - let mut enum_variants = vec![]; - - for possible_value_str in possible_values { - let possible_value = Ident::new( - possible_value_str.to_camel_case().as_str(), - Span::call_site(), - ); - enum_variants.push(quote! { - #possible_value - }); - } - - let en = quote! { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToSnakeCase, FromSnakeCase, FromPrimitive)] - pub enum #enum_ident { - #(#enum_variants),* - } - - impl Value for #enum_ident { - fn value(&self) -> usize { - *self as usize - } - fn from_value(val: usize) -> Option<Self> { - Self::from_usize(val) - } - } - }; - - property_enums.push(en); -} - -pub fn correct_variable_name(name: &str) -> &str { - match name { - "type" => "ty", - "in" => "_in", - name => name, - } -} - -/// A property value type. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum PropValueType { - Enum, - I32, - Bool, -} - -impl PropValueType { - pub fn guess_from_value(value: &str) -> Self { - if i32::from_str(value).is_ok() { - PropValueType::I32 - } else if bool::from_str(value).is_ok() { - PropValueType::Bool - } else { - PropValueType::Enum // Custom enum - } - } -} - -/// Generates a `Value` implementation for -/// a data struct. -/// -/// This uses a special algorithm to generate -/// consecutive values in constant time. -fn generate_value_implementation( - data_struct_ident: &Ident, - props: &BlockProperties, - variant_name: &str, -) -> TokenStream { - use crate::util::{min_in_slice, slice_product}; - - let mut terms = vec![]; - - let possible_value_lens: Vec<usize> = props - .props - .iter() - .map(|(_, possible_values)| possible_values.len()) - .collect(); - - let total_permutations = slice_product(&possible_value_lens); - - for (count, (prop_name, vals)) in props.props.iter().enumerate() { - let multiplier = if count == props.props.len() - 1 { - // This is the last property - just multiply by 1. - 1 - } else { - slice_product(&possible_value_lens[count + 1..]) - }; - - // If the property is an integer and it starts at 1 rather - // than 0, we need to subtract 1 for the function to work correctly. - let mut should_subtract = false; - let prop_type = PropValueType::guess_from_value(&vals[0]); - if prop_type == PropValueType::I32 { - let vals: Vec<i32> = vals.iter().map(|val| i32::from_str(val).unwrap()).collect(); - if min_in_slice(&vals) == 1 { - should_subtract = true; - } - // TODO account for values which start at neither 0 nor 1 - - // this hasn't been observed yet - assert!(min_in_slice(&vals) <= 1); - } - - let prop_field = Ident::new(correct_variable_name(prop_name.as_str()), Span::call_site()); - - if should_subtract { - terms.push(quote! { - ((self.#prop_field.value() - 1) * #multiplier) - }); - } else { - terms.push(quote! { - (self.#prop_field.value() * #multiplier) - }) - } - } - - // Calculate from_value function - - let mut variable_setters = vec![]; // e.g. "let facing = ..." - let mut field_setters = vec![]; // e.g. "facing," - - for (count, (prop_name, vals)) in props.props.iter().enumerate() { - let prop_field = Ident::new(correct_variable_name(prop_name.as_str()), Span::call_site()); - let prop_stride = if count == props.props.len() - 1 { - 1 - } else { - slice_product(&possible_value_lens[count + 1..]) - }; - - let ty = PropValueType::guess_from_value(vals[0].as_str()); - let enum_name = format!("{}{}", variant_name, prop_name.to_camel_case()); - - let ty_ident = Ident::new( - match ty { - PropValueType::Bool => "bool", - PropValueType::I32 => "i32", - PropValueType::Enum => &enum_name, - }, - Span::call_site(), - ); - - // If the property is an integer and it starts at 1 rather - // than 0, we need to subtract 1 for the function to work correctly. - let mut should_subtract = false; - let prop_type = PropValueType::guess_from_value(&vals[0]); - if prop_type == PropValueType::I32 { - let vals: Vec<i32> = vals.iter().map(|val| i32::from_str(val).unwrap()).collect(); - if min_in_slice(&vals) == 1 { - should_subtract = true; - } - // TODO account for values which start at neither 0 nor 1 - - // this hasn't been observed yet - assert!(min_in_slice(&vals) <= 1); - } - - let add: i32 = if should_subtract { 1 } else { 0 }; - let subtract: usize = if should_subtract { 1 } else { 0 }; - - if should_subtract { - variable_setters.push(quote! { - let #prop_field = #ty_ident::from_value(val / #prop_stride).unwrap() + #add; - }); - } else { - variable_setters.push(quote! { - let #prop_field = #ty_ident::from_value(val / #prop_stride).unwrap(); - }); - } - - variable_setters.push(quote! { - val -= (#prop_field.value() - #subtract) * #prop_stride; - }); - - field_setters.push(quote! { - #prop_field - }); - } - - let result = quote! { - impl Value for #data_struct_ident { - fn value(&self) -> usize { - #(#terms)+* - } - - #[allow(warnings)] - fn from_value(mut val: usize) -> Option<Self> { - if val >= #total_permutations { - return None; - } - - #(#variable_setters)* - - Some(Self { - #(#field_setters,)* - }) - } - } - }; - - result -} - -/// Generates the function which retrieves the offset -/// from the block type's internal ID to the block state -/// internal ID. -fn generate_internal_id_data_offset_fn(report: &BlockReport) -> TokenStream { - let mut match_arms = vec![]; - - for (block_name, block) in &report.blocks { - let ident = Ident::new(&block_name[10..].to_camel_case(), Span::call_site()); - match_arms.push(if block.properties.is_some() { - quote! { - Block::#ident(data) => data.value() - } - } else { - quote! { - Block::#ident => 0 - } - }); - } - - let result = quote! { - fn internal_id_data_offset(&self) -> usize { - match self { - #(#match_arms ,)* - } - } - }; - result -} - -/// Generates the global internal ID offsets array -/// which contains mappings from internal block type -/// IDs to their respective offsets. -/// To calculate the internal state ID of a block state, -/// add the block type ID offset from this from this array -/// to the internal_id_data_offset generated above. -fn generate_internal_id_offsets(report: &BlockReport) -> TokenStream { - let mut entries = vec![]; - - let mut count = 0usize; - for (_, block) in &report.blocks { - entries.push(quote! { - #count - }); - - count += block.states.len(); - } - - let amnt = report.blocks.len(); - - let result = quote! { - const INTERNAL_ID_OFFSETS: [usize; #amnt] = [ - #(#entries ,)* - ]; - }; - result -} - -/// Generates the `internal_state_id` function. -fn generate_internal_state_id_fn() -> TokenStream { - quote! { - pub fn internal_state_id(&self) -> usize { - let type_offset = INTERNAL_ID_OFFSETS[self.internal_type_id()]; - let data_offset = self.internal_id_data_offset(); - - type_offset + data_offset - } - } -} - -/// Generates the `from_internal_state_id` function. -fn generate_from_internal_state_id_fn(report: &BlockReport) -> TokenStream { - let mut match_arms = vec![]; - - let mut count = 0; - for (block_name, block) in &report.blocks { - let variant_name = block_name[10..].to_camel_case(); - let variant_ident = Ident::new(&variant_name, Span::call_site()); - - if block.properties.is_some() { - let range_start = count; - let range_end = range_start + block.states.len() - 1; - - let data_struct_str = format!("{}Data", variant_name); - let data_struct_ident = Ident::new(&data_struct_str, Span::call_site()); - - match_arms.push(quote! { - #range_start..=#range_end => { - let offset = id - #range_start; - let data = #data_struct_ident::from_value(offset)?; - Some(Block::#variant_ident(data)) - } - }); - } else { - match_arms.push(quote! { - #count => { - Some(Block::#variant_ident) - } - }); - } - - count += block.states.len(); - } - - let result = quote! { - pub fn from_internal_state_id(id: usize) -> Option<Self> { - match id { - #(#match_arms,)* - _ => None, - } - } - }; - result -} - -/// Generates `from_name_and_props` and `to_name_and_props`. -fn generate_name_and_props_mappings(report: &BlockReport) -> TokenStream { - let mut from_name_and_props_match_arms = vec![]; - let mut to_name_and_props_match_arms = vec![]; - - for (block_name, block) in &report.blocks { - let variant_name = block_name[10..].to_camel_case(); - let variant_ident = Ident::new(&variant_name, Span::call_site()); - - if let Some(props) = &block.properties { - let data_struct_str = format!("{}Data", variant_name); - let data_struct_ident = Ident::new(&data_struct_str, Span::call_site()); - - from_name_and_props_match_arms.push(quote! { - #block_name => { - let data = #data_struct_ident::from_map(props)?; - Some(Block::#variant_ident(data)) - } - }); - - // to_name_and_props: properties - let mut property_setters = vec![]; - - for property_name in props.props.keys() { - let field_name = - Ident::new(correct_variable_name(property_name), Span::call_site()); - - property_setters.push(quote! { - props.push((#property_name, data.#field_name.to_snake_case())); - }); - } - - to_name_and_props_match_arms.push(quote! { - Block::#variant_ident(data) => { - #(#property_setters)* - #block_name - } - }); - } else { - from_name_and_props_match_arms.push(quote! { - #block_name => Some(Block::#variant_ident) - }); - to_name_and_props_match_arms.push(quote! { - Block::#variant_ident => #block_name - }); - } - } - - let result = quote! { - pub fn from_name_and_props(name: &str, props: &HashMap<String, String>) -> Option<Self> { - match name { - #(#from_name_and_props_match_arms ,)* - _ => None, - } - } - - pub fn to_name_and_props(&self) -> (&'static str, Vec<(&'static str, String)>) { - let mut props = vec![]; - - let name = match self { - #(#to_name_and_props_match_arms ,)* - }; - - (name, props) - } - }; - result -} - -/// Generates the `from_name_and_default_props` function. -fn generate_from_and_default_props_fn(report: &BlockReport) -> TokenStream { - // More duplicate code than ever before! - // This entire file should probably be rewritten at some point. - let mut match_arms = vec![]; - - for (block_name, block) in &report.blocks { - let variant_name = block_name[10..].to_camel_case(); - let variant_ident = Ident::new(&variant_name, Span::call_site()); - - if block.properties.is_some() { - let data_struct_str = format!("{}Data", variant_name); - let data_struct_ident = Ident::new(&data_struct_str, Span::call_site()); - - match_arms.push(quote! { - #block_name => { - let data = #data_struct_ident::default(); - Some(Block::#variant_ident(data)) - } - }); - } else { - match_arms.push(quote! { - #block_name => Some(Block::#variant_ident) - }); - } - } - - let result = quote! { - pub fn from_name_and_default_props(name: &str) -> Option<Self> { - match name { - #(#match_arms ,)* - _ => None, - } - } - }; - result -} diff --git a/generator/src/util.rs b/generator/src/util.rs deleted file mode 100644 index 14e6efe97..000000000 --- a/generator/src/util.rs +++ /dev/null @@ -1,36 +0,0 @@ -/// Calculates the product of all values in the given slice. -pub fn slice_product(slice: &[usize]) -> usize { - let mut result = 1; - for val in slice { - result *= *val; - } - - result -} - -/* -/// Returns the highest value in a slice. -pub fn max_in_slice<O: Ord + Copy>(slice: &[O]) -> O { - assert!(!slice.is_empty()); - let mut highest = slice[0]; - for val in slice { - if *val > highest { - highest = *val; - } - } - - highest -}*/ - -/// Returns the lowest value in a slice. -pub fn min_in_slice<O: Ord + Copy>(slice: &[O]) -> O { - assert!(!slice.is_empty()); - let mut lowest = slice[0]; - for val in slice { - if *val < lowest { - lowest = *val; - } - } - - lowest -} diff --git a/item_block/src/mappings.rs b/item_block/src/mappings.rs deleted file mode 100644 index 806de1e85..000000000 --- a/item_block/src/mappings.rs +++ /dev/null @@ -1,1947 +0,0 @@ -use feather_blocks::*; -use feather_items::Item; -pub fn item_to_block(item: Item) -> Option<Block> { - match item { - Item::Air => Some(Block::Air), - Item::Stone => Some(Block::Stone), - Item::Granite => Some(Block::Granite), - Item::PolishedGranite => Some(Block::PolishedGranite), - Item::Diorite => Some(Block::Diorite), - Item::PolishedDiorite => Some(Block::PolishedDiorite), - Item::Andesite => Some(Block::Andesite), - Item::PolishedAndesite => Some(Block::PolishedAndesite), - Item::GrassBlock => Some(Block::GrassBlock(GrassBlockData { snowy: false })), - Item::Dirt => Some(Block::Dirt), - Item::CoarseDirt => Some(Block::CoarseDirt), - Item::Podzol => Some(Block::Podzol(PodzolData { snowy: false })), - Item::Cobblestone => Some(Block::Cobblestone), - Item::OakPlanks => Some(Block::OakPlanks), - Item::SprucePlanks => Some(Block::SprucePlanks), - Item::BirchPlanks => Some(Block::BirchPlanks), - Item::JunglePlanks => Some(Block::JunglePlanks), - Item::AcaciaPlanks => Some(Block::AcaciaPlanks), - Item::DarkOakPlanks => Some(Block::DarkOakPlanks), - Item::OakSapling => Some(Block::OakSapling(OakSaplingData { stage: 0i32 })), - Item::SpruceSapling => Some(Block::SpruceSapling(SpruceSaplingData { stage: 0i32 })), - Item::BirchSapling => Some(Block::BirchSapling(BirchSaplingData { stage: 0i32 })), - Item::JungleSapling => Some(Block::JungleSapling(JungleSaplingData { stage: 0i32 })), - Item::AcaciaSapling => Some(Block::AcaciaSapling(AcaciaSaplingData { stage: 0i32 })), - Item::DarkOakSapling => Some(Block::DarkOakSapling(DarkOakSaplingData { stage: 0i32 })), - Item::Bedrock => Some(Block::Bedrock), - Item::Sand => Some(Block::Sand), - Item::RedSand => Some(Block::RedSand), - Item::Gravel => Some(Block::Gravel), - Item::GoldOre => Some(Block::GoldOre), - Item::IronOre => Some(Block::IronOre), - Item::CoalOre => Some(Block::CoalOre), - Item::OakLog => Some(Block::OakLog(OakLogData { - axis: OakLogAxis::Y, - })), - Item::SpruceLog => Some(Block::SpruceLog(SpruceLogData { - axis: SpruceLogAxis::Y, - })), - Item::BirchLog => Some(Block::BirchLog(BirchLogData { - axis: BirchLogAxis::Y, - })), - Item::JungleLog => Some(Block::JungleLog(JungleLogData { - axis: JungleLogAxis::Y, - })), - Item::AcaciaLog => Some(Block::AcaciaLog(AcaciaLogData { - axis: AcaciaLogAxis::Y, - })), - Item::DarkOakLog => Some(Block::DarkOakLog(DarkOakLogData { - axis: DarkOakLogAxis::Y, - })), - Item::StrippedOakLog => Some(Block::StrippedOakLog(StrippedOakLogData { - axis: StrippedOakLogAxis::Y, - })), - Item::StrippedSpruceLog => Some(Block::StrippedSpruceLog(StrippedSpruceLogData { - axis: StrippedSpruceLogAxis::Y, - })), - Item::StrippedBirchLog => Some(Block::StrippedBirchLog(StrippedBirchLogData { - axis: StrippedBirchLogAxis::Y, - })), - Item::StrippedJungleLog => Some(Block::StrippedJungleLog(StrippedJungleLogData { - axis: StrippedJungleLogAxis::Y, - })), - Item::StrippedAcaciaLog => Some(Block::StrippedAcaciaLog(StrippedAcaciaLogData { - axis: StrippedAcaciaLogAxis::Y, - })), - Item::StrippedDarkOakLog => Some(Block::StrippedDarkOakLog(StrippedDarkOakLogData { - axis: StrippedDarkOakLogAxis::Y, - })), - Item::StrippedOakWood => Some(Block::StrippedOakWood(StrippedOakWoodData { - axis: StrippedOakWoodAxis::Y, - })), - Item::StrippedSpruceWood => Some(Block::StrippedSpruceWood(StrippedSpruceWoodData { - axis: StrippedSpruceWoodAxis::Y, - })), - Item::StrippedBirchWood => Some(Block::StrippedBirchWood(StrippedBirchWoodData { - axis: StrippedBirchWoodAxis::Y, - })), - Item::StrippedJungleWood => Some(Block::StrippedJungleWood(StrippedJungleWoodData { - axis: StrippedJungleWoodAxis::Y, - })), - Item::StrippedAcaciaWood => Some(Block::StrippedAcaciaWood(StrippedAcaciaWoodData { - axis: StrippedAcaciaWoodAxis::Y, - })), - Item::StrippedDarkOakWood => Some(Block::StrippedDarkOakWood(StrippedDarkOakWoodData { - axis: StrippedDarkOakWoodAxis::Y, - })), - Item::OakWood => Some(Block::OakWood(OakWoodData { - axis: OakWoodAxis::Y, - })), - Item::SpruceWood => Some(Block::SpruceWood(SpruceWoodData { - axis: SpruceWoodAxis::Y, - })), - Item::BirchWood => Some(Block::BirchWood(BirchWoodData { - axis: BirchWoodAxis::Y, - })), - Item::JungleWood => Some(Block::JungleWood(JungleWoodData { - axis: JungleWoodAxis::Y, - })), - Item::AcaciaWood => Some(Block::AcaciaWood(AcaciaWoodData { - axis: AcaciaWoodAxis::Y, - })), - Item::DarkOakWood => Some(Block::DarkOakWood(DarkOakWoodData { - axis: DarkOakWoodAxis::Y, - })), - Item::OakLeaves => Some(Block::OakLeaves(OakLeavesData { - persistent: false, - distance: 7i32, - })), - Item::SpruceLeaves => Some(Block::SpruceLeaves(SpruceLeavesData { - persistent: false, - distance: 7i32, - })), - Item::BirchLeaves => Some(Block::BirchLeaves(BirchLeavesData { - persistent: false, - distance: 7i32, - })), - Item::JungleLeaves => Some(Block::JungleLeaves(JungleLeavesData { - persistent: false, - distance: 7i32, - })), - Item::AcaciaLeaves => Some(Block::AcaciaLeaves(AcaciaLeavesData { - persistent: false, - distance: 7i32, - })), - Item::DarkOakLeaves => Some(Block::DarkOakLeaves(DarkOakLeavesData { - distance: 7i32, - persistent: false, - })), - Item::Sponge => Some(Block::Sponge), - Item::WetSponge => Some(Block::WetSponge), - Item::Glass => Some(Block::Glass), - Item::LapisOre => Some(Block::LapisOre), - Item::LapisBlock => Some(Block::LapisBlock), - Item::Dispenser => Some(Block::Dispenser(DispenserData { - triggered: false, - facing: DispenserFacing::North, - })), - Item::Sandstone => Some(Block::Sandstone), - Item::ChiseledSandstone => Some(Block::ChiseledSandstone), - Item::CutSandstone => Some(Block::CutSandstone), - Item::NoteBlock => Some(Block::NoteBlock(NoteBlockData { - instrument: NoteBlockInstrument::Harp, - powered: false, - note: 0i32, - })), - Item::PoweredRail => Some(Block::PoweredRail(PoweredRailData { - shape: PoweredRailShape::NorthSouth, - powered: false, - })), - Item::DetectorRail => Some(Block::DetectorRail(DetectorRailData { - powered: false, - shape: DetectorRailShape::NorthSouth, - })), - Item::StickyPiston => Some(Block::StickyPiston(StickyPistonData { - facing: StickyPistonFacing::North, - extended: false, - })), - Item::Cobweb => Some(Block::Cobweb), - Item::Grass => Some(Block::Grass), - Item::Fern => Some(Block::Fern), - Item::DeadBush => Some(Block::DeadBush), - Item::Seagrass => Some(Block::Seagrass), - Item::SeaPickle => Some(Block::SeaPickle(SeaPickleData { - pickles: 1i32, - waterlogged: true, - })), - Item::Piston => Some(Block::Piston(PistonData { - facing: PistonFacing::North, - extended: false, - })), - Item::WhiteWool => Some(Block::WhiteWool), - Item::OrangeWool => Some(Block::OrangeWool), - Item::MagentaWool => Some(Block::MagentaWool), - Item::LightBlueWool => Some(Block::LightBlueWool), - Item::YellowWool => Some(Block::YellowWool), - Item::LimeWool => Some(Block::LimeWool), - Item::PinkWool => Some(Block::PinkWool), - Item::GrayWool => Some(Block::GrayWool), - Item::LightGrayWool => Some(Block::LightGrayWool), - Item::CyanWool => Some(Block::CyanWool), - Item::PurpleWool => Some(Block::PurpleWool), - Item::BlueWool => Some(Block::BlueWool), - Item::BrownWool => Some(Block::BrownWool), - Item::GreenWool => Some(Block::GreenWool), - Item::RedWool => Some(Block::RedWool), - Item::BlackWool => Some(Block::BlackWool), - Item::Dandelion => Some(Block::Dandelion), - Item::Poppy => Some(Block::Poppy), - Item::BlueOrchid => Some(Block::BlueOrchid), - Item::Allium => Some(Block::Allium), - Item::AzureBluet => Some(Block::AzureBluet), - Item::RedTulip => Some(Block::RedTulip), - Item::OrangeTulip => Some(Block::OrangeTulip), - Item::WhiteTulip => Some(Block::WhiteTulip), - Item::PinkTulip => Some(Block::PinkTulip), - Item::OxeyeDaisy => Some(Block::OxeyeDaisy), - Item::BrownMushroom => Some(Block::BrownMushroom), - Item::RedMushroom => Some(Block::RedMushroom), - Item::GoldBlock => Some(Block::GoldBlock), - Item::IronBlock => Some(Block::IronBlock), - Item::OakSlab => Some(Block::OakSlab(OakSlabData { - ty: OakSlabType::Bottom, - waterlogged: false, - })), - Item::SpruceSlab => Some(Block::SpruceSlab(SpruceSlabData { - waterlogged: false, - ty: SpruceSlabType::Bottom, - })), - Item::BirchSlab => Some(Block::BirchSlab(BirchSlabData { - ty: BirchSlabType::Bottom, - waterlogged: false, - })), - Item::JungleSlab => Some(Block::JungleSlab(JungleSlabData { - ty: JungleSlabType::Bottom, - waterlogged: false, - })), - Item::AcaciaSlab => Some(Block::AcaciaSlab(AcaciaSlabData { - ty: AcaciaSlabType::Bottom, - waterlogged: false, - })), - Item::DarkOakSlab => Some(Block::DarkOakSlab(DarkOakSlabData { - waterlogged: false, - ty: DarkOakSlabType::Bottom, - })), - Item::StoneSlab => Some(Block::StoneSlab(StoneSlabData { - ty: StoneSlabType::Bottom, - waterlogged: false, - })), - Item::SandstoneSlab => Some(Block::SandstoneSlab(SandstoneSlabData { - waterlogged: false, - ty: SandstoneSlabType::Bottom, - })), - Item::PetrifiedOakSlab => Some(Block::PetrifiedOakSlab(PetrifiedOakSlabData { - waterlogged: false, - ty: PetrifiedOakSlabType::Bottom, - })), - Item::CobblestoneSlab => Some(Block::CobblestoneSlab(CobblestoneSlabData { - ty: CobblestoneSlabType::Bottom, - waterlogged: false, - })), - Item::BrickSlab => Some(Block::BrickSlab(BrickSlabData { - ty: BrickSlabType::Bottom, - waterlogged: false, - })), - Item::StoneBrickSlab => Some(Block::StoneBrickSlab(StoneBrickSlabData { - ty: StoneBrickSlabType::Bottom, - waterlogged: false, - })), - Item::NetherBrickSlab => Some(Block::NetherBrickSlab(NetherBrickSlabData { - ty: NetherBrickSlabType::Bottom, - waterlogged: false, - })), - Item::QuartzSlab => Some(Block::QuartzSlab(QuartzSlabData { - waterlogged: false, - ty: QuartzSlabType::Bottom, - })), - Item::RedSandstoneSlab => Some(Block::RedSandstoneSlab(RedSandstoneSlabData { - ty: RedSandstoneSlabType::Bottom, - waterlogged: false, - })), - Item::PurpurSlab => Some(Block::PurpurSlab(PurpurSlabData { - ty: PurpurSlabType::Bottom, - waterlogged: false, - })), - Item::PrismarineSlab => Some(Block::PrismarineSlab(PrismarineSlabData { - ty: PrismarineSlabType::Bottom, - waterlogged: false, - })), - Item::PrismarineBrickSlab => Some(Block::PrismarineBrickSlab(PrismarineBrickSlabData { - ty: PrismarineBrickSlabType::Bottom, - waterlogged: false, - })), - Item::DarkPrismarineSlab => Some(Block::DarkPrismarineSlab(DarkPrismarineSlabData { - waterlogged: false, - ty: DarkPrismarineSlabType::Bottom, - })), - Item::SmoothQuartz => Some(Block::SmoothQuartz), - Item::SmoothRedSandstone => Some(Block::SmoothRedSandstone), - Item::SmoothSandstone => Some(Block::SmoothSandstone), - Item::SmoothStone => Some(Block::SmoothStone), - Item::Bricks => Some(Block::Bricks), - Item::Tnt => Some(Block::Tnt(TntData { unstable: false })), - Item::Bookshelf => Some(Block::Bookshelf), - Item::MossyCobblestone => Some(Block::MossyCobblestone), - Item::Obsidian => Some(Block::Obsidian), - Item::Torch => Some(Block::Torch), - Item::EndRod => Some(Block::EndRod(EndRodData { - facing: EndRodFacing::Up, - })), - Item::ChorusPlant => Some(Block::ChorusPlant(ChorusPlantData { - east: false, - west: false, - north: false, - down: false, - south: false, - up: false, - })), - Item::ChorusFlower => Some(Block::ChorusFlower(ChorusFlowerData { age: 0i32 })), - Item::PurpurBlock => Some(Block::PurpurBlock), - Item::PurpurPillar => Some(Block::PurpurPillar(PurpurPillarData { - axis: PurpurPillarAxis::Y, - })), - Item::PurpurStairs => Some(Block::PurpurStairs(PurpurStairsData { - shape: PurpurStairsShape::Straight, - waterlogged: false, - half: PurpurStairsHalf::Bottom, - facing: PurpurStairsFacing::North, - })), - Item::Spawner => Some(Block::Spawner), - Item::OakStairs => Some(Block::OakStairs(OakStairsData { - half: OakStairsHalf::Bottom, - waterlogged: false, - shape: OakStairsShape::Straight, - facing: OakStairsFacing::North, - })), - Item::Chest => Some(Block::Chest(ChestData { - waterlogged: false, - facing: ChestFacing::North, - ty: ChestType::Single, - })), - Item::DiamondOre => Some(Block::DiamondOre), - Item::DiamondBlock => Some(Block::DiamondBlock), - Item::CraftingTable => Some(Block::CraftingTable), - Item::Farmland => Some(Block::Farmland(FarmlandData { moisture: 0i32 })), - Item::Furnace => Some(Block::Furnace(FurnaceData { - lit: false, - facing: FurnaceFacing::North, - })), - Item::Ladder => Some(Block::Ladder(LadderData { - facing: LadderFacing::North, - waterlogged: false, - })), - Item::Rail => Some(Block::Rail(RailData { - shape: RailShape::NorthSouth, - })), - Item::CobblestoneStairs => Some(Block::CobblestoneStairs(CobblestoneStairsData { - half: CobblestoneStairsHalf::Bottom, - shape: CobblestoneStairsShape::Straight, - facing: CobblestoneStairsFacing::North, - waterlogged: false, - })), - Item::Lever => Some(Block::Lever(LeverData { - face: LeverFace::Wall, - facing: LeverFacing::North, - powered: false, - })), - Item::StonePressurePlate => Some(Block::StonePressurePlate(StonePressurePlateData { - powered: false, - })), - Item::OakPressurePlate => Some(Block::OakPressurePlate(OakPressurePlateData { - powered: false, - })), - Item::SprucePressurePlate => Some(Block::SprucePressurePlate(SprucePressurePlateData { - powered: false, - })), - Item::BirchPressurePlate => Some(Block::BirchPressurePlate(BirchPressurePlateData { - powered: false, - })), - Item::JunglePressurePlate => Some(Block::JunglePressurePlate(JunglePressurePlateData { - powered: false, - })), - Item::AcaciaPressurePlate => Some(Block::AcaciaPressurePlate(AcaciaPressurePlateData { - powered: false, - })), - Item::DarkOakPressurePlate => Some(Block::DarkOakPressurePlate(DarkOakPressurePlateData { - powered: false, - })), - Item::RedstoneOre => Some(Block::RedstoneOre(RedstoneOreData { lit: false })), - Item::RedstoneTorch => Some(Block::RedstoneTorch(RedstoneTorchData { lit: true })), - Item::StoneButton => Some(Block::StoneButton(StoneButtonData { - facing: StoneButtonFacing::North, - face: StoneButtonFace::Wall, - powered: false, - })), - Item::Snow => Some(Block::Snow(SnowData { layers: 1i32 })), - Item::Ice => Some(Block::Ice), - Item::SnowBlock => Some(Block::SnowBlock), - Item::Cactus => Some(Block::Cactus(CactusData { age: 0i32 })), - Item::Clay => Some(Block::Clay), - Item::Jukebox => Some(Block::Jukebox(JukeboxData { has_record: false })), - Item::OakFence => Some(Block::OakFence(OakFenceData { - south: false, - waterlogged: false, - west: false, - east: false, - north: false, - })), - Item::SpruceFence => Some(Block::SpruceFence(SpruceFenceData { - north: false, - waterlogged: false, - south: false, - east: false, - west: false, - })), - Item::BirchFence => Some(Block::BirchFence(BirchFenceData { - waterlogged: false, - west: false, - north: false, - east: false, - south: false, - })), - Item::JungleFence => Some(Block::JungleFence(JungleFenceData { - waterlogged: false, - north: false, - west: false, - south: false, - east: false, - })), - Item::AcaciaFence => Some(Block::AcaciaFence(AcaciaFenceData { - east: false, - waterlogged: false, - west: false, - south: false, - north: false, - })), - Item::DarkOakFence => Some(Block::DarkOakFence(DarkOakFenceData { - north: false, - south: false, - east: false, - waterlogged: false, - west: false, - })), - Item::Pumpkin => Some(Block::Pumpkin), - Item::CarvedPumpkin => Some(Block::CarvedPumpkin(CarvedPumpkinData { - facing: CarvedPumpkinFacing::North, - })), - Item::Netherrack => Some(Block::Netherrack), - Item::SoulSand => Some(Block::SoulSand), - Item::Glowstone => Some(Block::Glowstone), - Item::JackOLantern => Some(Block::JackOLantern(JackOLanternData { - facing: JackOLanternFacing::North, - })), - Item::OakTrapdoor => Some(Block::OakTrapdoor(OakTrapdoorData { - waterlogged: false, - facing: OakTrapdoorFacing::North, - open: false, - half: OakTrapdoorHalf::Bottom, - powered: false, - })), - Item::SpruceTrapdoor => Some(Block::SpruceTrapdoor(SpruceTrapdoorData { - open: false, - waterlogged: false, - powered: false, - facing: SpruceTrapdoorFacing::North, - half: SpruceTrapdoorHalf::Bottom, - })), - Item::BirchTrapdoor => Some(Block::BirchTrapdoor(BirchTrapdoorData { - facing: BirchTrapdoorFacing::North, - waterlogged: false, - powered: false, - half: BirchTrapdoorHalf::Bottom, - open: false, - })), - Item::JungleTrapdoor => Some(Block::JungleTrapdoor(JungleTrapdoorData { - facing: JungleTrapdoorFacing::North, - half: JungleTrapdoorHalf::Bottom, - powered: false, - waterlogged: false, - open: false, - })), - Item::AcaciaTrapdoor => Some(Block::AcaciaTrapdoor(AcaciaTrapdoorData { - facing: AcaciaTrapdoorFacing::North, - half: AcaciaTrapdoorHalf::Bottom, - powered: false, - open: false, - waterlogged: false, - })), - Item::DarkOakTrapdoor => Some(Block::DarkOakTrapdoor(DarkOakTrapdoorData { - powered: false, - facing: DarkOakTrapdoorFacing::North, - open: false, - half: DarkOakTrapdoorHalf::Bottom, - waterlogged: false, - })), - Item::InfestedStone => Some(Block::InfestedStone), - Item::InfestedCobblestone => Some(Block::InfestedCobblestone), - Item::InfestedStoneBricks => Some(Block::InfestedStoneBricks), - Item::InfestedMossyStoneBricks => Some(Block::InfestedMossyStoneBricks), - Item::InfestedCrackedStoneBricks => Some(Block::InfestedCrackedStoneBricks), - Item::InfestedChiseledStoneBricks => Some(Block::InfestedChiseledStoneBricks), - Item::StoneBricks => Some(Block::StoneBricks), - Item::MossyStoneBricks => Some(Block::MossyStoneBricks), - Item::CrackedStoneBricks => Some(Block::CrackedStoneBricks), - Item::ChiseledStoneBricks => Some(Block::ChiseledStoneBricks), - Item::BrownMushroomBlock => Some(Block::BrownMushroomBlock(BrownMushroomBlockData { - east: true, - down: true, - up: true, - south: true, - west: true, - north: true, - })), - Item::RedMushroomBlock => Some(Block::RedMushroomBlock(RedMushroomBlockData { - south: true, - up: true, - west: true, - east: true, - north: true, - down: true, - })), - Item::MushroomStem => Some(Block::MushroomStem(MushroomStemData { - east: true, - up: true, - north: true, - west: true, - down: true, - south: true, - })), - Item::IronBars => Some(Block::IronBars(IronBarsData { - east: false, - south: false, - north: false, - west: false, - waterlogged: false, - })), - Item::GlassPane => Some(Block::GlassPane(GlassPaneData { - waterlogged: false, - north: false, - west: false, - south: false, - east: false, - })), - Item::Melon => Some(Block::Melon), - Item::Vine => Some(Block::Vine(VineData { - south: false, - north: false, - up: false, - east: false, - west: false, - })), - Item::OakFenceGate => Some(Block::OakFenceGate(OakFenceGateData { - facing: OakFenceGateFacing::North, - in_wall: false, - open: false, - powered: false, - })), - Item::SpruceFenceGate => Some(Block::SpruceFenceGate(SpruceFenceGateData { - facing: SpruceFenceGateFacing::North, - powered: false, - open: false, - in_wall: false, - })), - Item::BirchFenceGate => Some(Block::BirchFenceGate(BirchFenceGateData { - powered: false, - in_wall: false, - open: false, - facing: BirchFenceGateFacing::North, - })), - Item::JungleFenceGate => Some(Block::JungleFenceGate(JungleFenceGateData { - powered: false, - in_wall: false, - facing: JungleFenceGateFacing::North, - open: false, - })), - Item::AcaciaFenceGate => Some(Block::AcaciaFenceGate(AcaciaFenceGateData { - facing: AcaciaFenceGateFacing::North, - powered: false, - open: false, - in_wall: false, - })), - Item::DarkOakFenceGate => Some(Block::DarkOakFenceGate(DarkOakFenceGateData { - in_wall: false, - facing: DarkOakFenceGateFacing::North, - open: false, - powered: false, - })), - Item::BrickStairs => Some(Block::BrickStairs(BrickStairsData { - shape: BrickStairsShape::Straight, - half: BrickStairsHalf::Bottom, - waterlogged: false, - facing: BrickStairsFacing::North, - })), - Item::StoneBrickStairs => Some(Block::StoneBrickStairs(StoneBrickStairsData { - waterlogged: false, - shape: StoneBrickStairsShape::Straight, - half: StoneBrickStairsHalf::Bottom, - facing: StoneBrickStairsFacing::North, - })), - Item::Mycelium => Some(Block::Mycelium(MyceliumData { snowy: false })), - Item::LilyPad => Some(Block::LilyPad), - Item::NetherBricks => Some(Block::NetherBricks), - Item::NetherBrickFence => Some(Block::NetherBrickFence(NetherBrickFenceData { - waterlogged: false, - west: false, - north: false, - east: false, - south: false, - })), - Item::NetherBrickStairs => Some(Block::NetherBrickStairs(NetherBrickStairsData { - shape: NetherBrickStairsShape::Straight, - facing: NetherBrickStairsFacing::North, - half: NetherBrickStairsHalf::Bottom, - waterlogged: false, - })), - Item::EnchantingTable => Some(Block::EnchantingTable), - Item::EndPortalFrame => Some(Block::EndPortalFrame(EndPortalFrameData { - eye: false, - facing: EndPortalFrameFacing::North, - })), - Item::EndStone => Some(Block::EndStone), - Item::EndStoneBricks => Some(Block::EndStoneBricks), - Item::DragonEgg => Some(Block::DragonEgg), - Item::RedstoneLamp => Some(Block::RedstoneLamp(RedstoneLampData { lit: false })), - Item::SandstoneStairs => Some(Block::SandstoneStairs(SandstoneStairsData { - waterlogged: false, - half: SandstoneStairsHalf::Bottom, - facing: SandstoneStairsFacing::North, - shape: SandstoneStairsShape::Straight, - })), - Item::EmeraldOre => Some(Block::EmeraldOre), - Item::EnderChest => Some(Block::EnderChest(EnderChestData { - facing: EnderChestFacing::North, - waterlogged: false, - })), - Item::TripwireHook => Some(Block::TripwireHook(TripwireHookData { - facing: TripwireHookFacing::North, - attached: false, - powered: false, - })), - Item::EmeraldBlock => Some(Block::EmeraldBlock), - Item::SpruceStairs => Some(Block::SpruceStairs(SpruceStairsData { - shape: SpruceStairsShape::Straight, - half: SpruceStairsHalf::Bottom, - facing: SpruceStairsFacing::North, - waterlogged: false, - })), - Item::BirchStairs => Some(Block::BirchStairs(BirchStairsData { - facing: BirchStairsFacing::North, - waterlogged: false, - half: BirchStairsHalf::Bottom, - shape: BirchStairsShape::Straight, - })), - Item::JungleStairs => Some(Block::JungleStairs(JungleStairsData { - facing: JungleStairsFacing::North, - shape: JungleStairsShape::Straight, - half: JungleStairsHalf::Bottom, - waterlogged: false, - })), - Item::CommandBlock => Some(Block::CommandBlock(CommandBlockData { - facing: CommandBlockFacing::North, - conditional: false, - })), - Item::Beacon => Some(Block::Beacon), - Item::CobblestoneWall => Some(Block::CobblestoneWall(CobblestoneWallData { - up: true, - waterlogged: false, - north: false, - west: false, - south: false, - east: false, - })), - Item::MossyCobblestoneWall => Some(Block::MossyCobblestoneWall(MossyCobblestoneWallData { - up: true, - south: false, - north: false, - east: false, - west: false, - waterlogged: false, - })), - Item::OakButton => Some(Block::OakButton(OakButtonData { - powered: false, - facing: OakButtonFacing::North, - face: OakButtonFace::Wall, - })), - Item::SpruceButton => Some(Block::SpruceButton(SpruceButtonData { - face: SpruceButtonFace::Wall, - powered: false, - facing: SpruceButtonFacing::North, - })), - Item::BirchButton => Some(Block::BirchButton(BirchButtonData { - facing: BirchButtonFacing::North, - face: BirchButtonFace::Wall, - powered: false, - })), - Item::JungleButton => Some(Block::JungleButton(JungleButtonData { - facing: JungleButtonFacing::North, - powered: false, - face: JungleButtonFace::Wall, - })), - Item::AcaciaButton => Some(Block::AcaciaButton(AcaciaButtonData { - face: AcaciaButtonFace::Wall, - powered: false, - facing: AcaciaButtonFacing::North, - })), - Item::DarkOakButton => Some(Block::DarkOakButton(DarkOakButtonData { - powered: false, - face: DarkOakButtonFace::Wall, - facing: DarkOakButtonFacing::North, - })), - Item::Anvil => Some(Block::Anvil(AnvilData { - facing: AnvilFacing::North, - })), - Item::ChippedAnvil => Some(Block::ChippedAnvil(ChippedAnvilData { - facing: ChippedAnvilFacing::North, - })), - Item::DamagedAnvil => Some(Block::DamagedAnvil(DamagedAnvilData { - facing: DamagedAnvilFacing::North, - })), - Item::TrappedChest => Some(Block::TrappedChest(TrappedChestData { - waterlogged: false, - facing: TrappedChestFacing::North, - ty: TrappedChestType::Single, - })), - Item::LightWeightedPressurePlate => Some(Block::LightWeightedPressurePlate( - LightWeightedPressurePlateData { power: 0i32 }, - )), - Item::HeavyWeightedPressurePlate => Some(Block::HeavyWeightedPressurePlate( - HeavyWeightedPressurePlateData { power: 0i32 }, - )), - Item::DaylightDetector => Some(Block::DaylightDetector(DaylightDetectorData { - inverted: false, - power: 0i32, - })), - Item::RedstoneBlock => Some(Block::RedstoneBlock), - Item::NetherQuartzOre => Some(Block::NetherQuartzOre), - Item::Hopper => Some(Block::Hopper(HopperData { - enabled: true, - facing: HopperFacing::Down, - })), - Item::ChiseledQuartzBlock => Some(Block::ChiseledQuartzBlock), - Item::QuartzBlock => Some(Block::QuartzBlock), - Item::QuartzPillar => Some(Block::QuartzPillar(QuartzPillarData { - axis: QuartzPillarAxis::Y, - })), - Item::QuartzStairs => Some(Block::QuartzStairs(QuartzStairsData { - shape: QuartzStairsShape::Straight, - waterlogged: false, - half: QuartzStairsHalf::Bottom, - facing: QuartzStairsFacing::North, - })), - Item::ActivatorRail => Some(Block::ActivatorRail(ActivatorRailData { - powered: false, - shape: ActivatorRailShape::NorthSouth, - })), - Item::Dropper => Some(Block::Dropper(DropperData { - facing: DropperFacing::North, - triggered: false, - })), - Item::WhiteTerracotta => Some(Block::WhiteTerracotta), - Item::OrangeTerracotta => Some(Block::OrangeTerracotta), - Item::MagentaTerracotta => Some(Block::MagentaTerracotta), - Item::LightBlueTerracotta => Some(Block::LightBlueTerracotta), - Item::YellowTerracotta => Some(Block::YellowTerracotta), - Item::LimeTerracotta => Some(Block::LimeTerracotta), - Item::PinkTerracotta => Some(Block::PinkTerracotta), - Item::GrayTerracotta => Some(Block::GrayTerracotta), - Item::LightGrayTerracotta => Some(Block::LightGrayTerracotta), - Item::CyanTerracotta => Some(Block::CyanTerracotta), - Item::PurpleTerracotta => Some(Block::PurpleTerracotta), - Item::BlueTerracotta => Some(Block::BlueTerracotta), - Item::BrownTerracotta => Some(Block::BrownTerracotta), - Item::GreenTerracotta => Some(Block::GreenTerracotta), - Item::RedTerracotta => Some(Block::RedTerracotta), - Item::BlackTerracotta => Some(Block::BlackTerracotta), - Item::Barrier => Some(Block::Barrier), - Item::IronTrapdoor => Some(Block::IronTrapdoor(IronTrapdoorData { - open: false, - facing: IronTrapdoorFacing::North, - powered: false, - half: IronTrapdoorHalf::Bottom, - waterlogged: false, - })), - Item::HayBlock => Some(Block::HayBlock(HayBlockData { - axis: HayBlockAxis::Y, - })), - Item::WhiteCarpet => Some(Block::WhiteCarpet), - Item::OrangeCarpet => Some(Block::OrangeCarpet), - Item::MagentaCarpet => Some(Block::MagentaCarpet), - Item::LightBlueCarpet => Some(Block::LightBlueCarpet), - Item::YellowCarpet => Some(Block::YellowCarpet), - Item::LimeCarpet => Some(Block::LimeCarpet), - Item::PinkCarpet => Some(Block::PinkCarpet), - Item::GrayCarpet => Some(Block::GrayCarpet), - Item::LightGrayCarpet => Some(Block::LightGrayCarpet), - Item::CyanCarpet => Some(Block::CyanCarpet), - Item::PurpleCarpet => Some(Block::PurpleCarpet), - Item::BlueCarpet => Some(Block::BlueCarpet), - Item::BrownCarpet => Some(Block::BrownCarpet), - Item::GreenCarpet => Some(Block::GreenCarpet), - Item::RedCarpet => Some(Block::RedCarpet), - Item::BlackCarpet => Some(Block::BlackCarpet), - Item::Terracotta => Some(Block::Terracotta), - Item::CoalBlock => Some(Block::CoalBlock), - Item::PackedIce => Some(Block::PackedIce), - Item::AcaciaStairs => Some(Block::AcaciaStairs(AcaciaStairsData { - half: AcaciaStairsHalf::Bottom, - shape: AcaciaStairsShape::Straight, - waterlogged: false, - facing: AcaciaStairsFacing::North, - })), - Item::DarkOakStairs => Some(Block::DarkOakStairs(DarkOakStairsData { - shape: DarkOakStairsShape::Straight, - half: DarkOakStairsHalf::Bottom, - waterlogged: false, - facing: DarkOakStairsFacing::North, - })), - Item::SlimeBlock => Some(Block::SlimeBlock), - Item::GrassPath => Some(Block::GrassPath), - Item::Sunflower => Some(Block::Sunflower(SunflowerData { - half: SunflowerHalf::Lower, - })), - Item::Lilac => Some(Block::Lilac(LilacData { - half: LilacHalf::Lower, - })), - Item::RoseBush => Some(Block::RoseBush(RoseBushData { - half: RoseBushHalf::Lower, - })), - Item::Peony => Some(Block::Peony(PeonyData { - half: PeonyHalf::Lower, - })), - Item::TallGrass => Some(Block::TallGrass(TallGrassData { - half: TallGrassHalf::Lower, - })), - Item::LargeFern => Some(Block::LargeFern(LargeFernData { - half: LargeFernHalf::Lower, - })), - Item::WhiteStainedGlass => Some(Block::WhiteStainedGlass), - Item::OrangeStainedGlass => Some(Block::OrangeStainedGlass), - Item::MagentaStainedGlass => Some(Block::MagentaStainedGlass), - Item::LightBlueStainedGlass => Some(Block::LightBlueStainedGlass), - Item::YellowStainedGlass => Some(Block::YellowStainedGlass), - Item::LimeStainedGlass => Some(Block::LimeStainedGlass), - Item::PinkStainedGlass => Some(Block::PinkStainedGlass), - Item::GrayStainedGlass => Some(Block::GrayStainedGlass), - Item::LightGrayStainedGlass => Some(Block::LightGrayStainedGlass), - Item::CyanStainedGlass => Some(Block::CyanStainedGlass), - Item::PurpleStainedGlass => Some(Block::PurpleStainedGlass), - Item::BlueStainedGlass => Some(Block::BlueStainedGlass), - Item::BrownStainedGlass => Some(Block::BrownStainedGlass), - Item::GreenStainedGlass => Some(Block::GreenStainedGlass), - Item::RedStainedGlass => Some(Block::RedStainedGlass), - Item::BlackStainedGlass => Some(Block::BlackStainedGlass), - Item::WhiteStainedGlassPane => { - Some(Block::WhiteStainedGlassPane(WhiteStainedGlassPaneData { - west: false, - east: false, - waterlogged: false, - north: false, - south: false, - })) - } - Item::OrangeStainedGlassPane => { - Some(Block::OrangeStainedGlassPane(OrangeStainedGlassPaneData { - south: false, - waterlogged: false, - east: false, - west: false, - north: false, - })) - } - Item::MagentaStainedGlassPane => Some(Block::MagentaStainedGlassPane( - MagentaStainedGlassPaneData { - south: false, - waterlogged: false, - east: false, - north: false, - west: false, - }, - )), - Item::LightBlueStainedGlassPane => Some(Block::LightBlueStainedGlassPane( - LightBlueStainedGlassPaneData { - north: false, - east: false, - west: false, - waterlogged: false, - south: false, - }, - )), - Item::YellowStainedGlassPane => { - Some(Block::YellowStainedGlassPane(YellowStainedGlassPaneData { - west: false, - south: false, - north: false, - waterlogged: false, - east: false, - })) - } - Item::LimeStainedGlassPane => Some(Block::LimeStainedGlassPane(LimeStainedGlassPaneData { - south: false, - north: false, - west: false, - east: false, - waterlogged: false, - })), - Item::PinkStainedGlassPane => Some(Block::PinkStainedGlassPane(PinkStainedGlassPaneData { - waterlogged: false, - north: false, - east: false, - south: false, - west: false, - })), - Item::GrayStainedGlassPane => Some(Block::GrayStainedGlassPane(GrayStainedGlassPaneData { - waterlogged: false, - east: false, - north: false, - west: false, - south: false, - })), - Item::LightGrayStainedGlassPane => Some(Block::LightGrayStainedGlassPane( - LightGrayStainedGlassPaneData { - east: false, - waterlogged: false, - west: false, - north: false, - south: false, - }, - )), - Item::CyanStainedGlassPane => Some(Block::CyanStainedGlassPane(CyanStainedGlassPaneData { - west: false, - waterlogged: false, - east: false, - north: false, - south: false, - })), - Item::PurpleStainedGlassPane => { - Some(Block::PurpleStainedGlassPane(PurpleStainedGlassPaneData { - west: false, - waterlogged: false, - east: false, - north: false, - south: false, - })) - } - Item::BlueStainedGlassPane => Some(Block::BlueStainedGlassPane(BlueStainedGlassPaneData { - east: false, - north: false, - south: false, - waterlogged: false, - west: false, - })), - Item::BrownStainedGlassPane => { - Some(Block::BrownStainedGlassPane(BrownStainedGlassPaneData { - east: false, - west: false, - north: false, - waterlogged: false, - south: false, - })) - } - Item::GreenStainedGlassPane => { - Some(Block::GreenStainedGlassPane(GreenStainedGlassPaneData { - north: false, - west: false, - waterlogged: false, - south: false, - east: false, - })) - } - Item::RedStainedGlassPane => Some(Block::RedStainedGlassPane(RedStainedGlassPaneData { - waterlogged: false, - south: false, - west: false, - east: false, - north: false, - })), - Item::BlackStainedGlassPane => { - Some(Block::BlackStainedGlassPane(BlackStainedGlassPaneData { - east: false, - south: false, - west: false, - waterlogged: false, - north: false, - })) - } - Item::Prismarine => Some(Block::Prismarine), - Item::PrismarineBricks => Some(Block::PrismarineBricks), - Item::DarkPrismarine => Some(Block::DarkPrismarine), - Item::PrismarineStairs => Some(Block::PrismarineStairs(PrismarineStairsData { - half: PrismarineStairsHalf::Bottom, - shape: PrismarineStairsShape::Straight, - facing: PrismarineStairsFacing::North, - waterlogged: false, - })), - Item::PrismarineBrickStairs => { - Some(Block::PrismarineBrickStairs(PrismarineBrickStairsData { - half: PrismarineBrickStairsHalf::Bottom, - waterlogged: false, - shape: PrismarineBrickStairsShape::Straight, - facing: PrismarineBrickStairsFacing::North, - })) - } - Item::DarkPrismarineStairs => Some(Block::DarkPrismarineStairs(DarkPrismarineStairsData { - facing: DarkPrismarineStairsFacing::North, - half: DarkPrismarineStairsHalf::Bottom, - waterlogged: false, - shape: DarkPrismarineStairsShape::Straight, - })), - Item::SeaLantern => Some(Block::SeaLantern), - Item::RedSandstone => Some(Block::RedSandstone), - Item::ChiseledRedSandstone => Some(Block::ChiseledRedSandstone), - Item::CutRedSandstone => Some(Block::CutRedSandstone), - Item::RedSandstoneStairs => Some(Block::RedSandstoneStairs(RedSandstoneStairsData { - waterlogged: false, - facing: RedSandstoneStairsFacing::North, - half: RedSandstoneStairsHalf::Bottom, - shape: RedSandstoneStairsShape::Straight, - })), - Item::RepeatingCommandBlock => { - Some(Block::RepeatingCommandBlock(RepeatingCommandBlockData { - conditional: false, - facing: RepeatingCommandBlockFacing::North, - })) - } - Item::ChainCommandBlock => Some(Block::ChainCommandBlock(ChainCommandBlockData { - conditional: false, - facing: ChainCommandBlockFacing::North, - })), - Item::MagmaBlock => Some(Block::MagmaBlock), - Item::NetherWartBlock => Some(Block::NetherWartBlock), - Item::RedNetherBricks => Some(Block::RedNetherBricks), - Item::BoneBlock => Some(Block::BoneBlock(BoneBlockData { - axis: BoneBlockAxis::Y, - })), - Item::StructureVoid => Some(Block::StructureVoid), - Item::Observer => Some(Block::Observer(ObserverData { - facing: ObserverFacing::South, - powered: false, - })), - Item::ShulkerBox => Some(Block::ShulkerBox(ShulkerBoxData { - facing: ShulkerBoxFacing::Up, - })), - Item::WhiteShulkerBox => Some(Block::WhiteShulkerBox(WhiteShulkerBoxData { - facing: WhiteShulkerBoxFacing::Up, - })), - Item::OrangeShulkerBox => Some(Block::OrangeShulkerBox(OrangeShulkerBoxData { - facing: OrangeShulkerBoxFacing::Up, - })), - Item::MagentaShulkerBox => Some(Block::MagentaShulkerBox(MagentaShulkerBoxData { - facing: MagentaShulkerBoxFacing::Up, - })), - Item::LightBlueShulkerBox => Some(Block::LightBlueShulkerBox(LightBlueShulkerBoxData { - facing: LightBlueShulkerBoxFacing::Up, - })), - Item::YellowShulkerBox => Some(Block::YellowShulkerBox(YellowShulkerBoxData { - facing: YellowShulkerBoxFacing::Up, - })), - Item::LimeShulkerBox => Some(Block::LimeShulkerBox(LimeShulkerBoxData { - facing: LimeShulkerBoxFacing::Up, - })), - Item::PinkShulkerBox => Some(Block::PinkShulkerBox(PinkShulkerBoxData { - facing: PinkShulkerBoxFacing::Up, - })), - Item::GrayShulkerBox => Some(Block::GrayShulkerBox(GrayShulkerBoxData { - facing: GrayShulkerBoxFacing::Up, - })), - Item::LightGrayShulkerBox => Some(Block::LightGrayShulkerBox(LightGrayShulkerBoxData { - facing: LightGrayShulkerBoxFacing::Up, - })), - Item::CyanShulkerBox => Some(Block::CyanShulkerBox(CyanShulkerBoxData { - facing: CyanShulkerBoxFacing::Up, - })), - Item::PurpleShulkerBox => Some(Block::PurpleShulkerBox(PurpleShulkerBoxData { - facing: PurpleShulkerBoxFacing::Up, - })), - Item::BlueShulkerBox => Some(Block::BlueShulkerBox(BlueShulkerBoxData { - facing: BlueShulkerBoxFacing::Up, - })), - Item::BrownShulkerBox => Some(Block::BrownShulkerBox(BrownShulkerBoxData { - facing: BrownShulkerBoxFacing::Up, - })), - Item::GreenShulkerBox => Some(Block::GreenShulkerBox(GreenShulkerBoxData { - facing: GreenShulkerBoxFacing::Up, - })), - Item::RedShulkerBox => Some(Block::RedShulkerBox(RedShulkerBoxData { - facing: RedShulkerBoxFacing::Up, - })), - Item::BlackShulkerBox => Some(Block::BlackShulkerBox(BlackShulkerBoxData { - facing: BlackShulkerBoxFacing::Up, - })), - Item::WhiteGlazedTerracotta => { - Some(Block::WhiteGlazedTerracotta(WhiteGlazedTerracottaData { - facing: WhiteGlazedTerracottaFacing::North, - })) - } - Item::OrangeGlazedTerracotta => { - Some(Block::OrangeGlazedTerracotta(OrangeGlazedTerracottaData { - facing: OrangeGlazedTerracottaFacing::North, - })) - } - Item::MagentaGlazedTerracotta => Some(Block::MagentaGlazedTerracotta( - MagentaGlazedTerracottaData { - facing: MagentaGlazedTerracottaFacing::North, - }, - )), - Item::LightBlueGlazedTerracotta => Some(Block::LightBlueGlazedTerracotta( - LightBlueGlazedTerracottaData { - facing: LightBlueGlazedTerracottaFacing::North, - }, - )), - Item::YellowGlazedTerracotta => { - Some(Block::YellowGlazedTerracotta(YellowGlazedTerracottaData { - facing: YellowGlazedTerracottaFacing::North, - })) - } - Item::LimeGlazedTerracotta => Some(Block::LimeGlazedTerracotta(LimeGlazedTerracottaData { - facing: LimeGlazedTerracottaFacing::North, - })), - Item::PinkGlazedTerracotta => Some(Block::PinkGlazedTerracotta(PinkGlazedTerracottaData { - facing: PinkGlazedTerracottaFacing::North, - })), - Item::GrayGlazedTerracotta => Some(Block::GrayGlazedTerracotta(GrayGlazedTerracottaData { - facing: GrayGlazedTerracottaFacing::North, - })), - Item::LightGrayGlazedTerracotta => Some(Block::LightGrayGlazedTerracotta( - LightGrayGlazedTerracottaData { - facing: LightGrayGlazedTerracottaFacing::North, - }, - )), - Item::CyanGlazedTerracotta => Some(Block::CyanGlazedTerracotta(CyanGlazedTerracottaData { - facing: CyanGlazedTerracottaFacing::North, - })), - Item::PurpleGlazedTerracotta => { - Some(Block::PurpleGlazedTerracotta(PurpleGlazedTerracottaData { - facing: PurpleGlazedTerracottaFacing::North, - })) - } - Item::BlueGlazedTerracotta => Some(Block::BlueGlazedTerracotta(BlueGlazedTerracottaData { - facing: BlueGlazedTerracottaFacing::North, - })), - Item::BrownGlazedTerracotta => { - Some(Block::BrownGlazedTerracotta(BrownGlazedTerracottaData { - facing: BrownGlazedTerracottaFacing::North, - })) - } - Item::GreenGlazedTerracotta => { - Some(Block::GreenGlazedTerracotta(GreenGlazedTerracottaData { - facing: GreenGlazedTerracottaFacing::North, - })) - } - Item::RedGlazedTerracotta => Some(Block::RedGlazedTerracotta(RedGlazedTerracottaData { - facing: RedGlazedTerracottaFacing::North, - })), - Item::BlackGlazedTerracotta => { - Some(Block::BlackGlazedTerracotta(BlackGlazedTerracottaData { - facing: BlackGlazedTerracottaFacing::North, - })) - } - Item::WhiteConcrete => Some(Block::WhiteConcrete), - Item::OrangeConcrete => Some(Block::OrangeConcrete), - Item::MagentaConcrete => Some(Block::MagentaConcrete), - Item::LightBlueConcrete => Some(Block::LightBlueConcrete), - Item::YellowConcrete => Some(Block::YellowConcrete), - Item::LimeConcrete => Some(Block::LimeConcrete), - Item::PinkConcrete => Some(Block::PinkConcrete), - Item::GrayConcrete => Some(Block::GrayConcrete), - Item::LightGrayConcrete => Some(Block::LightGrayConcrete), - Item::CyanConcrete => Some(Block::CyanConcrete), - Item::PurpleConcrete => Some(Block::PurpleConcrete), - Item::BlueConcrete => Some(Block::BlueConcrete), - Item::BrownConcrete => Some(Block::BrownConcrete), - Item::GreenConcrete => Some(Block::GreenConcrete), - Item::RedConcrete => Some(Block::RedConcrete), - Item::BlackConcrete => Some(Block::BlackConcrete), - Item::WhiteConcretePowder => Some(Block::WhiteConcretePowder), - Item::OrangeConcretePowder => Some(Block::OrangeConcretePowder), - Item::MagentaConcretePowder => Some(Block::MagentaConcretePowder), - Item::LightBlueConcretePowder => Some(Block::LightBlueConcretePowder), - Item::YellowConcretePowder => Some(Block::YellowConcretePowder), - Item::LimeConcretePowder => Some(Block::LimeConcretePowder), - Item::PinkConcretePowder => Some(Block::PinkConcretePowder), - Item::GrayConcretePowder => Some(Block::GrayConcretePowder), - Item::LightGrayConcretePowder => Some(Block::LightGrayConcretePowder), - Item::CyanConcretePowder => Some(Block::CyanConcretePowder), - Item::PurpleConcretePowder => Some(Block::PurpleConcretePowder), - Item::BlueConcretePowder => Some(Block::BlueConcretePowder), - Item::BrownConcretePowder => Some(Block::BrownConcretePowder), - Item::GreenConcretePowder => Some(Block::GreenConcretePowder), - Item::RedConcretePowder => Some(Block::RedConcretePowder), - Item::BlackConcretePowder => Some(Block::BlackConcretePowder), - Item::TurtleEgg => Some(Block::TurtleEgg(TurtleEggData { - eggs: 1i32, - hatch: 0i32, - })), - Item::DeadTubeCoralBlock => Some(Block::DeadTubeCoralBlock), - Item::DeadBrainCoralBlock => Some(Block::DeadBrainCoralBlock), - Item::DeadBubbleCoralBlock => Some(Block::DeadBubbleCoralBlock), - Item::DeadFireCoralBlock => Some(Block::DeadFireCoralBlock), - Item::DeadHornCoralBlock => Some(Block::DeadHornCoralBlock), - Item::TubeCoralBlock => Some(Block::TubeCoralBlock), - Item::BrainCoralBlock => Some(Block::BrainCoralBlock), - Item::BubbleCoralBlock => Some(Block::BubbleCoralBlock), - Item::FireCoralBlock => Some(Block::FireCoralBlock), - Item::HornCoralBlock => Some(Block::HornCoralBlock), - Item::TubeCoral => Some(Block::TubeCoral(TubeCoralData { waterlogged: true })), - Item::BrainCoral => Some(Block::BrainCoral(BrainCoralData { waterlogged: true })), - Item::BubbleCoral => Some(Block::BubbleCoral(BubbleCoralData { waterlogged: true })), - Item::FireCoral => Some(Block::FireCoral(FireCoralData { waterlogged: true })), - Item::HornCoral => Some(Block::HornCoral(HornCoralData { waterlogged: true })), - Item::DeadBrainCoral => Some(Block::DeadBrainCoral(DeadBrainCoralData { - waterlogged: true, - })), - Item::DeadBubbleCoral => Some(Block::DeadBubbleCoral(DeadBubbleCoralData { - waterlogged: true, - })), - Item::DeadFireCoral => Some(Block::DeadFireCoral(DeadFireCoralData { - waterlogged: true, - })), - Item::DeadHornCoral => Some(Block::DeadHornCoral(DeadHornCoralData { - waterlogged: true, - })), - Item::DeadTubeCoral => Some(Block::DeadTubeCoral(DeadTubeCoralData { - waterlogged: true, - })), - Item::TubeCoralFan => Some(Block::TubeCoralFan(TubeCoralFanData { waterlogged: true })), - Item::BrainCoralFan => Some(Block::BrainCoralFan(BrainCoralFanData { - waterlogged: true, - })), - Item::BubbleCoralFan => Some(Block::BubbleCoralFan(BubbleCoralFanData { - waterlogged: true, - })), - Item::FireCoralFan => Some(Block::FireCoralFan(FireCoralFanData { waterlogged: true })), - Item::HornCoralFan => Some(Block::HornCoralFan(HornCoralFanData { waterlogged: true })), - Item::DeadTubeCoralFan => Some(Block::DeadTubeCoralFan(DeadTubeCoralFanData { - waterlogged: true, - })), - Item::DeadBrainCoralFan => Some(Block::DeadBrainCoralFan(DeadBrainCoralFanData { - waterlogged: true, - })), - Item::DeadBubbleCoralFan => Some(Block::DeadBubbleCoralFan(DeadBubbleCoralFanData { - waterlogged: true, - })), - Item::DeadFireCoralFan => Some(Block::DeadFireCoralFan(DeadFireCoralFanData { - waterlogged: true, - })), - Item::DeadHornCoralFan => Some(Block::DeadHornCoralFan(DeadHornCoralFanData { - waterlogged: true, - })), - Item::BlueIce => Some(Block::BlueIce), - Item::Conduit => Some(Block::Conduit(ConduitData { waterlogged: true })), - Item::IronDoor => Some(Block::IronDoor(IronDoorData { - powered: false, - half: IronDoorHalf::Lower, - open: false, - facing: IronDoorFacing::North, - hinge: IronDoorHinge::Left, - })), - Item::OakDoor => Some(Block::OakDoor(OakDoorData { - facing: OakDoorFacing::North, - powered: false, - half: OakDoorHalf::Lower, - open: false, - hinge: OakDoorHinge::Left, - })), - Item::SpruceDoor => Some(Block::SpruceDoor(SpruceDoorData { - powered: false, - half: SpruceDoorHalf::Lower, - facing: SpruceDoorFacing::North, - hinge: SpruceDoorHinge::Left, - open: false, - })), - Item::BirchDoor => Some(Block::BirchDoor(BirchDoorData { - half: BirchDoorHalf::Lower, - hinge: BirchDoorHinge::Left, - open: false, - facing: BirchDoorFacing::North, - powered: false, - })), - Item::JungleDoor => Some(Block::JungleDoor(JungleDoorData { - open: false, - powered: false, - hinge: JungleDoorHinge::Left, - facing: JungleDoorFacing::North, - half: JungleDoorHalf::Lower, - })), - Item::AcaciaDoor => Some(Block::AcaciaDoor(AcaciaDoorData { - facing: AcaciaDoorFacing::North, - hinge: AcaciaDoorHinge::Left, - open: false, - powered: false, - half: AcaciaDoorHalf::Lower, - })), - Item::DarkOakDoor => Some(Block::DarkOakDoor(DarkOakDoorData { - facing: DarkOakDoorFacing::North, - hinge: DarkOakDoorHinge::Left, - powered: false, - half: DarkOakDoorHalf::Lower, - open: false, - })), - Item::Repeater => Some(Block::Repeater(RepeaterData { - delay: 1i32, - facing: RepeaterFacing::North, - locked: false, - powered: false, - })), - Item::Comparator => Some(Block::Comparator(ComparatorData { - mode: ComparatorMode::Compare, - facing: ComparatorFacing::North, - powered: false, - })), - Item::StructureBlock => Some(Block::StructureBlock(StructureBlockData { - mode: StructureBlockMode::Save, - })), - Item::Wheat => Some(Block::Wheat(WheatData { age: 0i32 })), - Item::Sign => Some(Block::Sign(SignData { - waterlogged: false, - rotation: 0i32, - })), - Item::SugarCane => Some(Block::SugarCane(SugarCaneData { age: 0i32 })), - Item::Kelp => Some(Block::Kelp(KelpData { age: 0i32 })), - Item::DriedKelpBlock => Some(Block::DriedKelpBlock), - Item::Cake => Some(Block::Cake(CakeData { bites: 0i32 })), - Item::WhiteBed => Some(Block::WhiteBed(WhiteBedData { - occupied: false, - facing: WhiteBedFacing::North, - part: WhiteBedPart::Foot, - })), - Item::OrangeBed => Some(Block::OrangeBed(OrangeBedData { - occupied: false, - facing: OrangeBedFacing::North, - part: OrangeBedPart::Foot, - })), - Item::MagentaBed => Some(Block::MagentaBed(MagentaBedData { - facing: MagentaBedFacing::North, - occupied: false, - part: MagentaBedPart::Foot, - })), - Item::LightBlueBed => Some(Block::LightBlueBed(LightBlueBedData { - part: LightBlueBedPart::Foot, - occupied: false, - facing: LightBlueBedFacing::North, - })), - Item::YellowBed => Some(Block::YellowBed(YellowBedData { - occupied: false, - part: YellowBedPart::Foot, - facing: YellowBedFacing::North, - })), - Item::LimeBed => Some(Block::LimeBed(LimeBedData { - facing: LimeBedFacing::North, - occupied: false, - part: LimeBedPart::Foot, - })), - Item::PinkBed => Some(Block::PinkBed(PinkBedData { - facing: PinkBedFacing::North, - occupied: false, - part: PinkBedPart::Foot, - })), - Item::GrayBed => Some(Block::GrayBed(GrayBedData { - part: GrayBedPart::Foot, - occupied: false, - facing: GrayBedFacing::North, - })), - Item::LightGrayBed => Some(Block::LightGrayBed(LightGrayBedData { - occupied: false, - part: LightGrayBedPart::Foot, - facing: LightGrayBedFacing::North, - })), - Item::CyanBed => Some(Block::CyanBed(CyanBedData { - part: CyanBedPart::Foot, - facing: CyanBedFacing::North, - occupied: false, - })), - Item::PurpleBed => Some(Block::PurpleBed(PurpleBedData { - occupied: false, - part: PurpleBedPart::Foot, - facing: PurpleBedFacing::North, - })), - Item::BlueBed => Some(Block::BlueBed(BlueBedData { - facing: BlueBedFacing::North, - occupied: false, - part: BlueBedPart::Foot, - })), - Item::BrownBed => Some(Block::BrownBed(BrownBedData { - occupied: false, - part: BrownBedPart::Foot, - facing: BrownBedFacing::North, - })), - Item::GreenBed => Some(Block::GreenBed(GreenBedData { - occupied: false, - facing: GreenBedFacing::North, - part: GreenBedPart::Foot, - })), - Item::RedBed => Some(Block::RedBed(RedBedData { - occupied: false, - facing: RedBedFacing::North, - part: RedBedPart::Foot, - })), - Item::BlackBed => Some(Block::BlackBed(BlackBedData { - facing: BlackBedFacing::North, - part: BlackBedPart::Foot, - occupied: false, - })), - Item::NetherWart => Some(Block::NetherWart(NetherWartData { age: 0i32 })), - Item::BrewingStand => Some(Block::BrewingStand(BrewingStandData { - has_bottle_2: false, - has_bottle_0: false, - has_bottle_1: false, - })), - Item::Cauldron => Some(Block::Cauldron(CauldronData { level: 0i32 })), - Item::FlowerPot => Some(Block::FlowerPot), - Item::SkeletonSkull => Some(Block::SkeletonSkull(SkeletonSkullData { rotation: 0i32 })), - Item::WitherSkeletonSkull => Some(Block::WitherSkeletonSkull(WitherSkeletonSkullData { - rotation: 0i32, - })), - Item::PlayerHead => Some(Block::PlayerHead(PlayerHeadData { rotation: 0i32 })), - Item::ZombieHead => Some(Block::ZombieHead(ZombieHeadData { rotation: 0i32 })), - Item::CreeperHead => Some(Block::CreeperHead(CreeperHeadData { rotation: 0i32 })), - Item::DragonHead => Some(Block::DragonHead(DragonHeadData { rotation: 0i32 })), - Item::WhiteBanner => Some(Block::WhiteBanner(WhiteBannerData { rotation: 0i32 })), - Item::OrangeBanner => Some(Block::OrangeBanner(OrangeBannerData { rotation: 0i32 })), - Item::MagentaBanner => Some(Block::MagentaBanner(MagentaBannerData { rotation: 0i32 })), - Item::LightBlueBanner => Some(Block::LightBlueBanner(LightBlueBannerData { - rotation: 0i32, - })), - Item::YellowBanner => Some(Block::YellowBanner(YellowBannerData { rotation: 0i32 })), - Item::LimeBanner => Some(Block::LimeBanner(LimeBannerData { rotation: 0i32 })), - Item::PinkBanner => Some(Block::PinkBanner(PinkBannerData { rotation: 0i32 })), - Item::GrayBanner => Some(Block::GrayBanner(GrayBannerData { rotation: 0i32 })), - Item::LightGrayBanner => Some(Block::LightGrayBanner(LightGrayBannerData { - rotation: 0i32, - })), - Item::CyanBanner => Some(Block::CyanBanner(CyanBannerData { rotation: 0i32 })), - Item::PurpleBanner => Some(Block::PurpleBanner(PurpleBannerData { rotation: 0i32 })), - Item::BlueBanner => Some(Block::BlueBanner(BlueBannerData { rotation: 0i32 })), - Item::BrownBanner => Some(Block::BrownBanner(BrownBannerData { rotation: 0i32 })), - Item::GreenBanner => Some(Block::GreenBanner(GreenBannerData { rotation: 0i32 })), - Item::RedBanner => Some(Block::RedBanner(RedBannerData { rotation: 0i32 })), - Item::BlackBanner => Some(Block::BlackBanner(BlackBannerData { rotation: 0i32 })), - _ => None, - } -} -pub fn block_to_item(block: Block) -> Option<Item> { - match block { - Block::Air => Some(Item::Air), - Block::Stone => Some(Item::Stone), - Block::Granite => Some(Item::Granite), - Block::PolishedGranite => Some(Item::PolishedGranite), - Block::Diorite => Some(Item::Diorite), - Block::PolishedDiorite => Some(Item::PolishedDiorite), - Block::Andesite => Some(Item::Andesite), - Block::PolishedAndesite => Some(Item::PolishedAndesite), - Block::GrassBlock(_) => Some(Item::GrassBlock), - Block::Dirt => Some(Item::Dirt), - Block::CoarseDirt => Some(Item::CoarseDirt), - Block::Podzol(_) => Some(Item::Podzol), - Block::Cobblestone => Some(Item::Cobblestone), - Block::OakPlanks => Some(Item::OakPlanks), - Block::SprucePlanks => Some(Item::SprucePlanks), - Block::BirchPlanks => Some(Item::BirchPlanks), - Block::JunglePlanks => Some(Item::JunglePlanks), - Block::AcaciaPlanks => Some(Item::AcaciaPlanks), - Block::DarkOakPlanks => Some(Item::DarkOakPlanks), - Block::OakSapling(_) => Some(Item::OakSapling), - Block::SpruceSapling(_) => Some(Item::SpruceSapling), - Block::BirchSapling(_) => Some(Item::BirchSapling), - Block::JungleSapling(_) => Some(Item::JungleSapling), - Block::AcaciaSapling(_) => Some(Item::AcaciaSapling), - Block::DarkOakSapling(_) => Some(Item::DarkOakSapling), - Block::Bedrock => Some(Item::Bedrock), - Block::Sand => Some(Item::Sand), - Block::RedSand => Some(Item::RedSand), - Block::Gravel => Some(Item::Gravel), - Block::GoldOre => Some(Item::GoldOre), - Block::IronOre => Some(Item::IronOre), - Block::CoalOre => Some(Item::CoalOre), - Block::OakLog(_) => Some(Item::OakLog), - Block::SpruceLog(_) => Some(Item::SpruceLog), - Block::BirchLog(_) => Some(Item::BirchLog), - Block::JungleLog(_) => Some(Item::JungleLog), - Block::AcaciaLog(_) => Some(Item::AcaciaLog), - Block::DarkOakLog(_) => Some(Item::DarkOakLog), - Block::StrippedOakLog(_) => Some(Item::StrippedOakLog), - Block::StrippedSpruceLog(_) => Some(Item::StrippedSpruceLog), - Block::StrippedBirchLog(_) => Some(Item::StrippedBirchLog), - Block::StrippedJungleLog(_) => Some(Item::StrippedJungleLog), - Block::StrippedAcaciaLog(_) => Some(Item::StrippedAcaciaLog), - Block::StrippedDarkOakLog(_) => Some(Item::StrippedDarkOakLog), - Block::StrippedOakWood(_) => Some(Item::StrippedOakWood), - Block::StrippedSpruceWood(_) => Some(Item::StrippedSpruceWood), - Block::StrippedBirchWood(_) => Some(Item::StrippedBirchWood), - Block::StrippedJungleWood(_) => Some(Item::StrippedJungleWood), - Block::StrippedAcaciaWood(_) => Some(Item::StrippedAcaciaWood), - Block::StrippedDarkOakWood(_) => Some(Item::StrippedDarkOakWood), - Block::OakWood(_) => Some(Item::OakWood), - Block::SpruceWood(_) => Some(Item::SpruceWood), - Block::BirchWood(_) => Some(Item::BirchWood), - Block::JungleWood(_) => Some(Item::JungleWood), - Block::AcaciaWood(_) => Some(Item::AcaciaWood), - Block::DarkOakWood(_) => Some(Item::DarkOakWood), - Block::OakLeaves(_) => Some(Item::OakLeaves), - Block::SpruceLeaves(_) => Some(Item::SpruceLeaves), - Block::BirchLeaves(_) => Some(Item::BirchLeaves), - Block::JungleLeaves(_) => Some(Item::JungleLeaves), - Block::AcaciaLeaves(_) => Some(Item::AcaciaLeaves), - Block::DarkOakLeaves(_) => Some(Item::DarkOakLeaves), - Block::Sponge => Some(Item::Sponge), - Block::WetSponge => Some(Item::WetSponge), - Block::Glass => Some(Item::Glass), - Block::LapisOre => Some(Item::LapisOre), - Block::LapisBlock => Some(Item::LapisBlock), - Block::Dispenser(_) => Some(Item::Dispenser), - Block::Sandstone => Some(Item::Sandstone), - Block::ChiseledSandstone => Some(Item::ChiseledSandstone), - Block::CutSandstone => Some(Item::CutSandstone), - Block::NoteBlock(_) => Some(Item::NoteBlock), - Block::PoweredRail(_) => Some(Item::PoweredRail), - Block::DetectorRail(_) => Some(Item::DetectorRail), - Block::StickyPiston(_) => Some(Item::StickyPiston), - Block::Cobweb => Some(Item::Cobweb), - Block::Grass => Some(Item::Grass), - Block::Fern => Some(Item::Fern), - Block::DeadBush => Some(Item::DeadBush), - Block::Seagrass => Some(Item::Seagrass), - Block::SeaPickle(_) => Some(Item::SeaPickle), - Block::Piston(_) => Some(Item::Piston), - Block::WhiteWool => Some(Item::WhiteWool), - Block::OrangeWool => Some(Item::OrangeWool), - Block::MagentaWool => Some(Item::MagentaWool), - Block::LightBlueWool => Some(Item::LightBlueWool), - Block::YellowWool => Some(Item::YellowWool), - Block::LimeWool => Some(Item::LimeWool), - Block::PinkWool => Some(Item::PinkWool), - Block::GrayWool => Some(Item::GrayWool), - Block::LightGrayWool => Some(Item::LightGrayWool), - Block::CyanWool => Some(Item::CyanWool), - Block::PurpleWool => Some(Item::PurpleWool), - Block::BlueWool => Some(Item::BlueWool), - Block::BrownWool => Some(Item::BrownWool), - Block::GreenWool => Some(Item::GreenWool), - Block::RedWool => Some(Item::RedWool), - Block::BlackWool => Some(Item::BlackWool), - Block::Dandelion => Some(Item::Dandelion), - Block::Poppy => Some(Item::Poppy), - Block::BlueOrchid => Some(Item::BlueOrchid), - Block::Allium => Some(Item::Allium), - Block::AzureBluet => Some(Item::AzureBluet), - Block::RedTulip => Some(Item::RedTulip), - Block::OrangeTulip => Some(Item::OrangeTulip), - Block::WhiteTulip => Some(Item::WhiteTulip), - Block::PinkTulip => Some(Item::PinkTulip), - Block::OxeyeDaisy => Some(Item::OxeyeDaisy), - Block::BrownMushroom => Some(Item::BrownMushroom), - Block::RedMushroom => Some(Item::RedMushroom), - Block::GoldBlock => Some(Item::GoldBlock), - Block::IronBlock => Some(Item::IronBlock), - Block::OakSlab(_) => Some(Item::OakSlab), - Block::SpruceSlab(_) => Some(Item::SpruceSlab), - Block::BirchSlab(_) => Some(Item::BirchSlab), - Block::JungleSlab(_) => Some(Item::JungleSlab), - Block::AcaciaSlab(_) => Some(Item::AcaciaSlab), - Block::DarkOakSlab(_) => Some(Item::DarkOakSlab), - Block::StoneSlab(_) => Some(Item::StoneSlab), - Block::SandstoneSlab(_) => Some(Item::SandstoneSlab), - Block::PetrifiedOakSlab(_) => Some(Item::PetrifiedOakSlab), - Block::CobblestoneSlab(_) => Some(Item::CobblestoneSlab), - Block::BrickSlab(_) => Some(Item::BrickSlab), - Block::StoneBrickSlab(_) => Some(Item::StoneBrickSlab), - Block::NetherBrickSlab(_) => Some(Item::NetherBrickSlab), - Block::QuartzSlab(_) => Some(Item::QuartzSlab), - Block::RedSandstoneSlab(_) => Some(Item::RedSandstoneSlab), - Block::PurpurSlab(_) => Some(Item::PurpurSlab), - Block::PrismarineSlab(_) => Some(Item::PrismarineSlab), - Block::PrismarineBrickSlab(_) => Some(Item::PrismarineBrickSlab), - Block::DarkPrismarineSlab(_) => Some(Item::DarkPrismarineSlab), - Block::SmoothQuartz => Some(Item::SmoothQuartz), - Block::SmoothRedSandstone => Some(Item::SmoothRedSandstone), - Block::SmoothSandstone => Some(Item::SmoothSandstone), - Block::SmoothStone => Some(Item::SmoothStone), - Block::Bricks => Some(Item::Bricks), - Block::Tnt(_) => Some(Item::Tnt), - Block::Bookshelf => Some(Item::Bookshelf), - Block::MossyCobblestone => Some(Item::MossyCobblestone), - Block::Obsidian => Some(Item::Obsidian), - Block::Torch => Some(Item::Torch), - Block::EndRod(_) => Some(Item::EndRod), - Block::ChorusPlant(_) => Some(Item::ChorusPlant), - Block::ChorusFlower(_) => Some(Item::ChorusFlower), - Block::PurpurBlock => Some(Item::PurpurBlock), - Block::PurpurPillar(_) => Some(Item::PurpurPillar), - Block::PurpurStairs(_) => Some(Item::PurpurStairs), - Block::Spawner => Some(Item::Spawner), - Block::OakStairs(_) => Some(Item::OakStairs), - Block::Chest(_) => Some(Item::Chest), - Block::DiamondOre => Some(Item::DiamondOre), - Block::DiamondBlock => Some(Item::DiamondBlock), - Block::CraftingTable => Some(Item::CraftingTable), - Block::Farmland(_) => Some(Item::Farmland), - Block::Furnace(_) => Some(Item::Furnace), - Block::Ladder(_) => Some(Item::Ladder), - Block::Rail(_) => Some(Item::Rail), - Block::CobblestoneStairs(_) => Some(Item::CobblestoneStairs), - Block::Lever(_) => Some(Item::Lever), - Block::StonePressurePlate(_) => Some(Item::StonePressurePlate), - Block::OakPressurePlate(_) => Some(Item::OakPressurePlate), - Block::SprucePressurePlate(_) => Some(Item::SprucePressurePlate), - Block::BirchPressurePlate(_) => Some(Item::BirchPressurePlate), - Block::JunglePressurePlate(_) => Some(Item::JunglePressurePlate), - Block::AcaciaPressurePlate(_) => Some(Item::AcaciaPressurePlate), - Block::DarkOakPressurePlate(_) => Some(Item::DarkOakPressurePlate), - Block::RedstoneOre(_) => Some(Item::RedstoneOre), - Block::RedstoneTorch(_) => Some(Item::RedstoneTorch), - Block::StoneButton(_) => Some(Item::StoneButton), - Block::Snow(_) => Some(Item::Snow), - Block::Ice => Some(Item::Ice), - Block::SnowBlock => Some(Item::SnowBlock), - Block::Cactus(_) => Some(Item::Cactus), - Block::Clay => Some(Item::Clay), - Block::Jukebox(_) => Some(Item::Jukebox), - Block::OakFence(_) => Some(Item::OakFence), - Block::SpruceFence(_) => Some(Item::SpruceFence), - Block::BirchFence(_) => Some(Item::BirchFence), - Block::JungleFence(_) => Some(Item::JungleFence), - Block::AcaciaFence(_) => Some(Item::AcaciaFence), - Block::DarkOakFence(_) => Some(Item::DarkOakFence), - Block::Pumpkin => Some(Item::Pumpkin), - Block::CarvedPumpkin(_) => Some(Item::CarvedPumpkin), - Block::Netherrack => Some(Item::Netherrack), - Block::SoulSand => Some(Item::SoulSand), - Block::Glowstone => Some(Item::Glowstone), - Block::JackOLantern(_) => Some(Item::JackOLantern), - Block::OakTrapdoor(_) => Some(Item::OakTrapdoor), - Block::SpruceTrapdoor(_) => Some(Item::SpruceTrapdoor), - Block::BirchTrapdoor(_) => Some(Item::BirchTrapdoor), - Block::JungleTrapdoor(_) => Some(Item::JungleTrapdoor), - Block::AcaciaTrapdoor(_) => Some(Item::AcaciaTrapdoor), - Block::DarkOakTrapdoor(_) => Some(Item::DarkOakTrapdoor), - Block::InfestedStone => Some(Item::InfestedStone), - Block::InfestedCobblestone => Some(Item::InfestedCobblestone), - Block::InfestedStoneBricks => Some(Item::InfestedStoneBricks), - Block::InfestedMossyStoneBricks => Some(Item::InfestedMossyStoneBricks), - Block::InfestedCrackedStoneBricks => Some(Item::InfestedCrackedStoneBricks), - Block::InfestedChiseledStoneBricks => Some(Item::InfestedChiseledStoneBricks), - Block::StoneBricks => Some(Item::StoneBricks), - Block::MossyStoneBricks => Some(Item::MossyStoneBricks), - Block::CrackedStoneBricks => Some(Item::CrackedStoneBricks), - Block::ChiseledStoneBricks => Some(Item::ChiseledStoneBricks), - Block::BrownMushroomBlock(_) => Some(Item::BrownMushroomBlock), - Block::RedMushroomBlock(_) => Some(Item::RedMushroomBlock), - Block::MushroomStem(_) => Some(Item::MushroomStem), - Block::IronBars(_) => Some(Item::IronBars), - Block::GlassPane(_) => Some(Item::GlassPane), - Block::Melon => Some(Item::Melon), - Block::Vine(_) => Some(Item::Vine), - Block::OakFenceGate(_) => Some(Item::OakFenceGate), - Block::SpruceFenceGate(_) => Some(Item::SpruceFenceGate), - Block::BirchFenceGate(_) => Some(Item::BirchFenceGate), - Block::JungleFenceGate(_) => Some(Item::JungleFenceGate), - Block::AcaciaFenceGate(_) => Some(Item::AcaciaFenceGate), - Block::DarkOakFenceGate(_) => Some(Item::DarkOakFenceGate), - Block::BrickStairs(_) => Some(Item::BrickStairs), - Block::StoneBrickStairs(_) => Some(Item::StoneBrickStairs), - Block::Mycelium(_) => Some(Item::Mycelium), - Block::LilyPad => Some(Item::LilyPad), - Block::NetherBricks => Some(Item::NetherBricks), - Block::NetherBrickFence(_) => Some(Item::NetherBrickFence), - Block::NetherBrickStairs(_) => Some(Item::NetherBrickStairs), - Block::EnchantingTable => Some(Item::EnchantingTable), - Block::EndPortalFrame(_) => Some(Item::EndPortalFrame), - Block::EndStone => Some(Item::EndStone), - Block::EndStoneBricks => Some(Item::EndStoneBricks), - Block::DragonEgg => Some(Item::DragonEgg), - Block::RedstoneLamp(_) => Some(Item::RedstoneLamp), - Block::SandstoneStairs(_) => Some(Item::SandstoneStairs), - Block::EmeraldOre => Some(Item::EmeraldOre), - Block::EnderChest(_) => Some(Item::EnderChest), - Block::TripwireHook(_) => Some(Item::TripwireHook), - Block::EmeraldBlock => Some(Item::EmeraldBlock), - Block::SpruceStairs(_) => Some(Item::SpruceStairs), - Block::BirchStairs(_) => Some(Item::BirchStairs), - Block::JungleStairs(_) => Some(Item::JungleStairs), - Block::CommandBlock(_) => Some(Item::CommandBlock), - Block::Beacon => Some(Item::Beacon), - Block::CobblestoneWall(_) => Some(Item::CobblestoneWall), - Block::MossyCobblestoneWall(_) => Some(Item::MossyCobblestoneWall), - Block::OakButton(_) => Some(Item::OakButton), - Block::SpruceButton(_) => Some(Item::SpruceButton), - Block::BirchButton(_) => Some(Item::BirchButton), - Block::JungleButton(_) => Some(Item::JungleButton), - Block::AcaciaButton(_) => Some(Item::AcaciaButton), - Block::DarkOakButton(_) => Some(Item::DarkOakButton), - Block::Anvil(_) => Some(Item::Anvil), - Block::ChippedAnvil(_) => Some(Item::ChippedAnvil), - Block::DamagedAnvil(_) => Some(Item::DamagedAnvil), - Block::TrappedChest(_) => Some(Item::TrappedChest), - Block::LightWeightedPressurePlate(_) => Some(Item::LightWeightedPressurePlate), - Block::HeavyWeightedPressurePlate(_) => Some(Item::HeavyWeightedPressurePlate), - Block::DaylightDetector(_) => Some(Item::DaylightDetector), - Block::RedstoneBlock => Some(Item::RedstoneBlock), - Block::NetherQuartzOre => Some(Item::NetherQuartzOre), - Block::Hopper(_) => Some(Item::Hopper), - Block::ChiseledQuartzBlock => Some(Item::ChiseledQuartzBlock), - Block::QuartzBlock => Some(Item::QuartzBlock), - Block::QuartzPillar(_) => Some(Item::QuartzPillar), - Block::QuartzStairs(_) => Some(Item::QuartzStairs), - Block::ActivatorRail(_) => Some(Item::ActivatorRail), - Block::Dropper(_) => Some(Item::Dropper), - Block::WhiteTerracotta => Some(Item::WhiteTerracotta), - Block::OrangeTerracotta => Some(Item::OrangeTerracotta), - Block::MagentaTerracotta => Some(Item::MagentaTerracotta), - Block::LightBlueTerracotta => Some(Item::LightBlueTerracotta), - Block::YellowTerracotta => Some(Item::YellowTerracotta), - Block::LimeTerracotta => Some(Item::LimeTerracotta), - Block::PinkTerracotta => Some(Item::PinkTerracotta), - Block::GrayTerracotta => Some(Item::GrayTerracotta), - Block::LightGrayTerracotta => Some(Item::LightGrayTerracotta), - Block::CyanTerracotta => Some(Item::CyanTerracotta), - Block::PurpleTerracotta => Some(Item::PurpleTerracotta), - Block::BlueTerracotta => Some(Item::BlueTerracotta), - Block::BrownTerracotta => Some(Item::BrownTerracotta), - Block::GreenTerracotta => Some(Item::GreenTerracotta), - Block::RedTerracotta => Some(Item::RedTerracotta), - Block::BlackTerracotta => Some(Item::BlackTerracotta), - Block::Barrier => Some(Item::Barrier), - Block::IronTrapdoor(_) => Some(Item::IronTrapdoor), - Block::HayBlock(_) => Some(Item::HayBlock), - Block::WhiteCarpet => Some(Item::WhiteCarpet), - Block::OrangeCarpet => Some(Item::OrangeCarpet), - Block::MagentaCarpet => Some(Item::MagentaCarpet), - Block::LightBlueCarpet => Some(Item::LightBlueCarpet), - Block::YellowCarpet => Some(Item::YellowCarpet), - Block::LimeCarpet => Some(Item::LimeCarpet), - Block::PinkCarpet => Some(Item::PinkCarpet), - Block::GrayCarpet => Some(Item::GrayCarpet), - Block::LightGrayCarpet => Some(Item::LightGrayCarpet), - Block::CyanCarpet => Some(Item::CyanCarpet), - Block::PurpleCarpet => Some(Item::PurpleCarpet), - Block::BlueCarpet => Some(Item::BlueCarpet), - Block::BrownCarpet => Some(Item::BrownCarpet), - Block::GreenCarpet => Some(Item::GreenCarpet), - Block::RedCarpet => Some(Item::RedCarpet), - Block::BlackCarpet => Some(Item::BlackCarpet), - Block::Terracotta => Some(Item::Terracotta), - Block::CoalBlock => Some(Item::CoalBlock), - Block::PackedIce => Some(Item::PackedIce), - Block::AcaciaStairs(_) => Some(Item::AcaciaStairs), - Block::DarkOakStairs(_) => Some(Item::DarkOakStairs), - Block::SlimeBlock => Some(Item::SlimeBlock), - Block::GrassPath => Some(Item::GrassPath), - Block::Sunflower(_) => Some(Item::Sunflower), - Block::Lilac(_) => Some(Item::Lilac), - Block::RoseBush(_) => Some(Item::RoseBush), - Block::Peony(_) => Some(Item::Peony), - Block::TallGrass(_) => Some(Item::TallGrass), - Block::LargeFern(_) => Some(Item::LargeFern), - Block::WhiteStainedGlass => Some(Item::WhiteStainedGlass), - Block::OrangeStainedGlass => Some(Item::OrangeStainedGlass), - Block::MagentaStainedGlass => Some(Item::MagentaStainedGlass), - Block::LightBlueStainedGlass => Some(Item::LightBlueStainedGlass), - Block::YellowStainedGlass => Some(Item::YellowStainedGlass), - Block::LimeStainedGlass => Some(Item::LimeStainedGlass), - Block::PinkStainedGlass => Some(Item::PinkStainedGlass), - Block::GrayStainedGlass => Some(Item::GrayStainedGlass), - Block::LightGrayStainedGlass => Some(Item::LightGrayStainedGlass), - Block::CyanStainedGlass => Some(Item::CyanStainedGlass), - Block::PurpleStainedGlass => Some(Item::PurpleStainedGlass), - Block::BlueStainedGlass => Some(Item::BlueStainedGlass), - Block::BrownStainedGlass => Some(Item::BrownStainedGlass), - Block::GreenStainedGlass => Some(Item::GreenStainedGlass), - Block::RedStainedGlass => Some(Item::RedStainedGlass), - Block::BlackStainedGlass => Some(Item::BlackStainedGlass), - Block::WhiteStainedGlassPane(_) => Some(Item::WhiteStainedGlassPane), - Block::OrangeStainedGlassPane(_) => Some(Item::OrangeStainedGlassPane), - Block::MagentaStainedGlassPane(_) => Some(Item::MagentaStainedGlassPane), - Block::LightBlueStainedGlassPane(_) => Some(Item::LightBlueStainedGlassPane), - Block::YellowStainedGlassPane(_) => Some(Item::YellowStainedGlassPane), - Block::LimeStainedGlassPane(_) => Some(Item::LimeStainedGlassPane), - Block::PinkStainedGlassPane(_) => Some(Item::PinkStainedGlassPane), - Block::GrayStainedGlassPane(_) => Some(Item::GrayStainedGlassPane), - Block::LightGrayStainedGlassPane(_) => Some(Item::LightGrayStainedGlassPane), - Block::CyanStainedGlassPane(_) => Some(Item::CyanStainedGlassPane), - Block::PurpleStainedGlassPane(_) => Some(Item::PurpleStainedGlassPane), - Block::BlueStainedGlassPane(_) => Some(Item::BlueStainedGlassPane), - Block::BrownStainedGlassPane(_) => Some(Item::BrownStainedGlassPane), - Block::GreenStainedGlassPane(_) => Some(Item::GreenStainedGlassPane), - Block::RedStainedGlassPane(_) => Some(Item::RedStainedGlassPane), - Block::BlackStainedGlassPane(_) => Some(Item::BlackStainedGlassPane), - Block::Prismarine => Some(Item::Prismarine), - Block::PrismarineBricks => Some(Item::PrismarineBricks), - Block::DarkPrismarine => Some(Item::DarkPrismarine), - Block::PrismarineStairs(_) => Some(Item::PrismarineStairs), - Block::PrismarineBrickStairs(_) => Some(Item::PrismarineBrickStairs), - Block::DarkPrismarineStairs(_) => Some(Item::DarkPrismarineStairs), - Block::SeaLantern => Some(Item::SeaLantern), - Block::RedSandstone => Some(Item::RedSandstone), - Block::ChiseledRedSandstone => Some(Item::ChiseledRedSandstone), - Block::CutRedSandstone => Some(Item::CutRedSandstone), - Block::RedSandstoneStairs(_) => Some(Item::RedSandstoneStairs), - Block::RepeatingCommandBlock(_) => Some(Item::RepeatingCommandBlock), - Block::ChainCommandBlock(_) => Some(Item::ChainCommandBlock), - Block::MagmaBlock => Some(Item::MagmaBlock), - Block::NetherWartBlock => Some(Item::NetherWartBlock), - Block::RedNetherBricks => Some(Item::RedNetherBricks), - Block::BoneBlock(_) => Some(Item::BoneBlock), - Block::StructureVoid => Some(Item::StructureVoid), - Block::Observer(_) => Some(Item::Observer), - Block::ShulkerBox(_) => Some(Item::ShulkerBox), - Block::WhiteShulkerBox(_) => Some(Item::WhiteShulkerBox), - Block::OrangeShulkerBox(_) => Some(Item::OrangeShulkerBox), - Block::MagentaShulkerBox(_) => Some(Item::MagentaShulkerBox), - Block::LightBlueShulkerBox(_) => Some(Item::LightBlueShulkerBox), - Block::YellowShulkerBox(_) => Some(Item::YellowShulkerBox), - Block::LimeShulkerBox(_) => Some(Item::LimeShulkerBox), - Block::PinkShulkerBox(_) => Some(Item::PinkShulkerBox), - Block::GrayShulkerBox(_) => Some(Item::GrayShulkerBox), - Block::LightGrayShulkerBox(_) => Some(Item::LightGrayShulkerBox), - Block::CyanShulkerBox(_) => Some(Item::CyanShulkerBox), - Block::PurpleShulkerBox(_) => Some(Item::PurpleShulkerBox), - Block::BlueShulkerBox(_) => Some(Item::BlueShulkerBox), - Block::BrownShulkerBox(_) => Some(Item::BrownShulkerBox), - Block::GreenShulkerBox(_) => Some(Item::GreenShulkerBox), - Block::RedShulkerBox(_) => Some(Item::RedShulkerBox), - Block::BlackShulkerBox(_) => Some(Item::BlackShulkerBox), - Block::WhiteGlazedTerracotta(_) => Some(Item::WhiteGlazedTerracotta), - Block::OrangeGlazedTerracotta(_) => Some(Item::OrangeGlazedTerracotta), - Block::MagentaGlazedTerracotta(_) => Some(Item::MagentaGlazedTerracotta), - Block::LightBlueGlazedTerracotta(_) => Some(Item::LightBlueGlazedTerracotta), - Block::YellowGlazedTerracotta(_) => Some(Item::YellowGlazedTerracotta), - Block::LimeGlazedTerracotta(_) => Some(Item::LimeGlazedTerracotta), - Block::PinkGlazedTerracotta(_) => Some(Item::PinkGlazedTerracotta), - Block::GrayGlazedTerracotta(_) => Some(Item::GrayGlazedTerracotta), - Block::LightGrayGlazedTerracotta(_) => Some(Item::LightGrayGlazedTerracotta), - Block::CyanGlazedTerracotta(_) => Some(Item::CyanGlazedTerracotta), - Block::PurpleGlazedTerracotta(_) => Some(Item::PurpleGlazedTerracotta), - Block::BlueGlazedTerracotta(_) => Some(Item::BlueGlazedTerracotta), - Block::BrownGlazedTerracotta(_) => Some(Item::BrownGlazedTerracotta), - Block::GreenGlazedTerracotta(_) => Some(Item::GreenGlazedTerracotta), - Block::RedGlazedTerracotta(_) => Some(Item::RedGlazedTerracotta), - Block::BlackGlazedTerracotta(_) => Some(Item::BlackGlazedTerracotta), - Block::WhiteConcrete => Some(Item::WhiteConcrete), - Block::OrangeConcrete => Some(Item::OrangeConcrete), - Block::MagentaConcrete => Some(Item::MagentaConcrete), - Block::LightBlueConcrete => Some(Item::LightBlueConcrete), - Block::YellowConcrete => Some(Item::YellowConcrete), - Block::LimeConcrete => Some(Item::LimeConcrete), - Block::PinkConcrete => Some(Item::PinkConcrete), - Block::GrayConcrete => Some(Item::GrayConcrete), - Block::LightGrayConcrete => Some(Item::LightGrayConcrete), - Block::CyanConcrete => Some(Item::CyanConcrete), - Block::PurpleConcrete => Some(Item::PurpleConcrete), - Block::BlueConcrete => Some(Item::BlueConcrete), - Block::BrownConcrete => Some(Item::BrownConcrete), - Block::GreenConcrete => Some(Item::GreenConcrete), - Block::RedConcrete => Some(Item::RedConcrete), - Block::BlackConcrete => Some(Item::BlackConcrete), - Block::WhiteConcretePowder => Some(Item::WhiteConcretePowder), - Block::OrangeConcretePowder => Some(Item::OrangeConcretePowder), - Block::MagentaConcretePowder => Some(Item::MagentaConcretePowder), - Block::LightBlueConcretePowder => Some(Item::LightBlueConcretePowder), - Block::YellowConcretePowder => Some(Item::YellowConcretePowder), - Block::LimeConcretePowder => Some(Item::LimeConcretePowder), - Block::PinkConcretePowder => Some(Item::PinkConcretePowder), - Block::GrayConcretePowder => Some(Item::GrayConcretePowder), - Block::LightGrayConcretePowder => Some(Item::LightGrayConcretePowder), - Block::CyanConcretePowder => Some(Item::CyanConcretePowder), - Block::PurpleConcretePowder => Some(Item::PurpleConcretePowder), - Block::BlueConcretePowder => Some(Item::BlueConcretePowder), - Block::BrownConcretePowder => Some(Item::BrownConcretePowder), - Block::GreenConcretePowder => Some(Item::GreenConcretePowder), - Block::RedConcretePowder => Some(Item::RedConcretePowder), - Block::BlackConcretePowder => Some(Item::BlackConcretePowder), - Block::TurtleEgg(_) => Some(Item::TurtleEgg), - Block::DeadTubeCoralBlock => Some(Item::DeadTubeCoralBlock), - Block::DeadBrainCoralBlock => Some(Item::DeadBrainCoralBlock), - Block::DeadBubbleCoralBlock => Some(Item::DeadBubbleCoralBlock), - Block::DeadFireCoralBlock => Some(Item::DeadFireCoralBlock), - Block::DeadHornCoralBlock => Some(Item::DeadHornCoralBlock), - Block::TubeCoralBlock => Some(Item::TubeCoralBlock), - Block::BrainCoralBlock => Some(Item::BrainCoralBlock), - Block::BubbleCoralBlock => Some(Item::BubbleCoralBlock), - Block::FireCoralBlock => Some(Item::FireCoralBlock), - Block::HornCoralBlock => Some(Item::HornCoralBlock), - Block::TubeCoral(_) => Some(Item::TubeCoral), - Block::BrainCoral(_) => Some(Item::BrainCoral), - Block::BubbleCoral(_) => Some(Item::BubbleCoral), - Block::FireCoral(_) => Some(Item::FireCoral), - Block::HornCoral(_) => Some(Item::HornCoral), - Block::DeadBrainCoral(_) => Some(Item::DeadBrainCoral), - Block::DeadBubbleCoral(_) => Some(Item::DeadBubbleCoral), - Block::DeadFireCoral(_) => Some(Item::DeadFireCoral), - Block::DeadHornCoral(_) => Some(Item::DeadHornCoral), - Block::DeadTubeCoral(_) => Some(Item::DeadTubeCoral), - Block::TubeCoralFan(_) => Some(Item::TubeCoralFan), - Block::BrainCoralFan(_) => Some(Item::BrainCoralFan), - Block::BubbleCoralFan(_) => Some(Item::BubbleCoralFan), - Block::FireCoralFan(_) => Some(Item::FireCoralFan), - Block::HornCoralFan(_) => Some(Item::HornCoralFan), - Block::DeadTubeCoralFan(_) => Some(Item::DeadTubeCoralFan), - Block::DeadBrainCoralFan(_) => Some(Item::DeadBrainCoralFan), - Block::DeadBubbleCoralFan(_) => Some(Item::DeadBubbleCoralFan), - Block::DeadFireCoralFan(_) => Some(Item::DeadFireCoralFan), - Block::DeadHornCoralFan(_) => Some(Item::DeadHornCoralFan), - Block::BlueIce => Some(Item::BlueIce), - Block::Conduit(_) => Some(Item::Conduit), - Block::IronDoor(_) => Some(Item::IronDoor), - Block::OakDoor(_) => Some(Item::OakDoor), - Block::SpruceDoor(_) => Some(Item::SpruceDoor), - Block::BirchDoor(_) => Some(Item::BirchDoor), - Block::JungleDoor(_) => Some(Item::JungleDoor), - Block::AcaciaDoor(_) => Some(Item::AcaciaDoor), - Block::DarkOakDoor(_) => Some(Item::DarkOakDoor), - Block::Repeater(_) => Some(Item::Repeater), - Block::Comparator(_) => Some(Item::Comparator), - Block::StructureBlock(_) => Some(Item::StructureBlock), - Block::Wheat(_) => Some(Item::Wheat), - Block::Sign(_) => Some(Item::Sign), - Block::SugarCane(_) => Some(Item::SugarCane), - Block::Kelp(_) => Some(Item::Kelp), - Block::DriedKelpBlock => Some(Item::DriedKelpBlock), - Block::Cake(_) => Some(Item::Cake), - Block::WhiteBed(_) => Some(Item::WhiteBed), - Block::OrangeBed(_) => Some(Item::OrangeBed), - Block::MagentaBed(_) => Some(Item::MagentaBed), - Block::LightBlueBed(_) => Some(Item::LightBlueBed), - Block::YellowBed(_) => Some(Item::YellowBed), - Block::LimeBed(_) => Some(Item::LimeBed), - Block::PinkBed(_) => Some(Item::PinkBed), - Block::GrayBed(_) => Some(Item::GrayBed), - Block::LightGrayBed(_) => Some(Item::LightGrayBed), - Block::CyanBed(_) => Some(Item::CyanBed), - Block::PurpleBed(_) => Some(Item::PurpleBed), - Block::BlueBed(_) => Some(Item::BlueBed), - Block::BrownBed(_) => Some(Item::BrownBed), - Block::GreenBed(_) => Some(Item::GreenBed), - Block::RedBed(_) => Some(Item::RedBed), - Block::BlackBed(_) => Some(Item::BlackBed), - Block::NetherWart(_) => Some(Item::NetherWart), - Block::BrewingStand(_) => Some(Item::BrewingStand), - Block::Cauldron(_) => Some(Item::Cauldron), - Block::FlowerPot => Some(Item::FlowerPot), - Block::SkeletonSkull(_) => Some(Item::SkeletonSkull), - Block::WitherSkeletonSkull(_) => Some(Item::WitherSkeletonSkull), - Block::PlayerHead(_) => Some(Item::PlayerHead), - Block::ZombieHead(_) => Some(Item::ZombieHead), - Block::CreeperHead(_) => Some(Item::CreeperHead), - Block::DragonHead(_) => Some(Item::DragonHead), - Block::WhiteBanner(_) => Some(Item::WhiteBanner), - Block::OrangeBanner(_) => Some(Item::OrangeBanner), - Block::MagentaBanner(_) => Some(Item::MagentaBanner), - Block::LightBlueBanner(_) => Some(Item::LightBlueBanner), - Block::YellowBanner(_) => Some(Item::YellowBanner), - Block::LimeBanner(_) => Some(Item::LimeBanner), - Block::PinkBanner(_) => Some(Item::PinkBanner), - Block::GrayBanner(_) => Some(Item::GrayBanner), - Block::LightGrayBanner(_) => Some(Item::LightGrayBanner), - Block::CyanBanner(_) => Some(Item::CyanBanner), - Block::PurpleBanner(_) => Some(Item::PurpleBanner), - Block::BlueBanner(_) => Some(Item::BlueBanner), - Block::BrownBanner(_) => Some(Item::BrownBanner), - Block::GreenBanner(_) => Some(Item::GreenBanner), - Block::RedBanner(_) => Some(Item::RedBanner), - Block::BlackBanner(_) => Some(Item::BlackBanner), - _ => None, - } -} diff --git a/items/src/item.rs b/items/src/item.rs deleted file mode 100644 index 7236810aa..000000000 --- a/items/src/item.rs +++ /dev/null @@ -1,2384 +0,0 @@ -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ToPrimitive, FromPrimitive)] -pub enum Item { - Air, - Stone, - Granite, - PolishedGranite, - Diorite, - PolishedDiorite, - Andesite, - PolishedAndesite, - GrassBlock, - Dirt, - CoarseDirt, - Podzol, - Cobblestone, - OakPlanks, - SprucePlanks, - BirchPlanks, - JunglePlanks, - AcaciaPlanks, - DarkOakPlanks, - OakSapling, - SpruceSapling, - BirchSapling, - JungleSapling, - AcaciaSapling, - DarkOakSapling, - Bedrock, - Sand, - RedSand, - Gravel, - GoldOre, - IronOre, - CoalOre, - OakLog, - SpruceLog, - BirchLog, - JungleLog, - AcaciaLog, - DarkOakLog, - StrippedOakLog, - StrippedSpruceLog, - StrippedBirchLog, - StrippedJungleLog, - StrippedAcaciaLog, - StrippedDarkOakLog, - StrippedOakWood, - StrippedSpruceWood, - StrippedBirchWood, - StrippedJungleWood, - StrippedAcaciaWood, - StrippedDarkOakWood, - OakWood, - SpruceWood, - BirchWood, - JungleWood, - AcaciaWood, - DarkOakWood, - OakLeaves, - SpruceLeaves, - BirchLeaves, - JungleLeaves, - AcaciaLeaves, - DarkOakLeaves, - Sponge, - WetSponge, - Glass, - LapisOre, - LapisBlock, - Dispenser, - Sandstone, - ChiseledSandstone, - CutSandstone, - NoteBlock, - PoweredRail, - DetectorRail, - StickyPiston, - Cobweb, - Grass, - Fern, - DeadBush, - Seagrass, - SeaPickle, - Piston, - WhiteWool, - OrangeWool, - MagentaWool, - LightBlueWool, - YellowWool, - LimeWool, - PinkWool, - GrayWool, - LightGrayWool, - CyanWool, - PurpleWool, - BlueWool, - BrownWool, - GreenWool, - RedWool, - BlackWool, - Dandelion, - Poppy, - BlueOrchid, - Allium, - AzureBluet, - RedTulip, - OrangeTulip, - WhiteTulip, - PinkTulip, - OxeyeDaisy, - BrownMushroom, - RedMushroom, - GoldBlock, - IronBlock, - OakSlab, - SpruceSlab, - BirchSlab, - JungleSlab, - AcaciaSlab, - DarkOakSlab, - StoneSlab, - SandstoneSlab, - PetrifiedOakSlab, - CobblestoneSlab, - BrickSlab, - StoneBrickSlab, - NetherBrickSlab, - QuartzSlab, - RedSandstoneSlab, - PurpurSlab, - PrismarineSlab, - PrismarineBrickSlab, - DarkPrismarineSlab, - SmoothQuartz, - SmoothRedSandstone, - SmoothSandstone, - SmoothStone, - Bricks, - Tnt, - Bookshelf, - MossyCobblestone, - Obsidian, - Torch, - EndRod, - ChorusPlant, - ChorusFlower, - PurpurBlock, - PurpurPillar, - PurpurStairs, - Spawner, - OakStairs, - Chest, - DiamondOre, - DiamondBlock, - CraftingTable, - Farmland, - Furnace, - Ladder, - Rail, - CobblestoneStairs, - Lever, - StonePressurePlate, - OakPressurePlate, - SprucePressurePlate, - BirchPressurePlate, - JunglePressurePlate, - AcaciaPressurePlate, - DarkOakPressurePlate, - RedstoneOre, - RedstoneTorch, - StoneButton, - Snow, - Ice, - SnowBlock, - Cactus, - Clay, - Jukebox, - OakFence, - SpruceFence, - BirchFence, - JungleFence, - AcaciaFence, - DarkOakFence, - Pumpkin, - CarvedPumpkin, - Netherrack, - SoulSand, - Glowstone, - JackOLantern, - OakTrapdoor, - SpruceTrapdoor, - BirchTrapdoor, - JungleTrapdoor, - AcaciaTrapdoor, - DarkOakTrapdoor, - InfestedStone, - InfestedCobblestone, - InfestedStoneBricks, - InfestedMossyStoneBricks, - InfestedCrackedStoneBricks, - InfestedChiseledStoneBricks, - StoneBricks, - MossyStoneBricks, - CrackedStoneBricks, - ChiseledStoneBricks, - BrownMushroomBlock, - RedMushroomBlock, - MushroomStem, - IronBars, - GlassPane, - Melon, - Vine, - OakFenceGate, - SpruceFenceGate, - BirchFenceGate, - JungleFenceGate, - AcaciaFenceGate, - DarkOakFenceGate, - BrickStairs, - StoneBrickStairs, - Mycelium, - LilyPad, - NetherBricks, - NetherBrickFence, - NetherBrickStairs, - EnchantingTable, - EndPortalFrame, - EndStone, - EndStoneBricks, - DragonEgg, - RedstoneLamp, - SandstoneStairs, - EmeraldOre, - EnderChest, - TripwireHook, - EmeraldBlock, - SpruceStairs, - BirchStairs, - JungleStairs, - CommandBlock, - Beacon, - CobblestoneWall, - MossyCobblestoneWall, - OakButton, - SpruceButton, - BirchButton, - JungleButton, - AcaciaButton, - DarkOakButton, - Anvil, - ChippedAnvil, - DamagedAnvil, - TrappedChest, - LightWeightedPressurePlate, - HeavyWeightedPressurePlate, - DaylightDetector, - RedstoneBlock, - NetherQuartzOre, - Hopper, - ChiseledQuartzBlock, - QuartzBlock, - QuartzPillar, - QuartzStairs, - ActivatorRail, - Dropper, - WhiteTerracotta, - OrangeTerracotta, - MagentaTerracotta, - LightBlueTerracotta, - YellowTerracotta, - LimeTerracotta, - PinkTerracotta, - GrayTerracotta, - LightGrayTerracotta, - CyanTerracotta, - PurpleTerracotta, - BlueTerracotta, - BrownTerracotta, - GreenTerracotta, - RedTerracotta, - BlackTerracotta, - Barrier, - IronTrapdoor, - HayBlock, - WhiteCarpet, - OrangeCarpet, - MagentaCarpet, - LightBlueCarpet, - YellowCarpet, - LimeCarpet, - PinkCarpet, - GrayCarpet, - LightGrayCarpet, - CyanCarpet, - PurpleCarpet, - BlueCarpet, - BrownCarpet, - GreenCarpet, - RedCarpet, - BlackCarpet, - Terracotta, - CoalBlock, - PackedIce, - AcaciaStairs, - DarkOakStairs, - SlimeBlock, - GrassPath, - Sunflower, - Lilac, - RoseBush, - Peony, - TallGrass, - LargeFern, - WhiteStainedGlass, - OrangeStainedGlass, - MagentaStainedGlass, - LightBlueStainedGlass, - YellowStainedGlass, - LimeStainedGlass, - PinkStainedGlass, - GrayStainedGlass, - LightGrayStainedGlass, - CyanStainedGlass, - PurpleStainedGlass, - BlueStainedGlass, - BrownStainedGlass, - GreenStainedGlass, - RedStainedGlass, - BlackStainedGlass, - WhiteStainedGlassPane, - OrangeStainedGlassPane, - MagentaStainedGlassPane, - LightBlueStainedGlassPane, - YellowStainedGlassPane, - LimeStainedGlassPane, - PinkStainedGlassPane, - GrayStainedGlassPane, - LightGrayStainedGlassPane, - CyanStainedGlassPane, - PurpleStainedGlassPane, - BlueStainedGlassPane, - BrownStainedGlassPane, - GreenStainedGlassPane, - RedStainedGlassPane, - BlackStainedGlassPane, - Prismarine, - PrismarineBricks, - DarkPrismarine, - PrismarineStairs, - PrismarineBrickStairs, - DarkPrismarineStairs, - SeaLantern, - RedSandstone, - ChiseledRedSandstone, - CutRedSandstone, - RedSandstoneStairs, - RepeatingCommandBlock, - ChainCommandBlock, - MagmaBlock, - NetherWartBlock, - RedNetherBricks, - BoneBlock, - StructureVoid, - Observer, - ShulkerBox, - WhiteShulkerBox, - OrangeShulkerBox, - MagentaShulkerBox, - LightBlueShulkerBox, - YellowShulkerBox, - LimeShulkerBox, - PinkShulkerBox, - GrayShulkerBox, - LightGrayShulkerBox, - CyanShulkerBox, - PurpleShulkerBox, - BlueShulkerBox, - BrownShulkerBox, - GreenShulkerBox, - RedShulkerBox, - BlackShulkerBox, - WhiteGlazedTerracotta, - OrangeGlazedTerracotta, - MagentaGlazedTerracotta, - LightBlueGlazedTerracotta, - YellowGlazedTerracotta, - LimeGlazedTerracotta, - PinkGlazedTerracotta, - GrayGlazedTerracotta, - LightGrayGlazedTerracotta, - CyanGlazedTerracotta, - PurpleGlazedTerracotta, - BlueGlazedTerracotta, - BrownGlazedTerracotta, - GreenGlazedTerracotta, - RedGlazedTerracotta, - BlackGlazedTerracotta, - WhiteConcrete, - OrangeConcrete, - MagentaConcrete, - LightBlueConcrete, - YellowConcrete, - LimeConcrete, - PinkConcrete, - GrayConcrete, - LightGrayConcrete, - CyanConcrete, - PurpleConcrete, - BlueConcrete, - BrownConcrete, - GreenConcrete, - RedConcrete, - BlackConcrete, - WhiteConcretePowder, - OrangeConcretePowder, - MagentaConcretePowder, - LightBlueConcretePowder, - YellowConcretePowder, - LimeConcretePowder, - PinkConcretePowder, - GrayConcretePowder, - LightGrayConcretePowder, - CyanConcretePowder, - PurpleConcretePowder, - BlueConcretePowder, - BrownConcretePowder, - GreenConcretePowder, - RedConcretePowder, - BlackConcretePowder, - TurtleEgg, - DeadTubeCoralBlock, - DeadBrainCoralBlock, - DeadBubbleCoralBlock, - DeadFireCoralBlock, - DeadHornCoralBlock, - TubeCoralBlock, - BrainCoralBlock, - BubbleCoralBlock, - FireCoralBlock, - HornCoralBlock, - TubeCoral, - BrainCoral, - BubbleCoral, - FireCoral, - HornCoral, - DeadBrainCoral, - DeadBubbleCoral, - DeadFireCoral, - DeadHornCoral, - DeadTubeCoral, - TubeCoralFan, - BrainCoralFan, - BubbleCoralFan, - FireCoralFan, - HornCoralFan, - DeadTubeCoralFan, - DeadBrainCoralFan, - DeadBubbleCoralFan, - DeadFireCoralFan, - DeadHornCoralFan, - BlueIce, - Conduit, - IronDoor, - OakDoor, - SpruceDoor, - BirchDoor, - JungleDoor, - AcaciaDoor, - DarkOakDoor, - Repeater, - Comparator, - StructureBlock, - TurtleHelmet, - Scute, - IronShovel, - IronPickaxe, - IronAxe, - FlintAndSteel, - Apple, - Bow, - Arrow, - Coal, - Charcoal, - Diamond, - IronIngot, - GoldIngot, - IronSword, - WoodenSword, - WoodenShovel, - WoodenPickaxe, - WoodenAxe, - StoneSword, - StoneShovel, - StonePickaxe, - StoneAxe, - DiamondSword, - DiamondShovel, - DiamondPickaxe, - DiamondAxe, - Stick, - Bowl, - MushroomStew, - GoldenSword, - GoldenShovel, - GoldenPickaxe, - GoldenAxe, - String, - Feather, - Gunpowder, - WoodenHoe, - StoneHoe, - IronHoe, - DiamondHoe, - GoldenHoe, - WheatSeeds, - Wheat, - Bread, - LeatherHelmet, - LeatherChestplate, - LeatherLeggings, - LeatherBoots, - ChainmailHelmet, - ChainmailChestplate, - ChainmailLeggings, - ChainmailBoots, - IronHelmet, - IronChestplate, - IronLeggings, - IronBoots, - DiamondHelmet, - DiamondChestplate, - DiamondLeggings, - DiamondBoots, - GoldenHelmet, - GoldenChestplate, - GoldenLeggings, - GoldenBoots, - Flint, - Porkchop, - CookedPorkchop, - Painting, - GoldenApple, - EnchantedGoldenApple, - Sign, - Bucket, - WaterBucket, - LavaBucket, - Minecart, - Saddle, - Redstone, - Snowball, - OakBoat, - Leather, - MilkBucket, - PufferfishBucket, - SalmonBucket, - CodBucket, - TropicalFishBucket, - Brick, - ClayBall, - SugarCane, - Kelp, - DriedKelpBlock, - Paper, - Book, - SlimeBall, - ChestMinecart, - FurnaceMinecart, - Egg, - Compass, - FishingRod, - Clock, - GlowstoneDust, - Cod, - Salmon, - TropicalFish, - Pufferfish, - CookedCod, - CookedSalmon, - InkSac, - RoseRed, - CactusGreen, - CocoaBeans, - LapisLazuli, - PurpleDye, - CyanDye, - LightGrayDye, - GrayDye, - PinkDye, - LimeDye, - DandelionYellow, - LightBlueDye, - MagentaDye, - OrangeDye, - BoneMeal, - Bone, - Sugar, - Cake, - WhiteBed, - OrangeBed, - MagentaBed, - LightBlueBed, - YellowBed, - LimeBed, - PinkBed, - GrayBed, - LightGrayBed, - CyanBed, - PurpleBed, - BlueBed, - BrownBed, - GreenBed, - RedBed, - BlackBed, - Cookie, - FilledMap, - Shears, - MelonSlice, - DriedKelp, - PumpkinSeeds, - MelonSeeds, - Beef, - CookedBeef, - Chicken, - CookedChicken, - RottenFlesh, - EnderPearl, - BlazeRod, - GhastTear, - GoldNugget, - NetherWart, - Potion, - GlassBottle, - SpiderEye, - FermentedSpiderEye, - BlazePowder, - MagmaCream, - BrewingStand, - Cauldron, - EnderEye, - GlisteringMelonSlice, - BatSpawnEgg, - BlazeSpawnEgg, - CaveSpiderSpawnEgg, - ChickenSpawnEgg, - CodSpawnEgg, - CowSpawnEgg, - CreeperSpawnEgg, - DolphinSpawnEgg, - DonkeySpawnEgg, - DrownedSpawnEgg, - ElderGuardianSpawnEgg, - EndermanSpawnEgg, - EndermiteSpawnEgg, - EvokerSpawnEgg, - GhastSpawnEgg, - GuardianSpawnEgg, - HorseSpawnEgg, - HuskSpawnEgg, - LlamaSpawnEgg, - MagmaCubeSpawnEgg, - MooshroomSpawnEgg, - MuleSpawnEgg, - OcelotSpawnEgg, - ParrotSpawnEgg, - PhantomSpawnEgg, - PigSpawnEgg, - PolarBearSpawnEgg, - PufferfishSpawnEgg, - RabbitSpawnEgg, - SalmonSpawnEgg, - SheepSpawnEgg, - ShulkerSpawnEgg, - SilverfishSpawnEgg, - SkeletonSpawnEgg, - SkeletonHorseSpawnEgg, - SlimeSpawnEgg, - SpiderSpawnEgg, - SquidSpawnEgg, - StraySpawnEgg, - TropicalFishSpawnEgg, - TurtleSpawnEgg, - VexSpawnEgg, - VillagerSpawnEgg, - VindicatorSpawnEgg, - WitchSpawnEgg, - WitherSkeletonSpawnEgg, - WolfSpawnEgg, - ZombieSpawnEgg, - ZombieHorseSpawnEgg, - ZombiePigmanSpawnEgg, - ZombieVillagerSpawnEgg, - ExperienceBottle, - FireCharge, - WritableBook, - WrittenBook, - Emerald, - ItemFrame, - FlowerPot, - Carrot, - Potato, - BakedPotato, - PoisonousPotato, - Map, - GoldenCarrot, - SkeletonSkull, - WitherSkeletonSkull, - PlayerHead, - ZombieHead, - CreeperHead, - DragonHead, - CarrotOnAStick, - NetherStar, - PumpkinPie, - FireworkRocket, - FireworkStar, - EnchantedBook, - NetherBrick, - Quartz, - TntMinecart, - HopperMinecart, - PrismarineShard, - PrismarineCrystals, - Rabbit, - CookedRabbit, - RabbitStew, - RabbitFoot, - RabbitHide, - ArmorStand, - IronHorseArmor, - GoldenHorseArmor, - DiamondHorseArmor, - Lead, - NameTag, - CommandBlockMinecart, - Mutton, - CookedMutton, - WhiteBanner, - OrangeBanner, - MagentaBanner, - LightBlueBanner, - YellowBanner, - LimeBanner, - PinkBanner, - GrayBanner, - LightGrayBanner, - CyanBanner, - PurpleBanner, - BlueBanner, - BrownBanner, - GreenBanner, - RedBanner, - BlackBanner, - EndCrystal, - ChorusFruit, - PoppedChorusFruit, - Beetroot, - BeetrootSeeds, - BeetrootSoup, - DragonBreath, - SplashPotion, - SpectralArrow, - TippedArrow, - LingeringPotion, - Shield, - Elytra, - SpruceBoat, - BirchBoat, - JungleBoat, - AcaciaBoat, - DarkOakBoat, - TotemOfUndying, - ShulkerShell, - IronNugget, - KnowledgeBook, - DebugStick, - MusicDisc13, - MusicDiscCat, - MusicDiscBlocks, - MusicDiscChirp, - MusicDiscFar, - MusicDiscMall, - MusicDiscMellohi, - MusicDiscStal, - MusicDiscStrad, - MusicDiscWard, - MusicDisc11, - MusicDiscWait, - Trident, - PhantomMembrane, - NautilusShell, - HeartOfTheSea, -} -impl Item { - pub fn from_identifier(identifier: &str) -> Option<Self> { - match identifier { - "minecraft:air" => Some(Item::Air), - "minecraft:stone" => Some(Item::Stone), - "minecraft:granite" => Some(Item::Granite), - "minecraft:polished_granite" => Some(Item::PolishedGranite), - "minecraft:diorite" => Some(Item::Diorite), - "minecraft:polished_diorite" => Some(Item::PolishedDiorite), - "minecraft:andesite" => Some(Item::Andesite), - "minecraft:polished_andesite" => Some(Item::PolishedAndesite), - "minecraft:grass_block" => Some(Item::GrassBlock), - "minecraft:dirt" => Some(Item::Dirt), - "minecraft:coarse_dirt" => Some(Item::CoarseDirt), - "minecraft:podzol" => Some(Item::Podzol), - "minecraft:cobblestone" => Some(Item::Cobblestone), - "minecraft:oak_planks" => Some(Item::OakPlanks), - "minecraft:spruce_planks" => Some(Item::SprucePlanks), - "minecraft:birch_planks" => Some(Item::BirchPlanks), - "minecraft:jungle_planks" => Some(Item::JunglePlanks), - "minecraft:acacia_planks" => Some(Item::AcaciaPlanks), - "minecraft:dark_oak_planks" => Some(Item::DarkOakPlanks), - "minecraft:oak_sapling" => Some(Item::OakSapling), - "minecraft:spruce_sapling" => Some(Item::SpruceSapling), - "minecraft:birch_sapling" => Some(Item::BirchSapling), - "minecraft:jungle_sapling" => Some(Item::JungleSapling), - "minecraft:acacia_sapling" => Some(Item::AcaciaSapling), - "minecraft:dark_oak_sapling" => Some(Item::DarkOakSapling), - "minecraft:bedrock" => Some(Item::Bedrock), - "minecraft:sand" => Some(Item::Sand), - "minecraft:red_sand" => Some(Item::RedSand), - "minecraft:gravel" => Some(Item::Gravel), - "minecraft:gold_ore" => Some(Item::GoldOre), - "minecraft:iron_ore" => Some(Item::IronOre), - "minecraft:coal_ore" => Some(Item::CoalOre), - "minecraft:oak_log" => Some(Item::OakLog), - "minecraft:spruce_log" => Some(Item::SpruceLog), - "minecraft:birch_log" => Some(Item::BirchLog), - "minecraft:jungle_log" => Some(Item::JungleLog), - "minecraft:acacia_log" => Some(Item::AcaciaLog), - "minecraft:dark_oak_log" => Some(Item::DarkOakLog), - "minecraft:stripped_oak_log" => Some(Item::StrippedOakLog), - "minecraft:stripped_spruce_log" => Some(Item::StrippedSpruceLog), - "minecraft:stripped_birch_log" => Some(Item::StrippedBirchLog), - "minecraft:stripped_jungle_log" => Some(Item::StrippedJungleLog), - "minecraft:stripped_acacia_log" => Some(Item::StrippedAcaciaLog), - "minecraft:stripped_dark_oak_log" => Some(Item::StrippedDarkOakLog), - "minecraft:stripped_oak_wood" => Some(Item::StrippedOakWood), - "minecraft:stripped_spruce_wood" => Some(Item::StrippedSpruceWood), - "minecraft:stripped_birch_wood" => Some(Item::StrippedBirchWood), - "minecraft:stripped_jungle_wood" => Some(Item::StrippedJungleWood), - "minecraft:stripped_acacia_wood" => Some(Item::StrippedAcaciaWood), - "minecraft:stripped_dark_oak_wood" => Some(Item::StrippedDarkOakWood), - "minecraft:oak_wood" => Some(Item::OakWood), - "minecraft:spruce_wood" => Some(Item::SpruceWood), - "minecraft:birch_wood" => Some(Item::BirchWood), - "minecraft:jungle_wood" => Some(Item::JungleWood), - "minecraft:acacia_wood" => Some(Item::AcaciaWood), - "minecraft:dark_oak_wood" => Some(Item::DarkOakWood), - "minecraft:oak_leaves" => Some(Item::OakLeaves), - "minecraft:spruce_leaves" => Some(Item::SpruceLeaves), - "minecraft:birch_leaves" => Some(Item::BirchLeaves), - "minecraft:jungle_leaves" => Some(Item::JungleLeaves), - "minecraft:acacia_leaves" => Some(Item::AcaciaLeaves), - "minecraft:dark_oak_leaves" => Some(Item::DarkOakLeaves), - "minecraft:sponge" => Some(Item::Sponge), - "minecraft:wet_sponge" => Some(Item::WetSponge), - "minecraft:glass" => Some(Item::Glass), - "minecraft:lapis_ore" => Some(Item::LapisOre), - "minecraft:lapis_block" => Some(Item::LapisBlock), - "minecraft:dispenser" => Some(Item::Dispenser), - "minecraft:sandstone" => Some(Item::Sandstone), - "minecraft:chiseled_sandstone" => Some(Item::ChiseledSandstone), - "minecraft:cut_sandstone" => Some(Item::CutSandstone), - "minecraft:note_block" => Some(Item::NoteBlock), - "minecraft:powered_rail" => Some(Item::PoweredRail), - "minecraft:detector_rail" => Some(Item::DetectorRail), - "minecraft:sticky_piston" => Some(Item::StickyPiston), - "minecraft:cobweb" => Some(Item::Cobweb), - "minecraft:grass" => Some(Item::Grass), - "minecraft:fern" => Some(Item::Fern), - "minecraft:dead_bush" => Some(Item::DeadBush), - "minecraft:seagrass" => Some(Item::Seagrass), - "minecraft:sea_pickle" => Some(Item::SeaPickle), - "minecraft:piston" => Some(Item::Piston), - "minecraft:white_wool" => Some(Item::WhiteWool), - "minecraft:orange_wool" => Some(Item::OrangeWool), - "minecraft:magenta_wool" => Some(Item::MagentaWool), - "minecraft:light_blue_wool" => Some(Item::LightBlueWool), - "minecraft:yellow_wool" => Some(Item::YellowWool), - "minecraft:lime_wool" => Some(Item::LimeWool), - "minecraft:pink_wool" => Some(Item::PinkWool), - "minecraft:gray_wool" => Some(Item::GrayWool), - "minecraft:light_gray_wool" => Some(Item::LightGrayWool), - "minecraft:cyan_wool" => Some(Item::CyanWool), - "minecraft:purple_wool" => Some(Item::PurpleWool), - "minecraft:blue_wool" => Some(Item::BlueWool), - "minecraft:brown_wool" => Some(Item::BrownWool), - "minecraft:green_wool" => Some(Item::GreenWool), - "minecraft:red_wool" => Some(Item::RedWool), - "minecraft:black_wool" => Some(Item::BlackWool), - "minecraft:dandelion" => Some(Item::Dandelion), - "minecraft:poppy" => Some(Item::Poppy), - "minecraft:blue_orchid" => Some(Item::BlueOrchid), - "minecraft:allium" => Some(Item::Allium), - "minecraft:azure_bluet" => Some(Item::AzureBluet), - "minecraft:red_tulip" => Some(Item::RedTulip), - "minecraft:orange_tulip" => Some(Item::OrangeTulip), - "minecraft:white_tulip" => Some(Item::WhiteTulip), - "minecraft:pink_tulip" => Some(Item::PinkTulip), - "minecraft:oxeye_daisy" => Some(Item::OxeyeDaisy), - "minecraft:brown_mushroom" => Some(Item::BrownMushroom), - "minecraft:red_mushroom" => Some(Item::RedMushroom), - "minecraft:gold_block" => Some(Item::GoldBlock), - "minecraft:iron_block" => Some(Item::IronBlock), - "minecraft:oak_slab" => Some(Item::OakSlab), - "minecraft:spruce_slab" => Some(Item::SpruceSlab), - "minecraft:birch_slab" => Some(Item::BirchSlab), - "minecraft:jungle_slab" => Some(Item::JungleSlab), - "minecraft:acacia_slab" => Some(Item::AcaciaSlab), - "minecraft:dark_oak_slab" => Some(Item::DarkOakSlab), - "minecraft:stone_slab" => Some(Item::StoneSlab), - "minecraft:sandstone_slab" => Some(Item::SandstoneSlab), - "minecraft:petrified_oak_slab" => Some(Item::PetrifiedOakSlab), - "minecraft:cobblestone_slab" => Some(Item::CobblestoneSlab), - "minecraft:brick_slab" => Some(Item::BrickSlab), - "minecraft:stone_brick_slab" => Some(Item::StoneBrickSlab), - "minecraft:nether_brick_slab" => Some(Item::NetherBrickSlab), - "minecraft:quartz_slab" => Some(Item::QuartzSlab), - "minecraft:red_sandstone_slab" => Some(Item::RedSandstoneSlab), - "minecraft:purpur_slab" => Some(Item::PurpurSlab), - "minecraft:prismarine_slab" => Some(Item::PrismarineSlab), - "minecraft:prismarine_brick_slab" => Some(Item::PrismarineBrickSlab), - "minecraft:dark_prismarine_slab" => Some(Item::DarkPrismarineSlab), - "minecraft:smooth_quartz" => Some(Item::SmoothQuartz), - "minecraft:smooth_red_sandstone" => Some(Item::SmoothRedSandstone), - "minecraft:smooth_sandstone" => Some(Item::SmoothSandstone), - "minecraft:smooth_stone" => Some(Item::SmoothStone), - "minecraft:bricks" => Some(Item::Bricks), - "minecraft:tnt" => Some(Item::Tnt), - "minecraft:bookshelf" => Some(Item::Bookshelf), - "minecraft:mossy_cobblestone" => Some(Item::MossyCobblestone), - "minecraft:obsidian" => Some(Item::Obsidian), - "minecraft:torch" => Some(Item::Torch), - "minecraft:end_rod" => Some(Item::EndRod), - "minecraft:chorus_plant" => Some(Item::ChorusPlant), - "minecraft:chorus_flower" => Some(Item::ChorusFlower), - "minecraft:purpur_block" => Some(Item::PurpurBlock), - "minecraft:purpur_pillar" => Some(Item::PurpurPillar), - "minecraft:purpur_stairs" => Some(Item::PurpurStairs), - "minecraft:spawner" => Some(Item::Spawner), - "minecraft:oak_stairs" => Some(Item::OakStairs), - "minecraft:chest" => Some(Item::Chest), - "minecraft:diamond_ore" => Some(Item::DiamondOre), - "minecraft:diamond_block" => Some(Item::DiamondBlock), - "minecraft:crafting_table" => Some(Item::CraftingTable), - "minecraft:farmland" => Some(Item::Farmland), - "minecraft:furnace" => Some(Item::Furnace), - "minecraft:ladder" => Some(Item::Ladder), - "minecraft:rail" => Some(Item::Rail), - "minecraft:cobblestone_stairs" => Some(Item::CobblestoneStairs), - "minecraft:lever" => Some(Item::Lever), - "minecraft:stone_pressure_plate" => Some(Item::StonePressurePlate), - "minecraft:oak_pressure_plate" => Some(Item::OakPressurePlate), - "minecraft:spruce_pressure_plate" => Some(Item::SprucePressurePlate), - "minecraft:birch_pressure_plate" => Some(Item::BirchPressurePlate), - "minecraft:jungle_pressure_plate" => Some(Item::JunglePressurePlate), - "minecraft:acacia_pressure_plate" => Some(Item::AcaciaPressurePlate), - "minecraft:dark_oak_pressure_plate" => Some(Item::DarkOakPressurePlate), - "minecraft:redstone_ore" => Some(Item::RedstoneOre), - "minecraft:redstone_torch" => Some(Item::RedstoneTorch), - "minecraft:stone_button" => Some(Item::StoneButton), - "minecraft:snow" => Some(Item::Snow), - "minecraft:ice" => Some(Item::Ice), - "minecraft:snow_block" => Some(Item::SnowBlock), - "minecraft:cactus" => Some(Item::Cactus), - "minecraft:clay" => Some(Item::Clay), - "minecraft:jukebox" => Some(Item::Jukebox), - "minecraft:oak_fence" => Some(Item::OakFence), - "minecraft:spruce_fence" => Some(Item::SpruceFence), - "minecraft:birch_fence" => Some(Item::BirchFence), - "minecraft:jungle_fence" => Some(Item::JungleFence), - "minecraft:acacia_fence" => Some(Item::AcaciaFence), - "minecraft:dark_oak_fence" => Some(Item::DarkOakFence), - "minecraft:pumpkin" => Some(Item::Pumpkin), - "minecraft:carved_pumpkin" => Some(Item::CarvedPumpkin), - "minecraft:netherrack" => Some(Item::Netherrack), - "minecraft:soul_sand" => Some(Item::SoulSand), - "minecraft:glowstone" => Some(Item::Glowstone), - "minecraft:jack_o_lantern" => Some(Item::JackOLantern), - "minecraft:oak_trapdoor" => Some(Item::OakTrapdoor), - "minecraft:spruce_trapdoor" => Some(Item::SpruceTrapdoor), - "minecraft:birch_trapdoor" => Some(Item::BirchTrapdoor), - "minecraft:jungle_trapdoor" => Some(Item::JungleTrapdoor), - "minecraft:acacia_trapdoor" => Some(Item::AcaciaTrapdoor), - "minecraft:dark_oak_trapdoor" => Some(Item::DarkOakTrapdoor), - "minecraft:infested_stone" => Some(Item::InfestedStone), - "minecraft:infested_cobblestone" => Some(Item::InfestedCobblestone), - "minecraft:infested_stone_bricks" => Some(Item::InfestedStoneBricks), - "minecraft:infested_mossy_stone_bricks" => Some(Item::InfestedMossyStoneBricks), - "minecraft:infested_cracked_stone_bricks" => Some(Item::InfestedCrackedStoneBricks), - "minecraft:infested_chiseled_stone_bricks" => Some(Item::InfestedChiseledStoneBricks), - "minecraft:stone_bricks" => Some(Item::StoneBricks), - "minecraft:mossy_stone_bricks" => Some(Item::MossyStoneBricks), - "minecraft:cracked_stone_bricks" => Some(Item::CrackedStoneBricks), - "minecraft:chiseled_stone_bricks" => Some(Item::ChiseledStoneBricks), - "minecraft:brown_mushroom_block" => Some(Item::BrownMushroomBlock), - "minecraft:red_mushroom_block" => Some(Item::RedMushroomBlock), - "minecraft:mushroom_stem" => Some(Item::MushroomStem), - "minecraft:iron_bars" => Some(Item::IronBars), - "minecraft:glass_pane" => Some(Item::GlassPane), - "minecraft:melon" => Some(Item::Melon), - "minecraft:vine" => Some(Item::Vine), - "minecraft:oak_fence_gate" => Some(Item::OakFenceGate), - "minecraft:spruce_fence_gate" => Some(Item::SpruceFenceGate), - "minecraft:birch_fence_gate" => Some(Item::BirchFenceGate), - "minecraft:jungle_fence_gate" => Some(Item::JungleFenceGate), - "minecraft:acacia_fence_gate" => Some(Item::AcaciaFenceGate), - "minecraft:dark_oak_fence_gate" => Some(Item::DarkOakFenceGate), - "minecraft:brick_stairs" => Some(Item::BrickStairs), - "minecraft:stone_brick_stairs" => Some(Item::StoneBrickStairs), - "minecraft:mycelium" => Some(Item::Mycelium), - "minecraft:lily_pad" => Some(Item::LilyPad), - "minecraft:nether_bricks" => Some(Item::NetherBricks), - "minecraft:nether_brick_fence" => Some(Item::NetherBrickFence), - "minecraft:nether_brick_stairs" => Some(Item::NetherBrickStairs), - "minecraft:enchanting_table" => Some(Item::EnchantingTable), - "minecraft:end_portal_frame" => Some(Item::EndPortalFrame), - "minecraft:end_stone" => Some(Item::EndStone), - "minecraft:end_stone_bricks" => Some(Item::EndStoneBricks), - "minecraft:dragon_egg" => Some(Item::DragonEgg), - "minecraft:redstone_lamp" => Some(Item::RedstoneLamp), - "minecraft:sandstone_stairs" => Some(Item::SandstoneStairs), - "minecraft:emerald_ore" => Some(Item::EmeraldOre), - "minecraft:ender_chest" => Some(Item::EnderChest), - "minecraft:tripwire_hook" => Some(Item::TripwireHook), - "minecraft:emerald_block" => Some(Item::EmeraldBlock), - "minecraft:spruce_stairs" => Some(Item::SpruceStairs), - "minecraft:birch_stairs" => Some(Item::BirchStairs), - "minecraft:jungle_stairs" => Some(Item::JungleStairs), - "minecraft:command_block" => Some(Item::CommandBlock), - "minecraft:beacon" => Some(Item::Beacon), - "minecraft:cobblestone_wall" => Some(Item::CobblestoneWall), - "minecraft:mossy_cobblestone_wall" => Some(Item::MossyCobblestoneWall), - "minecraft:oak_button" => Some(Item::OakButton), - "minecraft:spruce_button" => Some(Item::SpruceButton), - "minecraft:birch_button" => Some(Item::BirchButton), - "minecraft:jungle_button" => Some(Item::JungleButton), - "minecraft:acacia_button" => Some(Item::AcaciaButton), - "minecraft:dark_oak_button" => Some(Item::DarkOakButton), - "minecraft:anvil" => Some(Item::Anvil), - "minecraft:chipped_anvil" => Some(Item::ChippedAnvil), - "minecraft:damaged_anvil" => Some(Item::DamagedAnvil), - "minecraft:trapped_chest" => Some(Item::TrappedChest), - "minecraft:light_weighted_pressure_plate" => Some(Item::LightWeightedPressurePlate), - "minecraft:heavy_weighted_pressure_plate" => Some(Item::HeavyWeightedPressurePlate), - "minecraft:daylight_detector" => Some(Item::DaylightDetector), - "minecraft:redstone_block" => Some(Item::RedstoneBlock), - "minecraft:nether_quartz_ore" => Some(Item::NetherQuartzOre), - "minecraft:hopper" => Some(Item::Hopper), - "minecraft:chiseled_quartz_block" => Some(Item::ChiseledQuartzBlock), - "minecraft:quartz_block" => Some(Item::QuartzBlock), - "minecraft:quartz_pillar" => Some(Item::QuartzPillar), - "minecraft:quartz_stairs" => Some(Item::QuartzStairs), - "minecraft:activator_rail" => Some(Item::ActivatorRail), - "minecraft:dropper" => Some(Item::Dropper), - "minecraft:white_terracotta" => Some(Item::WhiteTerracotta), - "minecraft:orange_terracotta" => Some(Item::OrangeTerracotta), - "minecraft:magenta_terracotta" => Some(Item::MagentaTerracotta), - "minecraft:light_blue_terracotta" => Some(Item::LightBlueTerracotta), - "minecraft:yellow_terracotta" => Some(Item::YellowTerracotta), - "minecraft:lime_terracotta" => Some(Item::LimeTerracotta), - "minecraft:pink_terracotta" => Some(Item::PinkTerracotta), - "minecraft:gray_terracotta" => Some(Item::GrayTerracotta), - "minecraft:light_gray_terracotta" => Some(Item::LightGrayTerracotta), - "minecraft:cyan_terracotta" => Some(Item::CyanTerracotta), - "minecraft:purple_terracotta" => Some(Item::PurpleTerracotta), - "minecraft:blue_terracotta" => Some(Item::BlueTerracotta), - "minecraft:brown_terracotta" => Some(Item::BrownTerracotta), - "minecraft:green_terracotta" => Some(Item::GreenTerracotta), - "minecraft:red_terracotta" => Some(Item::RedTerracotta), - "minecraft:black_terracotta" => Some(Item::BlackTerracotta), - "minecraft:barrier" => Some(Item::Barrier), - "minecraft:iron_trapdoor" => Some(Item::IronTrapdoor), - "minecraft:hay_block" => Some(Item::HayBlock), - "minecraft:white_carpet" => Some(Item::WhiteCarpet), - "minecraft:orange_carpet" => Some(Item::OrangeCarpet), - "minecraft:magenta_carpet" => Some(Item::MagentaCarpet), - "minecraft:light_blue_carpet" => Some(Item::LightBlueCarpet), - "minecraft:yellow_carpet" => Some(Item::YellowCarpet), - "minecraft:lime_carpet" => Some(Item::LimeCarpet), - "minecraft:pink_carpet" => Some(Item::PinkCarpet), - "minecraft:gray_carpet" => Some(Item::GrayCarpet), - "minecraft:light_gray_carpet" => Some(Item::LightGrayCarpet), - "minecraft:cyan_carpet" => Some(Item::CyanCarpet), - "minecraft:purple_carpet" => Some(Item::PurpleCarpet), - "minecraft:blue_carpet" => Some(Item::BlueCarpet), - "minecraft:brown_carpet" => Some(Item::BrownCarpet), - "minecraft:green_carpet" => Some(Item::GreenCarpet), - "minecraft:red_carpet" => Some(Item::RedCarpet), - "minecraft:black_carpet" => Some(Item::BlackCarpet), - "minecraft:terracotta" => Some(Item::Terracotta), - "minecraft:coal_block" => Some(Item::CoalBlock), - "minecraft:packed_ice" => Some(Item::PackedIce), - "minecraft:acacia_stairs" => Some(Item::AcaciaStairs), - "minecraft:dark_oak_stairs" => Some(Item::DarkOakStairs), - "minecraft:slime_block" => Some(Item::SlimeBlock), - "minecraft:grass_path" => Some(Item::GrassPath), - "minecraft:sunflower" => Some(Item::Sunflower), - "minecraft:lilac" => Some(Item::Lilac), - "minecraft:rose_bush" => Some(Item::RoseBush), - "minecraft:peony" => Some(Item::Peony), - "minecraft:tall_grass" => Some(Item::TallGrass), - "minecraft:large_fern" => Some(Item::LargeFern), - "minecraft:white_stained_glass" => Some(Item::WhiteStainedGlass), - "minecraft:orange_stained_glass" => Some(Item::OrangeStainedGlass), - "minecraft:magenta_stained_glass" => Some(Item::MagentaStainedGlass), - "minecraft:light_blue_stained_glass" => Some(Item::LightBlueStainedGlass), - "minecraft:yellow_stained_glass" => Some(Item::YellowStainedGlass), - "minecraft:lime_stained_glass" => Some(Item::LimeStainedGlass), - "minecraft:pink_stained_glass" => Some(Item::PinkStainedGlass), - "minecraft:gray_stained_glass" => Some(Item::GrayStainedGlass), - "minecraft:light_gray_stained_glass" => Some(Item::LightGrayStainedGlass), - "minecraft:cyan_stained_glass" => Some(Item::CyanStainedGlass), - "minecraft:purple_stained_glass" => Some(Item::PurpleStainedGlass), - "minecraft:blue_stained_glass" => Some(Item::BlueStainedGlass), - "minecraft:brown_stained_glass" => Some(Item::BrownStainedGlass), - "minecraft:green_stained_glass" => Some(Item::GreenStainedGlass), - "minecraft:red_stained_glass" => Some(Item::RedStainedGlass), - "minecraft:black_stained_glass" => Some(Item::BlackStainedGlass), - "minecraft:white_stained_glass_pane" => Some(Item::WhiteStainedGlassPane), - "minecraft:orange_stained_glass_pane" => Some(Item::OrangeStainedGlassPane), - "minecraft:magenta_stained_glass_pane" => Some(Item::MagentaStainedGlassPane), - "minecraft:light_blue_stained_glass_pane" => Some(Item::LightBlueStainedGlassPane), - "minecraft:yellow_stained_glass_pane" => Some(Item::YellowStainedGlassPane), - "minecraft:lime_stained_glass_pane" => Some(Item::LimeStainedGlassPane), - "minecraft:pink_stained_glass_pane" => Some(Item::PinkStainedGlassPane), - "minecraft:gray_stained_glass_pane" => Some(Item::GrayStainedGlassPane), - "minecraft:light_gray_stained_glass_pane" => Some(Item::LightGrayStainedGlassPane), - "minecraft:cyan_stained_glass_pane" => Some(Item::CyanStainedGlassPane), - "minecraft:purple_stained_glass_pane" => Some(Item::PurpleStainedGlassPane), - "minecraft:blue_stained_glass_pane" => Some(Item::BlueStainedGlassPane), - "minecraft:brown_stained_glass_pane" => Some(Item::BrownStainedGlassPane), - "minecraft:green_stained_glass_pane" => Some(Item::GreenStainedGlassPane), - "minecraft:red_stained_glass_pane" => Some(Item::RedStainedGlassPane), - "minecraft:black_stained_glass_pane" => Some(Item::BlackStainedGlassPane), - "minecraft:prismarine" => Some(Item::Prismarine), - "minecraft:prismarine_bricks" => Some(Item::PrismarineBricks), - "minecraft:dark_prismarine" => Some(Item::DarkPrismarine), - "minecraft:prismarine_stairs" => Some(Item::PrismarineStairs), - "minecraft:prismarine_brick_stairs" => Some(Item::PrismarineBrickStairs), - "minecraft:dark_prismarine_stairs" => Some(Item::DarkPrismarineStairs), - "minecraft:sea_lantern" => Some(Item::SeaLantern), - "minecraft:red_sandstone" => Some(Item::RedSandstone), - "minecraft:chiseled_red_sandstone" => Some(Item::ChiseledRedSandstone), - "minecraft:cut_red_sandstone" => Some(Item::CutRedSandstone), - "minecraft:red_sandstone_stairs" => Some(Item::RedSandstoneStairs), - "minecraft:repeating_command_block" => Some(Item::RepeatingCommandBlock), - "minecraft:chain_command_block" => Some(Item::ChainCommandBlock), - "minecraft:magma_block" => Some(Item::MagmaBlock), - "minecraft:nether_wart_block" => Some(Item::NetherWartBlock), - "minecraft:red_nether_bricks" => Some(Item::RedNetherBricks), - "minecraft:bone_block" => Some(Item::BoneBlock), - "minecraft:structure_void" => Some(Item::StructureVoid), - "minecraft:observer" => Some(Item::Observer), - "minecraft:shulker_box" => Some(Item::ShulkerBox), - "minecraft:white_shulker_box" => Some(Item::WhiteShulkerBox), - "minecraft:orange_shulker_box" => Some(Item::OrangeShulkerBox), - "minecraft:magenta_shulker_box" => Some(Item::MagentaShulkerBox), - "minecraft:light_blue_shulker_box" => Some(Item::LightBlueShulkerBox), - "minecraft:yellow_shulker_box" => Some(Item::YellowShulkerBox), - "minecraft:lime_shulker_box" => Some(Item::LimeShulkerBox), - "minecraft:pink_shulker_box" => Some(Item::PinkShulkerBox), - "minecraft:gray_shulker_box" => Some(Item::GrayShulkerBox), - "minecraft:light_gray_shulker_box" => Some(Item::LightGrayShulkerBox), - "minecraft:cyan_shulker_box" => Some(Item::CyanShulkerBox), - "minecraft:purple_shulker_box" => Some(Item::PurpleShulkerBox), - "minecraft:blue_shulker_box" => Some(Item::BlueShulkerBox), - "minecraft:brown_shulker_box" => Some(Item::BrownShulkerBox), - "minecraft:green_shulker_box" => Some(Item::GreenShulkerBox), - "minecraft:red_shulker_box" => Some(Item::RedShulkerBox), - "minecraft:black_shulker_box" => Some(Item::BlackShulkerBox), - "minecraft:white_glazed_terracotta" => Some(Item::WhiteGlazedTerracotta), - "minecraft:orange_glazed_terracotta" => Some(Item::OrangeGlazedTerracotta), - "minecraft:magenta_glazed_terracotta" => Some(Item::MagentaGlazedTerracotta), - "minecraft:light_blue_glazed_terracotta" => Some(Item::LightBlueGlazedTerracotta), - "minecraft:yellow_glazed_terracotta" => Some(Item::YellowGlazedTerracotta), - "minecraft:lime_glazed_terracotta" => Some(Item::LimeGlazedTerracotta), - "minecraft:pink_glazed_terracotta" => Some(Item::PinkGlazedTerracotta), - "minecraft:gray_glazed_terracotta" => Some(Item::GrayGlazedTerracotta), - "minecraft:light_gray_glazed_terracotta" => Some(Item::LightGrayGlazedTerracotta), - "minecraft:cyan_glazed_terracotta" => Some(Item::CyanGlazedTerracotta), - "minecraft:purple_glazed_terracotta" => Some(Item::PurpleGlazedTerracotta), - "minecraft:blue_glazed_terracotta" => Some(Item::BlueGlazedTerracotta), - "minecraft:brown_glazed_terracotta" => Some(Item::BrownGlazedTerracotta), - "minecraft:green_glazed_terracotta" => Some(Item::GreenGlazedTerracotta), - "minecraft:red_glazed_terracotta" => Some(Item::RedGlazedTerracotta), - "minecraft:black_glazed_terracotta" => Some(Item::BlackGlazedTerracotta), - "minecraft:white_concrete" => Some(Item::WhiteConcrete), - "minecraft:orange_concrete" => Some(Item::OrangeConcrete), - "minecraft:magenta_concrete" => Some(Item::MagentaConcrete), - "minecraft:light_blue_concrete" => Some(Item::LightBlueConcrete), - "minecraft:yellow_concrete" => Some(Item::YellowConcrete), - "minecraft:lime_concrete" => Some(Item::LimeConcrete), - "minecraft:pink_concrete" => Some(Item::PinkConcrete), - "minecraft:gray_concrete" => Some(Item::GrayConcrete), - "minecraft:light_gray_concrete" => Some(Item::LightGrayConcrete), - "minecraft:cyan_concrete" => Some(Item::CyanConcrete), - "minecraft:purple_concrete" => Some(Item::PurpleConcrete), - "minecraft:blue_concrete" => Some(Item::BlueConcrete), - "minecraft:brown_concrete" => Some(Item::BrownConcrete), - "minecraft:green_concrete" => Some(Item::GreenConcrete), - "minecraft:red_concrete" => Some(Item::RedConcrete), - "minecraft:black_concrete" => Some(Item::BlackConcrete), - "minecraft:white_concrete_powder" => Some(Item::WhiteConcretePowder), - "minecraft:orange_concrete_powder" => Some(Item::OrangeConcretePowder), - "minecraft:magenta_concrete_powder" => Some(Item::MagentaConcretePowder), - "minecraft:light_blue_concrete_powder" => Some(Item::LightBlueConcretePowder), - "minecraft:yellow_concrete_powder" => Some(Item::YellowConcretePowder), - "minecraft:lime_concrete_powder" => Some(Item::LimeConcretePowder), - "minecraft:pink_concrete_powder" => Some(Item::PinkConcretePowder), - "minecraft:gray_concrete_powder" => Some(Item::GrayConcretePowder), - "minecraft:light_gray_concrete_powder" => Some(Item::LightGrayConcretePowder), - "minecraft:cyan_concrete_powder" => Some(Item::CyanConcretePowder), - "minecraft:purple_concrete_powder" => Some(Item::PurpleConcretePowder), - "minecraft:blue_concrete_powder" => Some(Item::BlueConcretePowder), - "minecraft:brown_concrete_powder" => Some(Item::BrownConcretePowder), - "minecraft:green_concrete_powder" => Some(Item::GreenConcretePowder), - "minecraft:red_concrete_powder" => Some(Item::RedConcretePowder), - "minecraft:black_concrete_powder" => Some(Item::BlackConcretePowder), - "minecraft:turtle_egg" => Some(Item::TurtleEgg), - "minecraft:dead_tube_coral_block" => Some(Item::DeadTubeCoralBlock), - "minecraft:dead_brain_coral_block" => Some(Item::DeadBrainCoralBlock), - "minecraft:dead_bubble_coral_block" => Some(Item::DeadBubbleCoralBlock), - "minecraft:dead_fire_coral_block" => Some(Item::DeadFireCoralBlock), - "minecraft:dead_horn_coral_block" => Some(Item::DeadHornCoralBlock), - "minecraft:tube_coral_block" => Some(Item::TubeCoralBlock), - "minecraft:brain_coral_block" => Some(Item::BrainCoralBlock), - "minecraft:bubble_coral_block" => Some(Item::BubbleCoralBlock), - "minecraft:fire_coral_block" => Some(Item::FireCoralBlock), - "minecraft:horn_coral_block" => Some(Item::HornCoralBlock), - "minecraft:tube_coral" => Some(Item::TubeCoral), - "minecraft:brain_coral" => Some(Item::BrainCoral), - "minecraft:bubble_coral" => Some(Item::BubbleCoral), - "minecraft:fire_coral" => Some(Item::FireCoral), - "minecraft:horn_coral" => Some(Item::HornCoral), - "minecraft:dead_brain_coral" => Some(Item::DeadBrainCoral), - "minecraft:dead_bubble_coral" => Some(Item::DeadBubbleCoral), - "minecraft:dead_fire_coral" => Some(Item::DeadFireCoral), - "minecraft:dead_horn_coral" => Some(Item::DeadHornCoral), - "minecraft:dead_tube_coral" => Some(Item::DeadTubeCoral), - "minecraft:tube_coral_fan" => Some(Item::TubeCoralFan), - "minecraft:brain_coral_fan" => Some(Item::BrainCoralFan), - "minecraft:bubble_coral_fan" => Some(Item::BubbleCoralFan), - "minecraft:fire_coral_fan" => Some(Item::FireCoralFan), - "minecraft:horn_coral_fan" => Some(Item::HornCoralFan), - "minecraft:dead_tube_coral_fan" => Some(Item::DeadTubeCoralFan), - "minecraft:dead_brain_coral_fan" => Some(Item::DeadBrainCoralFan), - "minecraft:dead_bubble_coral_fan" => Some(Item::DeadBubbleCoralFan), - "minecraft:dead_fire_coral_fan" => Some(Item::DeadFireCoralFan), - "minecraft:dead_horn_coral_fan" => Some(Item::DeadHornCoralFan), - "minecraft:blue_ice" => Some(Item::BlueIce), - "minecraft:conduit" => Some(Item::Conduit), - "minecraft:iron_door" => Some(Item::IronDoor), - "minecraft:oak_door" => Some(Item::OakDoor), - "minecraft:spruce_door" => Some(Item::SpruceDoor), - "minecraft:birch_door" => Some(Item::BirchDoor), - "minecraft:jungle_door" => Some(Item::JungleDoor), - "minecraft:acacia_door" => Some(Item::AcaciaDoor), - "minecraft:dark_oak_door" => Some(Item::DarkOakDoor), - "minecraft:repeater" => Some(Item::Repeater), - "minecraft:comparator" => Some(Item::Comparator), - "minecraft:structure_block" => Some(Item::StructureBlock), - "minecraft:turtle_helmet" => Some(Item::TurtleHelmet), - "minecraft:scute" => Some(Item::Scute), - "minecraft:iron_shovel" => Some(Item::IronShovel), - "minecraft:iron_pickaxe" => Some(Item::IronPickaxe), - "minecraft:iron_axe" => Some(Item::IronAxe), - "minecraft:flint_and_steel" => Some(Item::FlintAndSteel), - "minecraft:apple" => Some(Item::Apple), - "minecraft:bow" => Some(Item::Bow), - "minecraft:arrow" => Some(Item::Arrow), - "minecraft:coal" => Some(Item::Coal), - "minecraft:charcoal" => Some(Item::Charcoal), - "minecraft:diamond" => Some(Item::Diamond), - "minecraft:iron_ingot" => Some(Item::IronIngot), - "minecraft:gold_ingot" => Some(Item::GoldIngot), - "minecraft:iron_sword" => Some(Item::IronSword), - "minecraft:wooden_sword" => Some(Item::WoodenSword), - "minecraft:wooden_shovel" => Some(Item::WoodenShovel), - "minecraft:wooden_pickaxe" => Some(Item::WoodenPickaxe), - "minecraft:wooden_axe" => Some(Item::WoodenAxe), - "minecraft:stone_sword" => Some(Item::StoneSword), - "minecraft:stone_shovel" => Some(Item::StoneShovel), - "minecraft:stone_pickaxe" => Some(Item::StonePickaxe), - "minecraft:stone_axe" => Some(Item::StoneAxe), - "minecraft:diamond_sword" => Some(Item::DiamondSword), - "minecraft:diamond_shovel" => Some(Item::DiamondShovel), - "minecraft:diamond_pickaxe" => Some(Item::DiamondPickaxe), - "minecraft:diamond_axe" => Some(Item::DiamondAxe), - "minecraft:stick" => Some(Item::Stick), - "minecraft:bowl" => Some(Item::Bowl), - "minecraft:mushroom_stew" => Some(Item::MushroomStew), - "minecraft:golden_sword" => Some(Item::GoldenSword), - "minecraft:golden_shovel" => Some(Item::GoldenShovel), - "minecraft:golden_pickaxe" => Some(Item::GoldenPickaxe), - "minecraft:golden_axe" => Some(Item::GoldenAxe), - "minecraft:string" => Some(Item::String), - "minecraft:feather" => Some(Item::Feather), - "minecraft:gunpowder" => Some(Item::Gunpowder), - "minecraft:wooden_hoe" => Some(Item::WoodenHoe), - "minecraft:stone_hoe" => Some(Item::StoneHoe), - "minecraft:iron_hoe" => Some(Item::IronHoe), - "minecraft:diamond_hoe" => Some(Item::DiamondHoe), - "minecraft:golden_hoe" => Some(Item::GoldenHoe), - "minecraft:wheat_seeds" => Some(Item::WheatSeeds), - "minecraft:wheat" => Some(Item::Wheat), - "minecraft:bread" => Some(Item::Bread), - "minecraft:leather_helmet" => Some(Item::LeatherHelmet), - "minecraft:leather_chestplate" => Some(Item::LeatherChestplate), - "minecraft:leather_leggings" => Some(Item::LeatherLeggings), - "minecraft:leather_boots" => Some(Item::LeatherBoots), - "minecraft:chainmail_helmet" => Some(Item::ChainmailHelmet), - "minecraft:chainmail_chestplate" => Some(Item::ChainmailChestplate), - "minecraft:chainmail_leggings" => Some(Item::ChainmailLeggings), - "minecraft:chainmail_boots" => Some(Item::ChainmailBoots), - "minecraft:iron_helmet" => Some(Item::IronHelmet), - "minecraft:iron_chestplate" => Some(Item::IronChestplate), - "minecraft:iron_leggings" => Some(Item::IronLeggings), - "minecraft:iron_boots" => Some(Item::IronBoots), - "minecraft:diamond_helmet" => Some(Item::DiamondHelmet), - "minecraft:diamond_chestplate" => Some(Item::DiamondChestplate), - "minecraft:diamond_leggings" => Some(Item::DiamondLeggings), - "minecraft:diamond_boots" => Some(Item::DiamondBoots), - "minecraft:golden_helmet" => Some(Item::GoldenHelmet), - "minecraft:golden_chestplate" => Some(Item::GoldenChestplate), - "minecraft:golden_leggings" => Some(Item::GoldenLeggings), - "minecraft:golden_boots" => Some(Item::GoldenBoots), - "minecraft:flint" => Some(Item::Flint), - "minecraft:porkchop" => Some(Item::Porkchop), - "minecraft:cooked_porkchop" => Some(Item::CookedPorkchop), - "minecraft:painting" => Some(Item::Painting), - "minecraft:golden_apple" => Some(Item::GoldenApple), - "minecraft:enchanted_golden_apple" => Some(Item::EnchantedGoldenApple), - "minecraft:sign" => Some(Item::Sign), - "minecraft:bucket" => Some(Item::Bucket), - "minecraft:water_bucket" => Some(Item::WaterBucket), - "minecraft:lava_bucket" => Some(Item::LavaBucket), - "minecraft:minecart" => Some(Item::Minecart), - "minecraft:saddle" => Some(Item::Saddle), - "minecraft:redstone" => Some(Item::Redstone), - "minecraft:snowball" => Some(Item::Snowball), - "minecraft:oak_boat" => Some(Item::OakBoat), - "minecraft:leather" => Some(Item::Leather), - "minecraft:milk_bucket" => Some(Item::MilkBucket), - "minecraft:pufferfish_bucket" => Some(Item::PufferfishBucket), - "minecraft:salmon_bucket" => Some(Item::SalmonBucket), - "minecraft:cod_bucket" => Some(Item::CodBucket), - "minecraft:tropical_fish_bucket" => Some(Item::TropicalFishBucket), - "minecraft:brick" => Some(Item::Brick), - "minecraft:clay_ball" => Some(Item::ClayBall), - "minecraft:sugar_cane" => Some(Item::SugarCane), - "minecraft:kelp" => Some(Item::Kelp), - "minecraft:dried_kelp_block" => Some(Item::DriedKelpBlock), - "minecraft:paper" => Some(Item::Paper), - "minecraft:book" => Some(Item::Book), - "minecraft:slime_ball" => Some(Item::SlimeBall), - "minecraft:chest_minecart" => Some(Item::ChestMinecart), - "minecraft:furnace_minecart" => Some(Item::FurnaceMinecart), - "minecraft:egg" => Some(Item::Egg), - "minecraft:compass" => Some(Item::Compass), - "minecraft:fishing_rod" => Some(Item::FishingRod), - "minecraft:clock" => Some(Item::Clock), - "minecraft:glowstone_dust" => Some(Item::GlowstoneDust), - "minecraft:cod" => Some(Item::Cod), - "minecraft:salmon" => Some(Item::Salmon), - "minecraft:tropical_fish" => Some(Item::TropicalFish), - "minecraft:pufferfish" => Some(Item::Pufferfish), - "minecraft:cooked_cod" => Some(Item::CookedCod), - "minecraft:cooked_salmon" => Some(Item::CookedSalmon), - "minecraft:ink_sac" => Some(Item::InkSac), - "minecraft:rose_red" => Some(Item::RoseRed), - "minecraft:cactus_green" => Some(Item::CactusGreen), - "minecraft:cocoa_beans" => Some(Item::CocoaBeans), - "minecraft:lapis_lazuli" => Some(Item::LapisLazuli), - "minecraft:purple_dye" => Some(Item::PurpleDye), - "minecraft:cyan_dye" => Some(Item::CyanDye), - "minecraft:light_gray_dye" => Some(Item::LightGrayDye), - "minecraft:gray_dye" => Some(Item::GrayDye), - "minecraft:pink_dye" => Some(Item::PinkDye), - "minecraft:lime_dye" => Some(Item::LimeDye), - "minecraft:dandelion_yellow" => Some(Item::DandelionYellow), - "minecraft:light_blue_dye" => Some(Item::LightBlueDye), - "minecraft:magenta_dye" => Some(Item::MagentaDye), - "minecraft:orange_dye" => Some(Item::OrangeDye), - "minecraft:bone_meal" => Some(Item::BoneMeal), - "minecraft:bone" => Some(Item::Bone), - "minecraft:sugar" => Some(Item::Sugar), - "minecraft:cake" => Some(Item::Cake), - "minecraft:white_bed" => Some(Item::WhiteBed), - "minecraft:orange_bed" => Some(Item::OrangeBed), - "minecraft:magenta_bed" => Some(Item::MagentaBed), - "minecraft:light_blue_bed" => Some(Item::LightBlueBed), - "minecraft:yellow_bed" => Some(Item::YellowBed), - "minecraft:lime_bed" => Some(Item::LimeBed), - "minecraft:pink_bed" => Some(Item::PinkBed), - "minecraft:gray_bed" => Some(Item::GrayBed), - "minecraft:light_gray_bed" => Some(Item::LightGrayBed), - "minecraft:cyan_bed" => Some(Item::CyanBed), - "minecraft:purple_bed" => Some(Item::PurpleBed), - "minecraft:blue_bed" => Some(Item::BlueBed), - "minecraft:brown_bed" => Some(Item::BrownBed), - "minecraft:green_bed" => Some(Item::GreenBed), - "minecraft:red_bed" => Some(Item::RedBed), - "minecraft:black_bed" => Some(Item::BlackBed), - "minecraft:cookie" => Some(Item::Cookie), - "minecraft:filled_map" => Some(Item::FilledMap), - "minecraft:shears" => Some(Item::Shears), - "minecraft:melon_slice" => Some(Item::MelonSlice), - "minecraft:dried_kelp" => Some(Item::DriedKelp), - "minecraft:pumpkin_seeds" => Some(Item::PumpkinSeeds), - "minecraft:melon_seeds" => Some(Item::MelonSeeds), - "minecraft:beef" => Some(Item::Beef), - "minecraft:cooked_beef" => Some(Item::CookedBeef), - "minecraft:chicken" => Some(Item::Chicken), - "minecraft:cooked_chicken" => Some(Item::CookedChicken), - "minecraft:rotten_flesh" => Some(Item::RottenFlesh), - "minecraft:ender_pearl" => Some(Item::EnderPearl), - "minecraft:blaze_rod" => Some(Item::BlazeRod), - "minecraft:ghast_tear" => Some(Item::GhastTear), - "minecraft:gold_nugget" => Some(Item::GoldNugget), - "minecraft:nether_wart" => Some(Item::NetherWart), - "minecraft:potion" => Some(Item::Potion), - "minecraft:glass_bottle" => Some(Item::GlassBottle), - "minecraft:spider_eye" => Some(Item::SpiderEye), - "minecraft:fermented_spider_eye" => Some(Item::FermentedSpiderEye), - "minecraft:blaze_powder" => Some(Item::BlazePowder), - "minecraft:magma_cream" => Some(Item::MagmaCream), - "minecraft:brewing_stand" => Some(Item::BrewingStand), - "minecraft:cauldron" => Some(Item::Cauldron), - "minecraft:ender_eye" => Some(Item::EnderEye), - "minecraft:glistering_melon_slice" => Some(Item::GlisteringMelonSlice), - "minecraft:bat_spawn_egg" => Some(Item::BatSpawnEgg), - "minecraft:blaze_spawn_egg" => Some(Item::BlazeSpawnEgg), - "minecraft:cave_spider_spawn_egg" => Some(Item::CaveSpiderSpawnEgg), - "minecraft:chicken_spawn_egg" => Some(Item::ChickenSpawnEgg), - "minecraft:cod_spawn_egg" => Some(Item::CodSpawnEgg), - "minecraft:cow_spawn_egg" => Some(Item::CowSpawnEgg), - "minecraft:creeper_spawn_egg" => Some(Item::CreeperSpawnEgg), - "minecraft:dolphin_spawn_egg" => Some(Item::DolphinSpawnEgg), - "minecraft:donkey_spawn_egg" => Some(Item::DonkeySpawnEgg), - "minecraft:drowned_spawn_egg" => Some(Item::DrownedSpawnEgg), - "minecraft:elder_guardian_spawn_egg" => Some(Item::ElderGuardianSpawnEgg), - "minecraft:enderman_spawn_egg" => Some(Item::EndermanSpawnEgg), - "minecraft:endermite_spawn_egg" => Some(Item::EndermiteSpawnEgg), - "minecraft:evoker_spawn_egg" => Some(Item::EvokerSpawnEgg), - "minecraft:ghast_spawn_egg" => Some(Item::GhastSpawnEgg), - "minecraft:guardian_spawn_egg" => Some(Item::GuardianSpawnEgg), - "minecraft:horse_spawn_egg" => Some(Item::HorseSpawnEgg), - "minecraft:husk_spawn_egg" => Some(Item::HuskSpawnEgg), - "minecraft:llama_spawn_egg" => Some(Item::LlamaSpawnEgg), - "minecraft:magma_cube_spawn_egg" => Some(Item::MagmaCubeSpawnEgg), - "minecraft:mooshroom_spawn_egg" => Some(Item::MooshroomSpawnEgg), - "minecraft:mule_spawn_egg" => Some(Item::MuleSpawnEgg), - "minecraft:ocelot_spawn_egg" => Some(Item::OcelotSpawnEgg), - "minecraft:parrot_spawn_egg" => Some(Item::ParrotSpawnEgg), - "minecraft:phantom_spawn_egg" => Some(Item::PhantomSpawnEgg), - "minecraft:pig_spawn_egg" => Some(Item::PigSpawnEgg), - "minecraft:polar_bear_spawn_egg" => Some(Item::PolarBearSpawnEgg), - "minecraft:pufferfish_spawn_egg" => Some(Item::PufferfishSpawnEgg), - "minecraft:rabbit_spawn_egg" => Some(Item::RabbitSpawnEgg), - "minecraft:salmon_spawn_egg" => Some(Item::SalmonSpawnEgg), - "minecraft:sheep_spawn_egg" => Some(Item::SheepSpawnEgg), - "minecraft:shulker_spawn_egg" => Some(Item::ShulkerSpawnEgg), - "minecraft:silverfish_spawn_egg" => Some(Item::SilverfishSpawnEgg), - "minecraft:skeleton_spawn_egg" => Some(Item::SkeletonSpawnEgg), - "minecraft:skeleton_horse_spawn_egg" => Some(Item::SkeletonHorseSpawnEgg), - "minecraft:slime_spawn_egg" => Some(Item::SlimeSpawnEgg), - "minecraft:spider_spawn_egg" => Some(Item::SpiderSpawnEgg), - "minecraft:squid_spawn_egg" => Some(Item::SquidSpawnEgg), - "minecraft:stray_spawn_egg" => Some(Item::StraySpawnEgg), - "minecraft:tropical_fish_spawn_egg" => Some(Item::TropicalFishSpawnEgg), - "minecraft:turtle_spawn_egg" => Some(Item::TurtleSpawnEgg), - "minecraft:vex_spawn_egg" => Some(Item::VexSpawnEgg), - "minecraft:villager_spawn_egg" => Some(Item::VillagerSpawnEgg), - "minecraft:vindicator_spawn_egg" => Some(Item::VindicatorSpawnEgg), - "minecraft:witch_spawn_egg" => Some(Item::WitchSpawnEgg), - "minecraft:wither_skeleton_spawn_egg" => Some(Item::WitherSkeletonSpawnEgg), - "minecraft:wolf_spawn_egg" => Some(Item::WolfSpawnEgg), - "minecraft:zombie_spawn_egg" => Some(Item::ZombieSpawnEgg), - "minecraft:zombie_horse_spawn_egg" => Some(Item::ZombieHorseSpawnEgg), - "minecraft:zombie_pigman_spawn_egg" => Some(Item::ZombiePigmanSpawnEgg), - "minecraft:zombie_villager_spawn_egg" => Some(Item::ZombieVillagerSpawnEgg), - "minecraft:experience_bottle" => Some(Item::ExperienceBottle), - "minecraft:fire_charge" => Some(Item::FireCharge), - "minecraft:writable_book" => Some(Item::WritableBook), - "minecraft:written_book" => Some(Item::WrittenBook), - "minecraft:emerald" => Some(Item::Emerald), - "minecraft:item_frame" => Some(Item::ItemFrame), - "minecraft:flower_pot" => Some(Item::FlowerPot), - "minecraft:carrot" => Some(Item::Carrot), - "minecraft:potato" => Some(Item::Potato), - "minecraft:baked_potato" => Some(Item::BakedPotato), - "minecraft:poisonous_potato" => Some(Item::PoisonousPotato), - "minecraft:map" => Some(Item::Map), - "minecraft:golden_carrot" => Some(Item::GoldenCarrot), - "minecraft:skeleton_skull" => Some(Item::SkeletonSkull), - "minecraft:wither_skeleton_skull" => Some(Item::WitherSkeletonSkull), - "minecraft:player_head" => Some(Item::PlayerHead), - "minecraft:zombie_head" => Some(Item::ZombieHead), - "minecraft:creeper_head" => Some(Item::CreeperHead), - "minecraft:dragon_head" => Some(Item::DragonHead), - "minecraft:carrot_on_a_stick" => Some(Item::CarrotOnAStick), - "minecraft:nether_star" => Some(Item::NetherStar), - "minecraft:pumpkin_pie" => Some(Item::PumpkinPie), - "minecraft:firework_rocket" => Some(Item::FireworkRocket), - "minecraft:firework_star" => Some(Item::FireworkStar), - "minecraft:enchanted_book" => Some(Item::EnchantedBook), - "minecraft:nether_brick" => Some(Item::NetherBrick), - "minecraft:quartz" => Some(Item::Quartz), - "minecraft:tnt_minecart" => Some(Item::TntMinecart), - "minecraft:hopper_minecart" => Some(Item::HopperMinecart), - "minecraft:prismarine_shard" => Some(Item::PrismarineShard), - "minecraft:prismarine_crystals" => Some(Item::PrismarineCrystals), - "minecraft:rabbit" => Some(Item::Rabbit), - "minecraft:cooked_rabbit" => Some(Item::CookedRabbit), - "minecraft:rabbit_stew" => Some(Item::RabbitStew), - "minecraft:rabbit_foot" => Some(Item::RabbitFoot), - "minecraft:rabbit_hide" => Some(Item::RabbitHide), - "minecraft:armor_stand" => Some(Item::ArmorStand), - "minecraft:iron_horse_armor" => Some(Item::IronHorseArmor), - "minecraft:golden_horse_armor" => Some(Item::GoldenHorseArmor), - "minecraft:diamond_horse_armor" => Some(Item::DiamondHorseArmor), - "minecraft:lead" => Some(Item::Lead), - "minecraft:name_tag" => Some(Item::NameTag), - "minecraft:command_block_minecart" => Some(Item::CommandBlockMinecart), - "minecraft:mutton" => Some(Item::Mutton), - "minecraft:cooked_mutton" => Some(Item::CookedMutton), - "minecraft:white_banner" => Some(Item::WhiteBanner), - "minecraft:orange_banner" => Some(Item::OrangeBanner), - "minecraft:magenta_banner" => Some(Item::MagentaBanner), - "minecraft:light_blue_banner" => Some(Item::LightBlueBanner), - "minecraft:yellow_banner" => Some(Item::YellowBanner), - "minecraft:lime_banner" => Some(Item::LimeBanner), - "minecraft:pink_banner" => Some(Item::PinkBanner), - "minecraft:gray_banner" => Some(Item::GrayBanner), - "minecraft:light_gray_banner" => Some(Item::LightGrayBanner), - "minecraft:cyan_banner" => Some(Item::CyanBanner), - "minecraft:purple_banner" => Some(Item::PurpleBanner), - "minecraft:blue_banner" => Some(Item::BlueBanner), - "minecraft:brown_banner" => Some(Item::BrownBanner), - "minecraft:green_banner" => Some(Item::GreenBanner), - "minecraft:red_banner" => Some(Item::RedBanner), - "minecraft:black_banner" => Some(Item::BlackBanner), - "minecraft:end_crystal" => Some(Item::EndCrystal), - "minecraft:chorus_fruit" => Some(Item::ChorusFruit), - "minecraft:popped_chorus_fruit" => Some(Item::PoppedChorusFruit), - "minecraft:beetroot" => Some(Item::Beetroot), - "minecraft:beetroot_seeds" => Some(Item::BeetrootSeeds), - "minecraft:beetroot_soup" => Some(Item::BeetrootSoup), - "minecraft:dragon_breath" => Some(Item::DragonBreath), - "minecraft:splash_potion" => Some(Item::SplashPotion), - "minecraft:spectral_arrow" => Some(Item::SpectralArrow), - "minecraft:tipped_arrow" => Some(Item::TippedArrow), - "minecraft:lingering_potion" => Some(Item::LingeringPotion), - "minecraft:shield" => Some(Item::Shield), - "minecraft:elytra" => Some(Item::Elytra), - "minecraft:spruce_boat" => Some(Item::SpruceBoat), - "minecraft:birch_boat" => Some(Item::BirchBoat), - "minecraft:jungle_boat" => Some(Item::JungleBoat), - "minecraft:acacia_boat" => Some(Item::AcaciaBoat), - "minecraft:dark_oak_boat" => Some(Item::DarkOakBoat), - "minecraft:totem_of_undying" => Some(Item::TotemOfUndying), - "minecraft:shulker_shell" => Some(Item::ShulkerShell), - "minecraft:iron_nugget" => Some(Item::IronNugget), - "minecraft:knowledge_book" => Some(Item::KnowledgeBook), - "minecraft:debug_stick" => Some(Item::DebugStick), - "minecraft:music_disc_13" => Some(Item::MusicDisc13), - "minecraft:music_disc_cat" => Some(Item::MusicDiscCat), - "minecraft:music_disc_blocks" => Some(Item::MusicDiscBlocks), - "minecraft:music_disc_chirp" => Some(Item::MusicDiscChirp), - "minecraft:music_disc_far" => Some(Item::MusicDiscFar), - "minecraft:music_disc_mall" => Some(Item::MusicDiscMall), - "minecraft:music_disc_mellohi" => Some(Item::MusicDiscMellohi), - "minecraft:music_disc_stal" => Some(Item::MusicDiscStal), - "minecraft:music_disc_strad" => Some(Item::MusicDiscStrad), - "minecraft:music_disc_ward" => Some(Item::MusicDiscWard), - "minecraft:music_disc_11" => Some(Item::MusicDisc11), - "minecraft:music_disc_wait" => Some(Item::MusicDiscWait), - "minecraft:trident" => Some(Item::Trident), - "minecraft:phantom_membrane" => Some(Item::PhantomMembrane), - "minecraft:nautilus_shell" => Some(Item::NautilusShell), - "minecraft:heart_of_the_sea" => Some(Item::HeartOfTheSea), - _ => None, - } - } - pub fn identifier(self) -> &'static str { - match self { - Item::Air => "minecraft:air", - Item::Stone => "minecraft:stone", - Item::Granite => "minecraft:granite", - Item::PolishedGranite => "minecraft:polished_granite", - Item::Diorite => "minecraft:diorite", - Item::PolishedDiorite => "minecraft:polished_diorite", - Item::Andesite => "minecraft:andesite", - Item::PolishedAndesite => "minecraft:polished_andesite", - Item::GrassBlock => "minecraft:grass_block", - Item::Dirt => "minecraft:dirt", - Item::CoarseDirt => "minecraft:coarse_dirt", - Item::Podzol => "minecraft:podzol", - Item::Cobblestone => "minecraft:cobblestone", - Item::OakPlanks => "minecraft:oak_planks", - Item::SprucePlanks => "minecraft:spruce_planks", - Item::BirchPlanks => "minecraft:birch_planks", - Item::JunglePlanks => "minecraft:jungle_planks", - Item::AcaciaPlanks => "minecraft:acacia_planks", - Item::DarkOakPlanks => "minecraft:dark_oak_planks", - Item::OakSapling => "minecraft:oak_sapling", - Item::SpruceSapling => "minecraft:spruce_sapling", - Item::BirchSapling => "minecraft:birch_sapling", - Item::JungleSapling => "minecraft:jungle_sapling", - Item::AcaciaSapling => "minecraft:acacia_sapling", - Item::DarkOakSapling => "minecraft:dark_oak_sapling", - Item::Bedrock => "minecraft:bedrock", - Item::Sand => "minecraft:sand", - Item::RedSand => "minecraft:red_sand", - Item::Gravel => "minecraft:gravel", - Item::GoldOre => "minecraft:gold_ore", - Item::IronOre => "minecraft:iron_ore", - Item::CoalOre => "minecraft:coal_ore", - Item::OakLog => "minecraft:oak_log", - Item::SpruceLog => "minecraft:spruce_log", - Item::BirchLog => "minecraft:birch_log", - Item::JungleLog => "minecraft:jungle_log", - Item::AcaciaLog => "minecraft:acacia_log", - Item::DarkOakLog => "minecraft:dark_oak_log", - Item::StrippedOakLog => "minecraft:stripped_oak_log", - Item::StrippedSpruceLog => "minecraft:stripped_spruce_log", - Item::StrippedBirchLog => "minecraft:stripped_birch_log", - Item::StrippedJungleLog => "minecraft:stripped_jungle_log", - Item::StrippedAcaciaLog => "minecraft:stripped_acacia_log", - Item::StrippedDarkOakLog => "minecraft:stripped_dark_oak_log", - Item::StrippedOakWood => "minecraft:stripped_oak_wood", - Item::StrippedSpruceWood => "minecraft:stripped_spruce_wood", - Item::StrippedBirchWood => "minecraft:stripped_birch_wood", - Item::StrippedJungleWood => "minecraft:stripped_jungle_wood", - Item::StrippedAcaciaWood => "minecraft:stripped_acacia_wood", - Item::StrippedDarkOakWood => "minecraft:stripped_dark_oak_wood", - Item::OakWood => "minecraft:oak_wood", - Item::SpruceWood => "minecraft:spruce_wood", - Item::BirchWood => "minecraft:birch_wood", - Item::JungleWood => "minecraft:jungle_wood", - Item::AcaciaWood => "minecraft:acacia_wood", - Item::DarkOakWood => "minecraft:dark_oak_wood", - Item::OakLeaves => "minecraft:oak_leaves", - Item::SpruceLeaves => "minecraft:spruce_leaves", - Item::BirchLeaves => "minecraft:birch_leaves", - Item::JungleLeaves => "minecraft:jungle_leaves", - Item::AcaciaLeaves => "minecraft:acacia_leaves", - Item::DarkOakLeaves => "minecraft:dark_oak_leaves", - Item::Sponge => "minecraft:sponge", - Item::WetSponge => "minecraft:wet_sponge", - Item::Glass => "minecraft:glass", - Item::LapisOre => "minecraft:lapis_ore", - Item::LapisBlock => "minecraft:lapis_block", - Item::Dispenser => "minecraft:dispenser", - Item::Sandstone => "minecraft:sandstone", - Item::ChiseledSandstone => "minecraft:chiseled_sandstone", - Item::CutSandstone => "minecraft:cut_sandstone", - Item::NoteBlock => "minecraft:note_block", - Item::PoweredRail => "minecraft:powered_rail", - Item::DetectorRail => "minecraft:detector_rail", - Item::StickyPiston => "minecraft:sticky_piston", - Item::Cobweb => "minecraft:cobweb", - Item::Grass => "minecraft:grass", - Item::Fern => "minecraft:fern", - Item::DeadBush => "minecraft:dead_bush", - Item::Seagrass => "minecraft:seagrass", - Item::SeaPickle => "minecraft:sea_pickle", - Item::Piston => "minecraft:piston", - Item::WhiteWool => "minecraft:white_wool", - Item::OrangeWool => "minecraft:orange_wool", - Item::MagentaWool => "minecraft:magenta_wool", - Item::LightBlueWool => "minecraft:light_blue_wool", - Item::YellowWool => "minecraft:yellow_wool", - Item::LimeWool => "minecraft:lime_wool", - Item::PinkWool => "minecraft:pink_wool", - Item::GrayWool => "minecraft:gray_wool", - Item::LightGrayWool => "minecraft:light_gray_wool", - Item::CyanWool => "minecraft:cyan_wool", - Item::PurpleWool => "minecraft:purple_wool", - Item::BlueWool => "minecraft:blue_wool", - Item::BrownWool => "minecraft:brown_wool", - Item::GreenWool => "minecraft:green_wool", - Item::RedWool => "minecraft:red_wool", - Item::BlackWool => "minecraft:black_wool", - Item::Dandelion => "minecraft:dandelion", - Item::Poppy => "minecraft:poppy", - Item::BlueOrchid => "minecraft:blue_orchid", - Item::Allium => "minecraft:allium", - Item::AzureBluet => "minecraft:azure_bluet", - Item::RedTulip => "minecraft:red_tulip", - Item::OrangeTulip => "minecraft:orange_tulip", - Item::WhiteTulip => "minecraft:white_tulip", - Item::PinkTulip => "minecraft:pink_tulip", - Item::OxeyeDaisy => "minecraft:oxeye_daisy", - Item::BrownMushroom => "minecraft:brown_mushroom", - Item::RedMushroom => "minecraft:red_mushroom", - Item::GoldBlock => "minecraft:gold_block", - Item::IronBlock => "minecraft:iron_block", - Item::OakSlab => "minecraft:oak_slab", - Item::SpruceSlab => "minecraft:spruce_slab", - Item::BirchSlab => "minecraft:birch_slab", - Item::JungleSlab => "minecraft:jungle_slab", - Item::AcaciaSlab => "minecraft:acacia_slab", - Item::DarkOakSlab => "minecraft:dark_oak_slab", - Item::StoneSlab => "minecraft:stone_slab", - Item::SandstoneSlab => "minecraft:sandstone_slab", - Item::PetrifiedOakSlab => "minecraft:petrified_oak_slab", - Item::CobblestoneSlab => "minecraft:cobblestone_slab", - Item::BrickSlab => "minecraft:brick_slab", - Item::StoneBrickSlab => "minecraft:stone_brick_slab", - Item::NetherBrickSlab => "minecraft:nether_brick_slab", - Item::QuartzSlab => "minecraft:quartz_slab", - Item::RedSandstoneSlab => "minecraft:red_sandstone_slab", - Item::PurpurSlab => "minecraft:purpur_slab", - Item::PrismarineSlab => "minecraft:prismarine_slab", - Item::PrismarineBrickSlab => "minecraft:prismarine_brick_slab", - Item::DarkPrismarineSlab => "minecraft:dark_prismarine_slab", - Item::SmoothQuartz => "minecraft:smooth_quartz", - Item::SmoothRedSandstone => "minecraft:smooth_red_sandstone", - Item::SmoothSandstone => "minecraft:smooth_sandstone", - Item::SmoothStone => "minecraft:smooth_stone", - Item::Bricks => "minecraft:bricks", - Item::Tnt => "minecraft:tnt", - Item::Bookshelf => "minecraft:bookshelf", - Item::MossyCobblestone => "minecraft:mossy_cobblestone", - Item::Obsidian => "minecraft:obsidian", - Item::Torch => "minecraft:torch", - Item::EndRod => "minecraft:end_rod", - Item::ChorusPlant => "minecraft:chorus_plant", - Item::ChorusFlower => "minecraft:chorus_flower", - Item::PurpurBlock => "minecraft:purpur_block", - Item::PurpurPillar => "minecraft:purpur_pillar", - Item::PurpurStairs => "minecraft:purpur_stairs", - Item::Spawner => "minecraft:spawner", - Item::OakStairs => "minecraft:oak_stairs", - Item::Chest => "minecraft:chest", - Item::DiamondOre => "minecraft:diamond_ore", - Item::DiamondBlock => "minecraft:diamond_block", - Item::CraftingTable => "minecraft:crafting_table", - Item::Farmland => "minecraft:farmland", - Item::Furnace => "minecraft:furnace", - Item::Ladder => "minecraft:ladder", - Item::Rail => "minecraft:rail", - Item::CobblestoneStairs => "minecraft:cobblestone_stairs", - Item::Lever => "minecraft:lever", - Item::StonePressurePlate => "minecraft:stone_pressure_plate", - Item::OakPressurePlate => "minecraft:oak_pressure_plate", - Item::SprucePressurePlate => "minecraft:spruce_pressure_plate", - Item::BirchPressurePlate => "minecraft:birch_pressure_plate", - Item::JunglePressurePlate => "minecraft:jungle_pressure_plate", - Item::AcaciaPressurePlate => "minecraft:acacia_pressure_plate", - Item::DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate", - Item::RedstoneOre => "minecraft:redstone_ore", - Item::RedstoneTorch => "minecraft:redstone_torch", - Item::StoneButton => "minecraft:stone_button", - Item::Snow => "minecraft:snow", - Item::Ice => "minecraft:ice", - Item::SnowBlock => "minecraft:snow_block", - Item::Cactus => "minecraft:cactus", - Item::Clay => "minecraft:clay", - Item::Jukebox => "minecraft:jukebox", - Item::OakFence => "minecraft:oak_fence", - Item::SpruceFence => "minecraft:spruce_fence", - Item::BirchFence => "minecraft:birch_fence", - Item::JungleFence => "minecraft:jungle_fence", - Item::AcaciaFence => "minecraft:acacia_fence", - Item::DarkOakFence => "minecraft:dark_oak_fence", - Item::Pumpkin => "minecraft:pumpkin", - Item::CarvedPumpkin => "minecraft:carved_pumpkin", - Item::Netherrack => "minecraft:netherrack", - Item::SoulSand => "minecraft:soul_sand", - Item::Glowstone => "minecraft:glowstone", - Item::JackOLantern => "minecraft:jack_o_lantern", - Item::OakTrapdoor => "minecraft:oak_trapdoor", - Item::SpruceTrapdoor => "minecraft:spruce_trapdoor", - Item::BirchTrapdoor => "minecraft:birch_trapdoor", - Item::JungleTrapdoor => "minecraft:jungle_trapdoor", - Item::AcaciaTrapdoor => "minecraft:acacia_trapdoor", - Item::DarkOakTrapdoor => "minecraft:dark_oak_trapdoor", - Item::InfestedStone => "minecraft:infested_stone", - Item::InfestedCobblestone => "minecraft:infested_cobblestone", - Item::InfestedStoneBricks => "minecraft:infested_stone_bricks", - Item::InfestedMossyStoneBricks => "minecraft:infested_mossy_stone_bricks", - Item::InfestedCrackedStoneBricks => "minecraft:infested_cracked_stone_bricks", - Item::InfestedChiseledStoneBricks => "minecraft:infested_chiseled_stone_bricks", - Item::StoneBricks => "minecraft:stone_bricks", - Item::MossyStoneBricks => "minecraft:mossy_stone_bricks", - Item::CrackedStoneBricks => "minecraft:cracked_stone_bricks", - Item::ChiseledStoneBricks => "minecraft:chiseled_stone_bricks", - Item::BrownMushroomBlock => "minecraft:brown_mushroom_block", - Item::RedMushroomBlock => "minecraft:red_mushroom_block", - Item::MushroomStem => "minecraft:mushroom_stem", - Item::IronBars => "minecraft:iron_bars", - Item::GlassPane => "minecraft:glass_pane", - Item::Melon => "minecraft:melon", - Item::Vine => "minecraft:vine", - Item::OakFenceGate => "minecraft:oak_fence_gate", - Item::SpruceFenceGate => "minecraft:spruce_fence_gate", - Item::BirchFenceGate => "minecraft:birch_fence_gate", - Item::JungleFenceGate => "minecraft:jungle_fence_gate", - Item::AcaciaFenceGate => "minecraft:acacia_fence_gate", - Item::DarkOakFenceGate => "minecraft:dark_oak_fence_gate", - Item::BrickStairs => "minecraft:brick_stairs", - Item::StoneBrickStairs => "minecraft:stone_brick_stairs", - Item::Mycelium => "minecraft:mycelium", - Item::LilyPad => "minecraft:lily_pad", - Item::NetherBricks => "minecraft:nether_bricks", - Item::NetherBrickFence => "minecraft:nether_brick_fence", - Item::NetherBrickStairs => "minecraft:nether_brick_stairs", - Item::EnchantingTable => "minecraft:enchanting_table", - Item::EndPortalFrame => "minecraft:end_portal_frame", - Item::EndStone => "minecraft:end_stone", - Item::EndStoneBricks => "minecraft:end_stone_bricks", - Item::DragonEgg => "minecraft:dragon_egg", - Item::RedstoneLamp => "minecraft:redstone_lamp", - Item::SandstoneStairs => "minecraft:sandstone_stairs", - Item::EmeraldOre => "minecraft:emerald_ore", - Item::EnderChest => "minecraft:ender_chest", - Item::TripwireHook => "minecraft:tripwire_hook", - Item::EmeraldBlock => "minecraft:emerald_block", - Item::SpruceStairs => "minecraft:spruce_stairs", - Item::BirchStairs => "minecraft:birch_stairs", - Item::JungleStairs => "minecraft:jungle_stairs", - Item::CommandBlock => "minecraft:command_block", - Item::Beacon => "minecraft:beacon", - Item::CobblestoneWall => "minecraft:cobblestone_wall", - Item::MossyCobblestoneWall => "minecraft:mossy_cobblestone_wall", - Item::OakButton => "minecraft:oak_button", - Item::SpruceButton => "minecraft:spruce_button", - Item::BirchButton => "minecraft:birch_button", - Item::JungleButton => "minecraft:jungle_button", - Item::AcaciaButton => "minecraft:acacia_button", - Item::DarkOakButton => "minecraft:dark_oak_button", - Item::Anvil => "minecraft:anvil", - Item::ChippedAnvil => "minecraft:chipped_anvil", - Item::DamagedAnvil => "minecraft:damaged_anvil", - Item::TrappedChest => "minecraft:trapped_chest", - Item::LightWeightedPressurePlate => "minecraft:light_weighted_pressure_plate", - Item::HeavyWeightedPressurePlate => "minecraft:heavy_weighted_pressure_plate", - Item::DaylightDetector => "minecraft:daylight_detector", - Item::RedstoneBlock => "minecraft:redstone_block", - Item::NetherQuartzOre => "minecraft:nether_quartz_ore", - Item::Hopper => "minecraft:hopper", - Item::ChiseledQuartzBlock => "minecraft:chiseled_quartz_block", - Item::QuartzBlock => "minecraft:quartz_block", - Item::QuartzPillar => "minecraft:quartz_pillar", - Item::QuartzStairs => "minecraft:quartz_stairs", - Item::ActivatorRail => "minecraft:activator_rail", - Item::Dropper => "minecraft:dropper", - Item::WhiteTerracotta => "minecraft:white_terracotta", - Item::OrangeTerracotta => "minecraft:orange_terracotta", - Item::MagentaTerracotta => "minecraft:magenta_terracotta", - Item::LightBlueTerracotta => "minecraft:light_blue_terracotta", - Item::YellowTerracotta => "minecraft:yellow_terracotta", - Item::LimeTerracotta => "minecraft:lime_terracotta", - Item::PinkTerracotta => "minecraft:pink_terracotta", - Item::GrayTerracotta => "minecraft:gray_terracotta", - Item::LightGrayTerracotta => "minecraft:light_gray_terracotta", - Item::CyanTerracotta => "minecraft:cyan_terracotta", - Item::PurpleTerracotta => "minecraft:purple_terracotta", - Item::BlueTerracotta => "minecraft:blue_terracotta", - Item::BrownTerracotta => "minecraft:brown_terracotta", - Item::GreenTerracotta => "minecraft:green_terracotta", - Item::RedTerracotta => "minecraft:red_terracotta", - Item::BlackTerracotta => "minecraft:black_terracotta", - Item::Barrier => "minecraft:barrier", - Item::IronTrapdoor => "minecraft:iron_trapdoor", - Item::HayBlock => "minecraft:hay_block", - Item::WhiteCarpet => "minecraft:white_carpet", - Item::OrangeCarpet => "minecraft:orange_carpet", - Item::MagentaCarpet => "minecraft:magenta_carpet", - Item::LightBlueCarpet => "minecraft:light_blue_carpet", - Item::YellowCarpet => "minecraft:yellow_carpet", - Item::LimeCarpet => "minecraft:lime_carpet", - Item::PinkCarpet => "minecraft:pink_carpet", - Item::GrayCarpet => "minecraft:gray_carpet", - Item::LightGrayCarpet => "minecraft:light_gray_carpet", - Item::CyanCarpet => "minecraft:cyan_carpet", - Item::PurpleCarpet => "minecraft:purple_carpet", - Item::BlueCarpet => "minecraft:blue_carpet", - Item::BrownCarpet => "minecraft:brown_carpet", - Item::GreenCarpet => "minecraft:green_carpet", - Item::RedCarpet => "minecraft:red_carpet", - Item::BlackCarpet => "minecraft:black_carpet", - Item::Terracotta => "minecraft:terracotta", - Item::CoalBlock => "minecraft:coal_block", - Item::PackedIce => "minecraft:packed_ice", - Item::AcaciaStairs => "minecraft:acacia_stairs", - Item::DarkOakStairs => "minecraft:dark_oak_stairs", - Item::SlimeBlock => "minecraft:slime_block", - Item::GrassPath => "minecraft:grass_path", - Item::Sunflower => "minecraft:sunflower", - Item::Lilac => "minecraft:lilac", - Item::RoseBush => "minecraft:rose_bush", - Item::Peony => "minecraft:peony", - Item::TallGrass => "minecraft:tall_grass", - Item::LargeFern => "minecraft:large_fern", - Item::WhiteStainedGlass => "minecraft:white_stained_glass", - Item::OrangeStainedGlass => "minecraft:orange_stained_glass", - Item::MagentaStainedGlass => "minecraft:magenta_stained_glass", - Item::LightBlueStainedGlass => "minecraft:light_blue_stained_glass", - Item::YellowStainedGlass => "minecraft:yellow_stained_glass", - Item::LimeStainedGlass => "minecraft:lime_stained_glass", - Item::PinkStainedGlass => "minecraft:pink_stained_glass", - Item::GrayStainedGlass => "minecraft:gray_stained_glass", - Item::LightGrayStainedGlass => "minecraft:light_gray_stained_glass", - Item::CyanStainedGlass => "minecraft:cyan_stained_glass", - Item::PurpleStainedGlass => "minecraft:purple_stained_glass", - Item::BlueStainedGlass => "minecraft:blue_stained_glass", - Item::BrownStainedGlass => "minecraft:brown_stained_glass", - Item::GreenStainedGlass => "minecraft:green_stained_glass", - Item::RedStainedGlass => "minecraft:red_stained_glass", - Item::BlackStainedGlass => "minecraft:black_stained_glass", - Item::WhiteStainedGlassPane => "minecraft:white_stained_glass_pane", - Item::OrangeStainedGlassPane => "minecraft:orange_stained_glass_pane", - Item::MagentaStainedGlassPane => "minecraft:magenta_stained_glass_pane", - Item::LightBlueStainedGlassPane => "minecraft:light_blue_stained_glass_pane", - Item::YellowStainedGlassPane => "minecraft:yellow_stained_glass_pane", - Item::LimeStainedGlassPane => "minecraft:lime_stained_glass_pane", - Item::PinkStainedGlassPane => "minecraft:pink_stained_glass_pane", - Item::GrayStainedGlassPane => "minecraft:gray_stained_glass_pane", - Item::LightGrayStainedGlassPane => "minecraft:light_gray_stained_glass_pane", - Item::CyanStainedGlassPane => "minecraft:cyan_stained_glass_pane", - Item::PurpleStainedGlassPane => "minecraft:purple_stained_glass_pane", - Item::BlueStainedGlassPane => "minecraft:blue_stained_glass_pane", - Item::BrownStainedGlassPane => "minecraft:brown_stained_glass_pane", - Item::GreenStainedGlassPane => "minecraft:green_stained_glass_pane", - Item::RedStainedGlassPane => "minecraft:red_stained_glass_pane", - Item::BlackStainedGlassPane => "minecraft:black_stained_glass_pane", - Item::Prismarine => "minecraft:prismarine", - Item::PrismarineBricks => "minecraft:prismarine_bricks", - Item::DarkPrismarine => "minecraft:dark_prismarine", - Item::PrismarineStairs => "minecraft:prismarine_stairs", - Item::PrismarineBrickStairs => "minecraft:prismarine_brick_stairs", - Item::DarkPrismarineStairs => "minecraft:dark_prismarine_stairs", - Item::SeaLantern => "minecraft:sea_lantern", - Item::RedSandstone => "minecraft:red_sandstone", - Item::ChiseledRedSandstone => "minecraft:chiseled_red_sandstone", - Item::CutRedSandstone => "minecraft:cut_red_sandstone", - Item::RedSandstoneStairs => "minecraft:red_sandstone_stairs", - Item::RepeatingCommandBlock => "minecraft:repeating_command_block", - Item::ChainCommandBlock => "minecraft:chain_command_block", - Item::MagmaBlock => "minecraft:magma_block", - Item::NetherWartBlock => "minecraft:nether_wart_block", - Item::RedNetherBricks => "minecraft:red_nether_bricks", - Item::BoneBlock => "minecraft:bone_block", - Item::StructureVoid => "minecraft:structure_void", - Item::Observer => "minecraft:observer", - Item::ShulkerBox => "minecraft:shulker_box", - Item::WhiteShulkerBox => "minecraft:white_shulker_box", - Item::OrangeShulkerBox => "minecraft:orange_shulker_box", - Item::MagentaShulkerBox => "minecraft:magenta_shulker_box", - Item::LightBlueShulkerBox => "minecraft:light_blue_shulker_box", - Item::YellowShulkerBox => "minecraft:yellow_shulker_box", - Item::LimeShulkerBox => "minecraft:lime_shulker_box", - Item::PinkShulkerBox => "minecraft:pink_shulker_box", - Item::GrayShulkerBox => "minecraft:gray_shulker_box", - Item::LightGrayShulkerBox => "minecraft:light_gray_shulker_box", - Item::CyanShulkerBox => "minecraft:cyan_shulker_box", - Item::PurpleShulkerBox => "minecraft:purple_shulker_box", - Item::BlueShulkerBox => "minecraft:blue_shulker_box", - Item::BrownShulkerBox => "minecraft:brown_shulker_box", - Item::GreenShulkerBox => "minecraft:green_shulker_box", - Item::RedShulkerBox => "minecraft:red_shulker_box", - Item::BlackShulkerBox => "minecraft:black_shulker_box", - Item::WhiteGlazedTerracotta => "minecraft:white_glazed_terracotta", - Item::OrangeGlazedTerracotta => "minecraft:orange_glazed_terracotta", - Item::MagentaGlazedTerracotta => "minecraft:magenta_glazed_terracotta", - Item::LightBlueGlazedTerracotta => "minecraft:light_blue_glazed_terracotta", - Item::YellowGlazedTerracotta => "minecraft:yellow_glazed_terracotta", - Item::LimeGlazedTerracotta => "minecraft:lime_glazed_terracotta", - Item::PinkGlazedTerracotta => "minecraft:pink_glazed_terracotta", - Item::GrayGlazedTerracotta => "minecraft:gray_glazed_terracotta", - Item::LightGrayGlazedTerracotta => "minecraft:light_gray_glazed_terracotta", - Item::CyanGlazedTerracotta => "minecraft:cyan_glazed_terracotta", - Item::PurpleGlazedTerracotta => "minecraft:purple_glazed_terracotta", - Item::BlueGlazedTerracotta => "minecraft:blue_glazed_terracotta", - Item::BrownGlazedTerracotta => "minecraft:brown_glazed_terracotta", - Item::GreenGlazedTerracotta => "minecraft:green_glazed_terracotta", - Item::RedGlazedTerracotta => "minecraft:red_glazed_terracotta", - Item::BlackGlazedTerracotta => "minecraft:black_glazed_terracotta", - Item::WhiteConcrete => "minecraft:white_concrete", - Item::OrangeConcrete => "minecraft:orange_concrete", - Item::MagentaConcrete => "minecraft:magenta_concrete", - Item::LightBlueConcrete => "minecraft:light_blue_concrete", - Item::YellowConcrete => "minecraft:yellow_concrete", - Item::LimeConcrete => "minecraft:lime_concrete", - Item::PinkConcrete => "minecraft:pink_concrete", - Item::GrayConcrete => "minecraft:gray_concrete", - Item::LightGrayConcrete => "minecraft:light_gray_concrete", - Item::CyanConcrete => "minecraft:cyan_concrete", - Item::PurpleConcrete => "minecraft:purple_concrete", - Item::BlueConcrete => "minecraft:blue_concrete", - Item::BrownConcrete => "minecraft:brown_concrete", - Item::GreenConcrete => "minecraft:green_concrete", - Item::RedConcrete => "minecraft:red_concrete", - Item::BlackConcrete => "minecraft:black_concrete", - Item::WhiteConcretePowder => "minecraft:white_concrete_powder", - Item::OrangeConcretePowder => "minecraft:orange_concrete_powder", - Item::MagentaConcretePowder => "minecraft:magenta_concrete_powder", - Item::LightBlueConcretePowder => "minecraft:light_blue_concrete_powder", - Item::YellowConcretePowder => "minecraft:yellow_concrete_powder", - Item::LimeConcretePowder => "minecraft:lime_concrete_powder", - Item::PinkConcretePowder => "minecraft:pink_concrete_powder", - Item::GrayConcretePowder => "minecraft:gray_concrete_powder", - Item::LightGrayConcretePowder => "minecraft:light_gray_concrete_powder", - Item::CyanConcretePowder => "minecraft:cyan_concrete_powder", - Item::PurpleConcretePowder => "minecraft:purple_concrete_powder", - Item::BlueConcretePowder => "minecraft:blue_concrete_powder", - Item::BrownConcretePowder => "minecraft:brown_concrete_powder", - Item::GreenConcretePowder => "minecraft:green_concrete_powder", - Item::RedConcretePowder => "minecraft:red_concrete_powder", - Item::BlackConcretePowder => "minecraft:black_concrete_powder", - Item::TurtleEgg => "minecraft:turtle_egg", - Item::DeadTubeCoralBlock => "minecraft:dead_tube_coral_block", - Item::DeadBrainCoralBlock => "minecraft:dead_brain_coral_block", - Item::DeadBubbleCoralBlock => "minecraft:dead_bubble_coral_block", - Item::DeadFireCoralBlock => "minecraft:dead_fire_coral_block", - Item::DeadHornCoralBlock => "minecraft:dead_horn_coral_block", - Item::TubeCoralBlock => "minecraft:tube_coral_block", - Item::BrainCoralBlock => "minecraft:brain_coral_block", - Item::BubbleCoralBlock => "minecraft:bubble_coral_block", - Item::FireCoralBlock => "minecraft:fire_coral_block", - Item::HornCoralBlock => "minecraft:horn_coral_block", - Item::TubeCoral => "minecraft:tube_coral", - Item::BrainCoral => "minecraft:brain_coral", - Item::BubbleCoral => "minecraft:bubble_coral", - Item::FireCoral => "minecraft:fire_coral", - Item::HornCoral => "minecraft:horn_coral", - Item::DeadBrainCoral => "minecraft:dead_brain_coral", - Item::DeadBubbleCoral => "minecraft:dead_bubble_coral", - Item::DeadFireCoral => "minecraft:dead_fire_coral", - Item::DeadHornCoral => "minecraft:dead_horn_coral", - Item::DeadTubeCoral => "minecraft:dead_tube_coral", - Item::TubeCoralFan => "minecraft:tube_coral_fan", - Item::BrainCoralFan => "minecraft:brain_coral_fan", - Item::BubbleCoralFan => "minecraft:bubble_coral_fan", - Item::FireCoralFan => "minecraft:fire_coral_fan", - Item::HornCoralFan => "minecraft:horn_coral_fan", - Item::DeadTubeCoralFan => "minecraft:dead_tube_coral_fan", - Item::DeadBrainCoralFan => "minecraft:dead_brain_coral_fan", - Item::DeadBubbleCoralFan => "minecraft:dead_bubble_coral_fan", - Item::DeadFireCoralFan => "minecraft:dead_fire_coral_fan", - Item::DeadHornCoralFan => "minecraft:dead_horn_coral_fan", - Item::BlueIce => "minecraft:blue_ice", - Item::Conduit => "minecraft:conduit", - Item::IronDoor => "minecraft:iron_door", - Item::OakDoor => "minecraft:oak_door", - Item::SpruceDoor => "minecraft:spruce_door", - Item::BirchDoor => "minecraft:birch_door", - Item::JungleDoor => "minecraft:jungle_door", - Item::AcaciaDoor => "minecraft:acacia_door", - Item::DarkOakDoor => "minecraft:dark_oak_door", - Item::Repeater => "minecraft:repeater", - Item::Comparator => "minecraft:comparator", - Item::StructureBlock => "minecraft:structure_block", - Item::TurtleHelmet => "minecraft:turtle_helmet", - Item::Scute => "minecraft:scute", - Item::IronShovel => "minecraft:iron_shovel", - Item::IronPickaxe => "minecraft:iron_pickaxe", - Item::IronAxe => "minecraft:iron_axe", - Item::FlintAndSteel => "minecraft:flint_and_steel", - Item::Apple => "minecraft:apple", - Item::Bow => "minecraft:bow", - Item::Arrow => "minecraft:arrow", - Item::Coal => "minecraft:coal", - Item::Charcoal => "minecraft:charcoal", - Item::Diamond => "minecraft:diamond", - Item::IronIngot => "minecraft:iron_ingot", - Item::GoldIngot => "minecraft:gold_ingot", - Item::IronSword => "minecraft:iron_sword", - Item::WoodenSword => "minecraft:wooden_sword", - Item::WoodenShovel => "minecraft:wooden_shovel", - Item::WoodenPickaxe => "minecraft:wooden_pickaxe", - Item::WoodenAxe => "minecraft:wooden_axe", - Item::StoneSword => "minecraft:stone_sword", - Item::StoneShovel => "minecraft:stone_shovel", - Item::StonePickaxe => "minecraft:stone_pickaxe", - Item::StoneAxe => "minecraft:stone_axe", - Item::DiamondSword => "minecraft:diamond_sword", - Item::DiamondShovel => "minecraft:diamond_shovel", - Item::DiamondPickaxe => "minecraft:diamond_pickaxe", - Item::DiamondAxe => "minecraft:diamond_axe", - Item::Stick => "minecraft:stick", - Item::Bowl => "minecraft:bowl", - Item::MushroomStew => "minecraft:mushroom_stew", - Item::GoldenSword => "minecraft:golden_sword", - Item::GoldenShovel => "minecraft:golden_shovel", - Item::GoldenPickaxe => "minecraft:golden_pickaxe", - Item::GoldenAxe => "minecraft:golden_axe", - Item::String => "minecraft:string", - Item::Feather => "minecraft:feather", - Item::Gunpowder => "minecraft:gunpowder", - Item::WoodenHoe => "minecraft:wooden_hoe", - Item::StoneHoe => "minecraft:stone_hoe", - Item::IronHoe => "minecraft:iron_hoe", - Item::DiamondHoe => "minecraft:diamond_hoe", - Item::GoldenHoe => "minecraft:golden_hoe", - Item::WheatSeeds => "minecraft:wheat_seeds", - Item::Wheat => "minecraft:wheat", - Item::Bread => "minecraft:bread", - Item::LeatherHelmet => "minecraft:leather_helmet", - Item::LeatherChestplate => "minecraft:leather_chestplate", - Item::LeatherLeggings => "minecraft:leather_leggings", - Item::LeatherBoots => "minecraft:leather_boots", - Item::ChainmailHelmet => "minecraft:chainmail_helmet", - Item::ChainmailChestplate => "minecraft:chainmail_chestplate", - Item::ChainmailLeggings => "minecraft:chainmail_leggings", - Item::ChainmailBoots => "minecraft:chainmail_boots", - Item::IronHelmet => "minecraft:iron_helmet", - Item::IronChestplate => "minecraft:iron_chestplate", - Item::IronLeggings => "minecraft:iron_leggings", - Item::IronBoots => "minecraft:iron_boots", - Item::DiamondHelmet => "minecraft:diamond_helmet", - Item::DiamondChestplate => "minecraft:diamond_chestplate", - Item::DiamondLeggings => "minecraft:diamond_leggings", - Item::DiamondBoots => "minecraft:diamond_boots", - Item::GoldenHelmet => "minecraft:golden_helmet", - Item::GoldenChestplate => "minecraft:golden_chestplate", - Item::GoldenLeggings => "minecraft:golden_leggings", - Item::GoldenBoots => "minecraft:golden_boots", - Item::Flint => "minecraft:flint", - Item::Porkchop => "minecraft:porkchop", - Item::CookedPorkchop => "minecraft:cooked_porkchop", - Item::Painting => "minecraft:painting", - Item::GoldenApple => "minecraft:golden_apple", - Item::EnchantedGoldenApple => "minecraft:enchanted_golden_apple", - Item::Sign => "minecraft:sign", - Item::Bucket => "minecraft:bucket", - Item::WaterBucket => "minecraft:water_bucket", - Item::LavaBucket => "minecraft:lava_bucket", - Item::Minecart => "minecraft:minecart", - Item::Saddle => "minecraft:saddle", - Item::Redstone => "minecraft:redstone", - Item::Snowball => "minecraft:snowball", - Item::OakBoat => "minecraft:oak_boat", - Item::Leather => "minecraft:leather", - Item::MilkBucket => "minecraft:milk_bucket", - Item::PufferfishBucket => "minecraft:pufferfish_bucket", - Item::SalmonBucket => "minecraft:salmon_bucket", - Item::CodBucket => "minecraft:cod_bucket", - Item::TropicalFishBucket => "minecraft:tropical_fish_bucket", - Item::Brick => "minecraft:brick", - Item::ClayBall => "minecraft:clay_ball", - Item::SugarCane => "minecraft:sugar_cane", - Item::Kelp => "minecraft:kelp", - Item::DriedKelpBlock => "minecraft:dried_kelp_block", - Item::Paper => "minecraft:paper", - Item::Book => "minecraft:book", - Item::SlimeBall => "minecraft:slime_ball", - Item::ChestMinecart => "minecraft:chest_minecart", - Item::FurnaceMinecart => "minecraft:furnace_minecart", - Item::Egg => "minecraft:egg", - Item::Compass => "minecraft:compass", - Item::FishingRod => "minecraft:fishing_rod", - Item::Clock => "minecraft:clock", - Item::GlowstoneDust => "minecraft:glowstone_dust", - Item::Cod => "minecraft:cod", - Item::Salmon => "minecraft:salmon", - Item::TropicalFish => "minecraft:tropical_fish", - Item::Pufferfish => "minecraft:pufferfish", - Item::CookedCod => "minecraft:cooked_cod", - Item::CookedSalmon => "minecraft:cooked_salmon", - Item::InkSac => "minecraft:ink_sac", - Item::RoseRed => "minecraft:rose_red", - Item::CactusGreen => "minecraft:cactus_green", - Item::CocoaBeans => "minecraft:cocoa_beans", - Item::LapisLazuli => "minecraft:lapis_lazuli", - Item::PurpleDye => "minecraft:purple_dye", - Item::CyanDye => "minecraft:cyan_dye", - Item::LightGrayDye => "minecraft:light_gray_dye", - Item::GrayDye => "minecraft:gray_dye", - Item::PinkDye => "minecraft:pink_dye", - Item::LimeDye => "minecraft:lime_dye", - Item::DandelionYellow => "minecraft:dandelion_yellow", - Item::LightBlueDye => "minecraft:light_blue_dye", - Item::MagentaDye => "minecraft:magenta_dye", - Item::OrangeDye => "minecraft:orange_dye", - Item::BoneMeal => "minecraft:bone_meal", - Item::Bone => "minecraft:bone", - Item::Sugar => "minecraft:sugar", - Item::Cake => "minecraft:cake", - Item::WhiteBed => "minecraft:white_bed", - Item::OrangeBed => "minecraft:orange_bed", - Item::MagentaBed => "minecraft:magenta_bed", - Item::LightBlueBed => "minecraft:light_blue_bed", - Item::YellowBed => "minecraft:yellow_bed", - Item::LimeBed => "minecraft:lime_bed", - Item::PinkBed => "minecraft:pink_bed", - Item::GrayBed => "minecraft:gray_bed", - Item::LightGrayBed => "minecraft:light_gray_bed", - Item::CyanBed => "minecraft:cyan_bed", - Item::PurpleBed => "minecraft:purple_bed", - Item::BlueBed => "minecraft:blue_bed", - Item::BrownBed => "minecraft:brown_bed", - Item::GreenBed => "minecraft:green_bed", - Item::RedBed => "minecraft:red_bed", - Item::BlackBed => "minecraft:black_bed", - Item::Cookie => "minecraft:cookie", - Item::FilledMap => "minecraft:filled_map", - Item::Shears => "minecraft:shears", - Item::MelonSlice => "minecraft:melon_slice", - Item::DriedKelp => "minecraft:dried_kelp", - Item::PumpkinSeeds => "minecraft:pumpkin_seeds", - Item::MelonSeeds => "minecraft:melon_seeds", - Item::Beef => "minecraft:beef", - Item::CookedBeef => "minecraft:cooked_beef", - Item::Chicken => "minecraft:chicken", - Item::CookedChicken => "minecraft:cooked_chicken", - Item::RottenFlesh => "minecraft:rotten_flesh", - Item::EnderPearl => "minecraft:ender_pearl", - Item::BlazeRod => "minecraft:blaze_rod", - Item::GhastTear => "minecraft:ghast_tear", - Item::GoldNugget => "minecraft:gold_nugget", - Item::NetherWart => "minecraft:nether_wart", - Item::Potion => "minecraft:potion", - Item::GlassBottle => "minecraft:glass_bottle", - Item::SpiderEye => "minecraft:spider_eye", - Item::FermentedSpiderEye => "minecraft:fermented_spider_eye", - Item::BlazePowder => "minecraft:blaze_powder", - Item::MagmaCream => "minecraft:magma_cream", - Item::BrewingStand => "minecraft:brewing_stand", - Item::Cauldron => "minecraft:cauldron", - Item::EnderEye => "minecraft:ender_eye", - Item::GlisteringMelonSlice => "minecraft:glistering_melon_slice", - Item::BatSpawnEgg => "minecraft:bat_spawn_egg", - Item::BlazeSpawnEgg => "minecraft:blaze_spawn_egg", - Item::CaveSpiderSpawnEgg => "minecraft:cave_spider_spawn_egg", - Item::ChickenSpawnEgg => "minecraft:chicken_spawn_egg", - Item::CodSpawnEgg => "minecraft:cod_spawn_egg", - Item::CowSpawnEgg => "minecraft:cow_spawn_egg", - Item::CreeperSpawnEgg => "minecraft:creeper_spawn_egg", - Item::DolphinSpawnEgg => "minecraft:dolphin_spawn_egg", - Item::DonkeySpawnEgg => "minecraft:donkey_spawn_egg", - Item::DrownedSpawnEgg => "minecraft:drowned_spawn_egg", - Item::ElderGuardianSpawnEgg => "minecraft:elder_guardian_spawn_egg", - Item::EndermanSpawnEgg => "minecraft:enderman_spawn_egg", - Item::EndermiteSpawnEgg => "minecraft:endermite_spawn_egg", - Item::EvokerSpawnEgg => "minecraft:evoker_spawn_egg", - Item::GhastSpawnEgg => "minecraft:ghast_spawn_egg", - Item::GuardianSpawnEgg => "minecraft:guardian_spawn_egg", - Item::HorseSpawnEgg => "minecraft:horse_spawn_egg", - Item::HuskSpawnEgg => "minecraft:husk_spawn_egg", - Item::LlamaSpawnEgg => "minecraft:llama_spawn_egg", - Item::MagmaCubeSpawnEgg => "minecraft:magma_cube_spawn_egg", - Item::MooshroomSpawnEgg => "minecraft:mooshroom_spawn_egg", - Item::MuleSpawnEgg => "minecraft:mule_spawn_egg", - Item::OcelotSpawnEgg => "minecraft:ocelot_spawn_egg", - Item::ParrotSpawnEgg => "minecraft:parrot_spawn_egg", - Item::PhantomSpawnEgg => "minecraft:phantom_spawn_egg", - Item::PigSpawnEgg => "minecraft:pig_spawn_egg", - Item::PolarBearSpawnEgg => "minecraft:polar_bear_spawn_egg", - Item::PufferfishSpawnEgg => "minecraft:pufferfish_spawn_egg", - Item::RabbitSpawnEgg => "minecraft:rabbit_spawn_egg", - Item::SalmonSpawnEgg => "minecraft:salmon_spawn_egg", - Item::SheepSpawnEgg => "minecraft:sheep_spawn_egg", - Item::ShulkerSpawnEgg => "minecraft:shulker_spawn_egg", - Item::SilverfishSpawnEgg => "minecraft:silverfish_spawn_egg", - Item::SkeletonSpawnEgg => "minecraft:skeleton_spawn_egg", - Item::SkeletonHorseSpawnEgg => "minecraft:skeleton_horse_spawn_egg", - Item::SlimeSpawnEgg => "minecraft:slime_spawn_egg", - Item::SpiderSpawnEgg => "minecraft:spider_spawn_egg", - Item::SquidSpawnEgg => "minecraft:squid_spawn_egg", - Item::StraySpawnEgg => "minecraft:stray_spawn_egg", - Item::TropicalFishSpawnEgg => "minecraft:tropical_fish_spawn_egg", - Item::TurtleSpawnEgg => "minecraft:turtle_spawn_egg", - Item::VexSpawnEgg => "minecraft:vex_spawn_egg", - Item::VillagerSpawnEgg => "minecraft:villager_spawn_egg", - Item::VindicatorSpawnEgg => "minecraft:vindicator_spawn_egg", - Item::WitchSpawnEgg => "minecraft:witch_spawn_egg", - Item::WitherSkeletonSpawnEgg => "minecraft:wither_skeleton_spawn_egg", - Item::WolfSpawnEgg => "minecraft:wolf_spawn_egg", - Item::ZombieSpawnEgg => "minecraft:zombie_spawn_egg", - Item::ZombieHorseSpawnEgg => "minecraft:zombie_horse_spawn_egg", - Item::ZombiePigmanSpawnEgg => "minecraft:zombie_pigman_spawn_egg", - Item::ZombieVillagerSpawnEgg => "minecraft:zombie_villager_spawn_egg", - Item::ExperienceBottle => "minecraft:experience_bottle", - Item::FireCharge => "minecraft:fire_charge", - Item::WritableBook => "minecraft:writable_book", - Item::WrittenBook => "minecraft:written_book", - Item::Emerald => "minecraft:emerald", - Item::ItemFrame => "minecraft:item_frame", - Item::FlowerPot => "minecraft:flower_pot", - Item::Carrot => "minecraft:carrot", - Item::Potato => "minecraft:potato", - Item::BakedPotato => "minecraft:baked_potato", - Item::PoisonousPotato => "minecraft:poisonous_potato", - Item::Map => "minecraft:map", - Item::GoldenCarrot => "minecraft:golden_carrot", - Item::SkeletonSkull => "minecraft:skeleton_skull", - Item::WitherSkeletonSkull => "minecraft:wither_skeleton_skull", - Item::PlayerHead => "minecraft:player_head", - Item::ZombieHead => "minecraft:zombie_head", - Item::CreeperHead => "minecraft:creeper_head", - Item::DragonHead => "minecraft:dragon_head", - Item::CarrotOnAStick => "minecraft:carrot_on_a_stick", - Item::NetherStar => "minecraft:nether_star", - Item::PumpkinPie => "minecraft:pumpkin_pie", - Item::FireworkRocket => "minecraft:firework_rocket", - Item::FireworkStar => "minecraft:firework_star", - Item::EnchantedBook => "minecraft:enchanted_book", - Item::NetherBrick => "minecraft:nether_brick", - Item::Quartz => "minecraft:quartz", - Item::TntMinecart => "minecraft:tnt_minecart", - Item::HopperMinecart => "minecraft:hopper_minecart", - Item::PrismarineShard => "minecraft:prismarine_shard", - Item::PrismarineCrystals => "minecraft:prismarine_crystals", - Item::Rabbit => "minecraft:rabbit", - Item::CookedRabbit => "minecraft:cooked_rabbit", - Item::RabbitStew => "minecraft:rabbit_stew", - Item::RabbitFoot => "minecraft:rabbit_foot", - Item::RabbitHide => "minecraft:rabbit_hide", - Item::ArmorStand => "minecraft:armor_stand", - Item::IronHorseArmor => "minecraft:iron_horse_armor", - Item::GoldenHorseArmor => "minecraft:golden_horse_armor", - Item::DiamondHorseArmor => "minecraft:diamond_horse_armor", - Item::Lead => "minecraft:lead", - Item::NameTag => "minecraft:name_tag", - Item::CommandBlockMinecart => "minecraft:command_block_minecart", - Item::Mutton => "minecraft:mutton", - Item::CookedMutton => "minecraft:cooked_mutton", - Item::WhiteBanner => "minecraft:white_banner", - Item::OrangeBanner => "minecraft:orange_banner", - Item::MagentaBanner => "minecraft:magenta_banner", - Item::LightBlueBanner => "minecraft:light_blue_banner", - Item::YellowBanner => "minecraft:yellow_banner", - Item::LimeBanner => "minecraft:lime_banner", - Item::PinkBanner => "minecraft:pink_banner", - Item::GrayBanner => "minecraft:gray_banner", - Item::LightGrayBanner => "minecraft:light_gray_banner", - Item::CyanBanner => "minecraft:cyan_banner", - Item::PurpleBanner => "minecraft:purple_banner", - Item::BlueBanner => "minecraft:blue_banner", - Item::BrownBanner => "minecraft:brown_banner", - Item::GreenBanner => "minecraft:green_banner", - Item::RedBanner => "minecraft:red_banner", - Item::BlackBanner => "minecraft:black_banner", - Item::EndCrystal => "minecraft:end_crystal", - Item::ChorusFruit => "minecraft:chorus_fruit", - Item::PoppedChorusFruit => "minecraft:popped_chorus_fruit", - Item::Beetroot => "minecraft:beetroot", - Item::BeetrootSeeds => "minecraft:beetroot_seeds", - Item::BeetrootSoup => "minecraft:beetroot_soup", - Item::DragonBreath => "minecraft:dragon_breath", - Item::SplashPotion => "minecraft:splash_potion", - Item::SpectralArrow => "minecraft:spectral_arrow", - Item::TippedArrow => "minecraft:tipped_arrow", - Item::LingeringPotion => "minecraft:lingering_potion", - Item::Shield => "minecraft:shield", - Item::Elytra => "minecraft:elytra", - Item::SpruceBoat => "minecraft:spruce_boat", - Item::BirchBoat => "minecraft:birch_boat", - Item::JungleBoat => "minecraft:jungle_boat", - Item::AcaciaBoat => "minecraft:acacia_boat", - Item::DarkOakBoat => "minecraft:dark_oak_boat", - Item::TotemOfUndying => "minecraft:totem_of_undying", - Item::ShulkerShell => "minecraft:shulker_shell", - Item::IronNugget => "minecraft:iron_nugget", - Item::KnowledgeBook => "minecraft:knowledge_book", - Item::DebugStick => "minecraft:debug_stick", - Item::MusicDisc13 => "minecraft:music_disc_13", - Item::MusicDiscCat => "minecraft:music_disc_cat", - Item::MusicDiscBlocks => "minecraft:music_disc_blocks", - Item::MusicDiscChirp => "minecraft:music_disc_chirp", - Item::MusicDiscFar => "minecraft:music_disc_far", - Item::MusicDiscMall => "minecraft:music_disc_mall", - Item::MusicDiscMellohi => "minecraft:music_disc_mellohi", - Item::MusicDiscStal => "minecraft:music_disc_stal", - Item::MusicDiscStrad => "minecraft:music_disc_strad", - Item::MusicDiscWard => "minecraft:music_disc_ward", - Item::MusicDisc11 => "minecraft:music_disc_11", - Item::MusicDiscWait => "minecraft:music_disc_wait", - Item::Trident => "minecraft:trident", - Item::PhantomMembrane => "minecraft:phantom_membrane", - Item::NautilusShell => "minecraft:nautilus_shell", - Item::HeartOfTheSea => "minecraft:heart_of_the_sea", - } - } -} diff --git a/items/src/lib.rs b/items/src/lib.rs deleted file mode 100644 index 2fabe0f25..000000000 --- a/items/src/lib.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![forbid(unsafe_code, warnings)] - -use num_traits::{FromPrimitive, ToPrimitive}; - -#[macro_use] -extern crate num_derive; - -mod item; - -pub use item::Item; - -pub trait ItemExt { - /// Retrieves the 1.13.2 protocol ID for this item. - fn native_protocol_id(self) -> i32; - /// Attempts to get an item by its 1.13.2 protocol ID. - fn from_native_protocol_id(id: i32) -> Option<Self> - where - Self: Sized; -} - -impl ItemExt for Item { - fn native_protocol_id(self) -> i32 { - // Conveniently, the item enum variants are listed - // in the order of the protocol IDs, so we can - // just use the `ToPrimitive` implementation. - self.to_i32().unwrap() - } - - fn from_native_protocol_id(id: i32) -> Option<Self> - where - Self: Sized, - { - Item::from_i32(id) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_item() { - let item = Item::Air; - assert_eq!(item.native_protocol_id(), 0); - assert_eq!(Item::from_native_protocol_id(0), Some(item)); - } -} diff --git a/libcraft/LICENSE.md b/libcraft/LICENSE.md new file mode 100644 index 000000000..f49a4e16e --- /dev/null +++ b/libcraft/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/libcraft/README.md b/libcraft/README.md new file mode 100644 index 000000000..7d1d5c476 --- /dev/null +++ b/libcraft/README.md @@ -0,0 +1,32 @@ +# libcraft + +General-purpose Minecraft types and functions for Rust. Work in progress; code is being moved from [Feather](../README.md). + +`libcraft` is part of the Feather project, but it aims to provide standalone functionality for use in Minecraft-related tools +like map editors, world converters, etc. + +Once finished, this crate will provide: +* Block struct with access to properties, block state values, and IDs +* Item struct with access to properties and IDs +* Inventory and [window](https://wiki.vg/Inventory) definitions +* An implementation of Minecraft's [in-memory chunk data structure](https://wiki.vg/Chunk_Format) +* The [JSON Text/ChatComponent API](https://wiki.vg/Chat) +* Region file loading +* Packets from the [protocol](https://wiki.vg/Protocol) + +Each piece of functionality is in its own crate. All `libcraft-*` crates are reexported from the main `libcraft` crate. + +## License +Copyright 2021 Caelum van Ispelen + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/libcraft/blocks/Cargo.toml b/libcraft/blocks/Cargo.toml new file mode 100644 index 000000000..67a068115 --- /dev/null +++ b/libcraft/blocks/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "libcraft-blocks" +version = "0.1.0" +authors = ["Caelum van Ispelen <caelum12321@gmail.com>"] +edition = "2018" + +[dependencies] +libcraft-core = { path = "../core" } +libcraft-items = { path = "../items" } +libcraft-macros = { path = "../macros" } + +ahash = "0.7" +bincode = "1" +bytemuck = { version = "1", features = ["derive"] } +flate2 = "1" +once_cell = "1" +serde = { version = "1", features = ["derive"] } +thiserror = "1" +num-traits = "0.2" +num-derive = "0.3" diff --git a/libcraft/blocks/assets/raw_block_properties.bc.gz b/libcraft/blocks/assets/raw_block_properties.bc.gz new file mode 100644 index 000000000..f2b9fa5ad Binary files /dev/null and b/libcraft/blocks/assets/raw_block_properties.bc.gz differ diff --git a/libcraft/blocks/assets/raw_block_states.bc.gz b/libcraft/blocks/assets/raw_block_states.bc.gz new file mode 100644 index 000000000..f5c1f6b90 Binary files /dev/null and b/libcraft/blocks/assets/raw_block_states.bc.gz differ diff --git a/libcraft/blocks/src/block.rs b/libcraft/blocks/src/block.rs new file mode 100644 index 000000000..d80cc8ce1 --- /dev/null +++ b/libcraft/blocks/src/block.rs @@ -0,0 +1,13722 @@ +// This file is @generated. Please do not edit. +#[derive( + num_derive::FromPrimitive, + num_derive::ToPrimitive, + serde::Serialize, + serde::Deserialize, + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, +)] +pub enum BlockKind { + Air, + Stone, + Granite, + PolishedGranite, + Diorite, + PolishedDiorite, + Andesite, + PolishedAndesite, + GrassBlock, + Dirt, + CoarseDirt, + Podzol, + Cobblestone, + OakPlanks, + SprucePlanks, + BirchPlanks, + JunglePlanks, + AcaciaPlanks, + DarkOakPlanks, + OakSapling, + SpruceSapling, + BirchSapling, + JungleSapling, + AcaciaSapling, + DarkOakSapling, + Bedrock, + Water, + Lava, + Sand, + RedSand, + Gravel, + GoldOre, + IronOre, + CoalOre, + NetherGoldOre, + OakLog, + SpruceLog, + BirchLog, + JungleLog, + AcaciaLog, + DarkOakLog, + StrippedSpruceLog, + StrippedBirchLog, + StrippedJungleLog, + StrippedAcaciaLog, + StrippedDarkOakLog, + StrippedOakLog, + OakWood, + SpruceWood, + BirchWood, + JungleWood, + AcaciaWood, + DarkOakWood, + StrippedOakWood, + StrippedSpruceWood, + StrippedBirchWood, + StrippedJungleWood, + StrippedAcaciaWood, + StrippedDarkOakWood, + OakLeaves, + SpruceLeaves, + BirchLeaves, + JungleLeaves, + AcaciaLeaves, + DarkOakLeaves, + Sponge, + WetSponge, + Glass, + LapisOre, + LapisBlock, + Dispenser, + Sandstone, + ChiseledSandstone, + CutSandstone, + NoteBlock, + WhiteBed, + OrangeBed, + MagentaBed, + LightBlueBed, + YellowBed, + LimeBed, + PinkBed, + GrayBed, + LightGrayBed, + CyanBed, + PurpleBed, + BlueBed, + BrownBed, + GreenBed, + RedBed, + BlackBed, + PoweredRail, + DetectorRail, + StickyPiston, + Cobweb, + Grass, + Fern, + DeadBush, + Seagrass, + TallSeagrass, + Piston, + PistonHead, + WhiteWool, + OrangeWool, + MagentaWool, + LightBlueWool, + YellowWool, + LimeWool, + PinkWool, + GrayWool, + LightGrayWool, + CyanWool, + PurpleWool, + BlueWool, + BrownWool, + GreenWool, + RedWool, + BlackWool, + MovingPiston, + Dandelion, + Poppy, + BlueOrchid, + Allium, + AzureBluet, + RedTulip, + OrangeTulip, + WhiteTulip, + PinkTulip, + OxeyeDaisy, + Cornflower, + WitherRose, + LilyOfTheValley, + BrownMushroom, + RedMushroom, + GoldBlock, + IronBlock, + Bricks, + Tnt, + Bookshelf, + MossyCobblestone, + Obsidian, + Torch, + WallTorch, + Fire, + SoulFire, + Spawner, + OakStairs, + Chest, + RedstoneWire, + DiamondOre, + DiamondBlock, + CraftingTable, + Wheat, + Farmland, + Furnace, + OakSign, + SpruceSign, + BirchSign, + AcaciaSign, + JungleSign, + DarkOakSign, + OakDoor, + Ladder, + Rail, + CobblestoneStairs, + OakWallSign, + SpruceWallSign, + BirchWallSign, + AcaciaWallSign, + JungleWallSign, + DarkOakWallSign, + Lever, + StonePressurePlate, + IronDoor, + OakPressurePlate, + SprucePressurePlate, + BirchPressurePlate, + JunglePressurePlate, + AcaciaPressurePlate, + DarkOakPressurePlate, + RedstoneOre, + RedstoneTorch, + RedstoneWallTorch, + StoneButton, + Snow, + Ice, + SnowBlock, + Cactus, + Clay, + SugarCane, + Jukebox, + OakFence, + Pumpkin, + Netherrack, + SoulSand, + SoulSoil, + Basalt, + PolishedBasalt, + SoulTorch, + SoulWallTorch, + Glowstone, + NetherPortal, + CarvedPumpkin, + JackOLantern, + Cake, + Repeater, + WhiteStainedGlass, + OrangeStainedGlass, + MagentaStainedGlass, + LightBlueStainedGlass, + YellowStainedGlass, + LimeStainedGlass, + PinkStainedGlass, + GrayStainedGlass, + LightGrayStainedGlass, + CyanStainedGlass, + PurpleStainedGlass, + BlueStainedGlass, + BrownStainedGlass, + GreenStainedGlass, + RedStainedGlass, + BlackStainedGlass, + OakTrapdoor, + SpruceTrapdoor, + BirchTrapdoor, + JungleTrapdoor, + AcaciaTrapdoor, + DarkOakTrapdoor, + StoneBricks, + MossyStoneBricks, + CrackedStoneBricks, + ChiseledStoneBricks, + InfestedStone, + InfestedCobblestone, + InfestedStoneBricks, + InfestedMossyStoneBricks, + InfestedCrackedStoneBricks, + InfestedChiseledStoneBricks, + BrownMushroomBlock, + RedMushroomBlock, + MushroomStem, + IronBars, + Chain, + GlassPane, + Melon, + AttachedPumpkinStem, + AttachedMelonStem, + PumpkinStem, + MelonStem, + Vine, + OakFenceGate, + BrickStairs, + StoneBrickStairs, + Mycelium, + LilyPad, + NetherBricks, + NetherBrickFence, + NetherBrickStairs, + NetherWart, + EnchantingTable, + BrewingStand, + Cauldron, + EndPortal, + EndPortalFrame, + EndStone, + DragonEgg, + RedstoneLamp, + Cocoa, + SandstoneStairs, + EmeraldOre, + EnderChest, + TripwireHook, + Tripwire, + EmeraldBlock, + SpruceStairs, + BirchStairs, + JungleStairs, + CommandBlock, + Beacon, + CobblestoneWall, + MossyCobblestoneWall, + FlowerPot, + PottedOakSapling, + PottedSpruceSapling, + PottedBirchSapling, + PottedJungleSapling, + PottedAcaciaSapling, + PottedDarkOakSapling, + PottedFern, + PottedDandelion, + PottedPoppy, + PottedBlueOrchid, + PottedAllium, + PottedAzureBluet, + PottedRedTulip, + PottedOrangeTulip, + PottedWhiteTulip, + PottedPinkTulip, + PottedOxeyeDaisy, + PottedCornflower, + PottedLilyOfTheValley, + PottedWitherRose, + PottedRedMushroom, + PottedBrownMushroom, + PottedDeadBush, + PottedCactus, + Carrots, + Potatoes, + OakButton, + SpruceButton, + BirchButton, + JungleButton, + AcaciaButton, + DarkOakButton, + SkeletonSkull, + SkeletonWallSkull, + WitherSkeletonSkull, + WitherSkeletonWallSkull, + ZombieHead, + ZombieWallHead, + PlayerHead, + PlayerWallHead, + CreeperHead, + CreeperWallHead, + DragonHead, + DragonWallHead, + Anvil, + ChippedAnvil, + DamagedAnvil, + TrappedChest, + LightWeightedPressurePlate, + HeavyWeightedPressurePlate, + Comparator, + DaylightDetector, + RedstoneBlock, + NetherQuartzOre, + Hopper, + QuartzBlock, + ChiseledQuartzBlock, + QuartzPillar, + QuartzStairs, + ActivatorRail, + Dropper, + WhiteTerracotta, + OrangeTerracotta, + MagentaTerracotta, + LightBlueTerracotta, + YellowTerracotta, + LimeTerracotta, + PinkTerracotta, + GrayTerracotta, + LightGrayTerracotta, + CyanTerracotta, + PurpleTerracotta, + BlueTerracotta, + BrownTerracotta, + GreenTerracotta, + RedTerracotta, + BlackTerracotta, + WhiteStainedGlassPane, + OrangeStainedGlassPane, + MagentaStainedGlassPane, + LightBlueStainedGlassPane, + YellowStainedGlassPane, + LimeStainedGlassPane, + PinkStainedGlassPane, + GrayStainedGlassPane, + LightGrayStainedGlassPane, + CyanStainedGlassPane, + PurpleStainedGlassPane, + BlueStainedGlassPane, + BrownStainedGlassPane, + GreenStainedGlassPane, + RedStainedGlassPane, + BlackStainedGlassPane, + AcaciaStairs, + DarkOakStairs, + SlimeBlock, + Barrier, + IronTrapdoor, + Prismarine, + PrismarineBricks, + DarkPrismarine, + PrismarineStairs, + PrismarineBrickStairs, + DarkPrismarineStairs, + PrismarineSlab, + PrismarineBrickSlab, + DarkPrismarineSlab, + SeaLantern, + HayBlock, + WhiteCarpet, + OrangeCarpet, + MagentaCarpet, + LightBlueCarpet, + YellowCarpet, + LimeCarpet, + PinkCarpet, + GrayCarpet, + LightGrayCarpet, + CyanCarpet, + PurpleCarpet, + BlueCarpet, + BrownCarpet, + GreenCarpet, + RedCarpet, + BlackCarpet, + Terracotta, + CoalBlock, + PackedIce, + Sunflower, + Lilac, + RoseBush, + Peony, + TallGrass, + LargeFern, + WhiteBanner, + OrangeBanner, + MagentaBanner, + LightBlueBanner, + YellowBanner, + LimeBanner, + PinkBanner, + GrayBanner, + LightGrayBanner, + CyanBanner, + PurpleBanner, + BlueBanner, + BrownBanner, + GreenBanner, + RedBanner, + BlackBanner, + WhiteWallBanner, + OrangeWallBanner, + MagentaWallBanner, + LightBlueWallBanner, + YellowWallBanner, + LimeWallBanner, + PinkWallBanner, + GrayWallBanner, + LightGrayWallBanner, + CyanWallBanner, + PurpleWallBanner, + BlueWallBanner, + BrownWallBanner, + GreenWallBanner, + RedWallBanner, + BlackWallBanner, + RedSandstone, + ChiseledRedSandstone, + CutRedSandstone, + RedSandstoneStairs, + OakSlab, + SpruceSlab, + BirchSlab, + JungleSlab, + AcaciaSlab, + DarkOakSlab, + StoneSlab, + SmoothStoneSlab, + SandstoneSlab, + CutSandstoneSlab, + PetrifiedOakSlab, + CobblestoneSlab, + BrickSlab, + StoneBrickSlab, + NetherBrickSlab, + QuartzSlab, + RedSandstoneSlab, + CutRedSandstoneSlab, + PurpurSlab, + SmoothStone, + SmoothSandstone, + SmoothQuartz, + SmoothRedSandstone, + SpruceFenceGate, + BirchFenceGate, + JungleFenceGate, + AcaciaFenceGate, + DarkOakFenceGate, + SpruceFence, + BirchFence, + JungleFence, + AcaciaFence, + DarkOakFence, + SpruceDoor, + BirchDoor, + JungleDoor, + AcaciaDoor, + DarkOakDoor, + EndRod, + ChorusPlant, + ChorusFlower, + PurpurBlock, + PurpurPillar, + PurpurStairs, + EndStoneBricks, + Beetroots, + GrassPath, + EndGateway, + RepeatingCommandBlock, + ChainCommandBlock, + FrostedIce, + MagmaBlock, + NetherWartBlock, + RedNetherBricks, + BoneBlock, + StructureVoid, + Observer, + ShulkerBox, + WhiteShulkerBox, + OrangeShulkerBox, + MagentaShulkerBox, + LightBlueShulkerBox, + YellowShulkerBox, + LimeShulkerBox, + PinkShulkerBox, + GrayShulkerBox, + LightGrayShulkerBox, + CyanShulkerBox, + PurpleShulkerBox, + BlueShulkerBox, + BrownShulkerBox, + GreenShulkerBox, + RedShulkerBox, + BlackShulkerBox, + WhiteGlazedTerracotta, + OrangeGlazedTerracotta, + MagentaGlazedTerracotta, + LightBlueGlazedTerracotta, + YellowGlazedTerracotta, + LimeGlazedTerracotta, + PinkGlazedTerracotta, + GrayGlazedTerracotta, + LightGrayGlazedTerracotta, + CyanGlazedTerracotta, + PurpleGlazedTerracotta, + BlueGlazedTerracotta, + BrownGlazedTerracotta, + GreenGlazedTerracotta, + RedGlazedTerracotta, + BlackGlazedTerracotta, + WhiteConcrete, + OrangeConcrete, + MagentaConcrete, + LightBlueConcrete, + YellowConcrete, + LimeConcrete, + PinkConcrete, + GrayConcrete, + LightGrayConcrete, + CyanConcrete, + PurpleConcrete, + BlueConcrete, + BrownConcrete, + GreenConcrete, + RedConcrete, + BlackConcrete, + WhiteConcretePowder, + OrangeConcretePowder, + MagentaConcretePowder, + LightBlueConcretePowder, + YellowConcretePowder, + LimeConcretePowder, + PinkConcretePowder, + GrayConcretePowder, + LightGrayConcretePowder, + CyanConcretePowder, + PurpleConcretePowder, + BlueConcretePowder, + BrownConcretePowder, + GreenConcretePowder, + RedConcretePowder, + BlackConcretePowder, + Kelp, + KelpPlant, + DriedKelpBlock, + TurtleEgg, + DeadTubeCoralBlock, + DeadBrainCoralBlock, + DeadBubbleCoralBlock, + DeadFireCoralBlock, + DeadHornCoralBlock, + TubeCoralBlock, + BrainCoralBlock, + BubbleCoralBlock, + FireCoralBlock, + HornCoralBlock, + DeadTubeCoral, + DeadBrainCoral, + DeadBubbleCoral, + DeadFireCoral, + DeadHornCoral, + TubeCoral, + BrainCoral, + BubbleCoral, + FireCoral, + HornCoral, + DeadTubeCoralFan, + DeadBrainCoralFan, + DeadBubbleCoralFan, + DeadFireCoralFan, + DeadHornCoralFan, + TubeCoralFan, + BrainCoralFan, + BubbleCoralFan, + FireCoralFan, + HornCoralFan, + DeadTubeCoralWallFan, + DeadBrainCoralWallFan, + DeadBubbleCoralWallFan, + DeadFireCoralWallFan, + DeadHornCoralWallFan, + TubeCoralWallFan, + BrainCoralWallFan, + BubbleCoralWallFan, + FireCoralWallFan, + HornCoralWallFan, + SeaPickle, + BlueIce, + Conduit, + BambooSapling, + Bamboo, + PottedBamboo, + VoidAir, + CaveAir, + BubbleColumn, + PolishedGraniteStairs, + SmoothRedSandstoneStairs, + MossyStoneBrickStairs, + PolishedDioriteStairs, + MossyCobblestoneStairs, + EndStoneBrickStairs, + StoneStairs, + SmoothSandstoneStairs, + SmoothQuartzStairs, + GraniteStairs, + AndesiteStairs, + RedNetherBrickStairs, + PolishedAndesiteStairs, + DioriteStairs, + PolishedGraniteSlab, + SmoothRedSandstoneSlab, + MossyStoneBrickSlab, + PolishedDioriteSlab, + MossyCobblestoneSlab, + EndStoneBrickSlab, + SmoothSandstoneSlab, + SmoothQuartzSlab, + GraniteSlab, + AndesiteSlab, + RedNetherBrickSlab, + PolishedAndesiteSlab, + DioriteSlab, + BrickWall, + PrismarineWall, + RedSandstoneWall, + MossyStoneBrickWall, + GraniteWall, + StoneBrickWall, + NetherBrickWall, + AndesiteWall, + RedNetherBrickWall, + SandstoneWall, + EndStoneBrickWall, + DioriteWall, + Scaffolding, + Loom, + Barrel, + Smoker, + BlastFurnace, + CartographyTable, + FletchingTable, + Grindstone, + Lectern, + SmithingTable, + Stonecutter, + Bell, + Lantern, + SoulLantern, + Campfire, + SoulCampfire, + SweetBerryBush, + WarpedStem, + StrippedWarpedStem, + WarpedHyphae, + StrippedWarpedHyphae, + WarpedNylium, + WarpedFungus, + WarpedWartBlock, + WarpedRoots, + NetherSprouts, + CrimsonStem, + StrippedCrimsonStem, + CrimsonHyphae, + StrippedCrimsonHyphae, + CrimsonNylium, + CrimsonFungus, + Shroomlight, + WeepingVines, + WeepingVinesPlant, + TwistingVines, + TwistingVinesPlant, + CrimsonRoots, + CrimsonPlanks, + WarpedPlanks, + CrimsonSlab, + WarpedSlab, + CrimsonPressurePlate, + WarpedPressurePlate, + CrimsonFence, + WarpedFence, + CrimsonTrapdoor, + WarpedTrapdoor, + CrimsonFenceGate, + WarpedFenceGate, + CrimsonStairs, + WarpedStairs, + CrimsonButton, + WarpedButton, + CrimsonDoor, + WarpedDoor, + CrimsonSign, + WarpedSign, + CrimsonWallSign, + WarpedWallSign, + StructureBlock, + Jigsaw, + Composter, + Target, + BeeNest, + Beehive, + HoneyBlock, + HoneycombBlock, + NetheriteBlock, + AncientDebris, + CryingObsidian, + RespawnAnchor, + PottedCrimsonFungus, + PottedWarpedFungus, + PottedCrimsonRoots, + PottedWarpedRoots, + Lodestone, + Blackstone, + BlackstoneStairs, + BlackstoneWall, + BlackstoneSlab, + PolishedBlackstone, + PolishedBlackstoneBricks, + CrackedPolishedBlackstoneBricks, + ChiseledPolishedBlackstone, + PolishedBlackstoneBrickSlab, + PolishedBlackstoneBrickStairs, + PolishedBlackstoneBrickWall, + GildedBlackstone, + PolishedBlackstoneStairs, + PolishedBlackstoneSlab, + PolishedBlackstonePressurePlate, + PolishedBlackstoneButton, + PolishedBlackstoneWall, + ChiseledNetherBricks, + CrackedNetherBricks, + QuartzBricks, +} + +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `id` property of this `BlockKind`. + pub fn id(&self) -> u32 { + match self { + BlockKind::Air => 0, + BlockKind::Stone => 1, + BlockKind::Granite => 2, + BlockKind::PolishedGranite => 3, + BlockKind::Diorite => 4, + BlockKind::PolishedDiorite => 5, + BlockKind::Andesite => 6, + BlockKind::PolishedAndesite => 7, + BlockKind::GrassBlock => 8, + BlockKind::Dirt => 9, + BlockKind::CoarseDirt => 10, + BlockKind::Podzol => 11, + BlockKind::Cobblestone => 12, + BlockKind::OakPlanks => 13, + BlockKind::SprucePlanks => 14, + BlockKind::BirchPlanks => 15, + BlockKind::JunglePlanks => 16, + BlockKind::AcaciaPlanks => 17, + BlockKind::DarkOakPlanks => 18, + BlockKind::OakSapling => 19, + BlockKind::SpruceSapling => 20, + BlockKind::BirchSapling => 21, + BlockKind::JungleSapling => 22, + BlockKind::AcaciaSapling => 23, + BlockKind::DarkOakSapling => 24, + BlockKind::Bedrock => 25, + BlockKind::Water => 26, + BlockKind::Lava => 27, + BlockKind::Sand => 28, + BlockKind::RedSand => 29, + BlockKind::Gravel => 30, + BlockKind::GoldOre => 31, + BlockKind::IronOre => 32, + BlockKind::CoalOre => 33, + BlockKind::NetherGoldOre => 34, + BlockKind::OakLog => 35, + BlockKind::SpruceLog => 36, + BlockKind::BirchLog => 37, + BlockKind::JungleLog => 38, + BlockKind::AcaciaLog => 39, + BlockKind::DarkOakLog => 40, + BlockKind::StrippedSpruceLog => 41, + BlockKind::StrippedBirchLog => 42, + BlockKind::StrippedJungleLog => 43, + BlockKind::StrippedAcaciaLog => 44, + BlockKind::StrippedDarkOakLog => 45, + BlockKind::StrippedOakLog => 46, + BlockKind::OakWood => 47, + BlockKind::SpruceWood => 48, + BlockKind::BirchWood => 49, + BlockKind::JungleWood => 50, + BlockKind::AcaciaWood => 51, + BlockKind::DarkOakWood => 52, + BlockKind::StrippedOakWood => 53, + BlockKind::StrippedSpruceWood => 54, + BlockKind::StrippedBirchWood => 55, + BlockKind::StrippedJungleWood => 56, + BlockKind::StrippedAcaciaWood => 57, + BlockKind::StrippedDarkOakWood => 58, + BlockKind::OakLeaves => 59, + BlockKind::SpruceLeaves => 60, + BlockKind::BirchLeaves => 61, + BlockKind::JungleLeaves => 62, + BlockKind::AcaciaLeaves => 63, + BlockKind::DarkOakLeaves => 64, + BlockKind::Sponge => 65, + BlockKind::WetSponge => 66, + BlockKind::Glass => 67, + BlockKind::LapisOre => 68, + BlockKind::LapisBlock => 69, + BlockKind::Dispenser => 70, + BlockKind::Sandstone => 71, + BlockKind::ChiseledSandstone => 72, + BlockKind::CutSandstone => 73, + BlockKind::NoteBlock => 74, + BlockKind::WhiteBed => 75, + BlockKind::OrangeBed => 76, + BlockKind::MagentaBed => 77, + BlockKind::LightBlueBed => 78, + BlockKind::YellowBed => 79, + BlockKind::LimeBed => 80, + BlockKind::PinkBed => 81, + BlockKind::GrayBed => 82, + BlockKind::LightGrayBed => 83, + BlockKind::CyanBed => 84, + BlockKind::PurpleBed => 85, + BlockKind::BlueBed => 86, + BlockKind::BrownBed => 87, + BlockKind::GreenBed => 88, + BlockKind::RedBed => 89, + BlockKind::BlackBed => 90, + BlockKind::PoweredRail => 91, + BlockKind::DetectorRail => 92, + BlockKind::StickyPiston => 93, + BlockKind::Cobweb => 94, + BlockKind::Grass => 95, + BlockKind::Fern => 96, + BlockKind::DeadBush => 97, + BlockKind::Seagrass => 98, + BlockKind::TallSeagrass => 99, + BlockKind::Piston => 100, + BlockKind::PistonHead => 101, + BlockKind::WhiteWool => 102, + BlockKind::OrangeWool => 103, + BlockKind::MagentaWool => 104, + BlockKind::LightBlueWool => 105, + BlockKind::YellowWool => 106, + BlockKind::LimeWool => 107, + BlockKind::PinkWool => 108, + BlockKind::GrayWool => 109, + BlockKind::LightGrayWool => 110, + BlockKind::CyanWool => 111, + BlockKind::PurpleWool => 112, + BlockKind::BlueWool => 113, + BlockKind::BrownWool => 114, + BlockKind::GreenWool => 115, + BlockKind::RedWool => 116, + BlockKind::BlackWool => 117, + BlockKind::MovingPiston => 118, + BlockKind::Dandelion => 119, + BlockKind::Poppy => 120, + BlockKind::BlueOrchid => 121, + BlockKind::Allium => 122, + BlockKind::AzureBluet => 123, + BlockKind::RedTulip => 124, + BlockKind::OrangeTulip => 125, + BlockKind::WhiteTulip => 126, + BlockKind::PinkTulip => 127, + BlockKind::OxeyeDaisy => 128, + BlockKind::Cornflower => 129, + BlockKind::WitherRose => 130, + BlockKind::LilyOfTheValley => 131, + BlockKind::BrownMushroom => 132, + BlockKind::RedMushroom => 133, + BlockKind::GoldBlock => 134, + BlockKind::IronBlock => 135, + BlockKind::Bricks => 136, + BlockKind::Tnt => 137, + BlockKind::Bookshelf => 138, + BlockKind::MossyCobblestone => 139, + BlockKind::Obsidian => 140, + BlockKind::Torch => 141, + BlockKind::WallTorch => 142, + BlockKind::Fire => 143, + BlockKind::SoulFire => 144, + BlockKind::Spawner => 145, + BlockKind::OakStairs => 146, + BlockKind::Chest => 147, + BlockKind::RedstoneWire => 148, + BlockKind::DiamondOre => 149, + BlockKind::DiamondBlock => 150, + BlockKind::CraftingTable => 151, + BlockKind::Wheat => 152, + BlockKind::Farmland => 153, + BlockKind::Furnace => 154, + BlockKind::OakSign => 155, + BlockKind::SpruceSign => 156, + BlockKind::BirchSign => 157, + BlockKind::AcaciaSign => 158, + BlockKind::JungleSign => 159, + BlockKind::DarkOakSign => 160, + BlockKind::OakDoor => 161, + BlockKind::Ladder => 162, + BlockKind::Rail => 163, + BlockKind::CobblestoneStairs => 164, + BlockKind::OakWallSign => 165, + BlockKind::SpruceWallSign => 166, + BlockKind::BirchWallSign => 167, + BlockKind::AcaciaWallSign => 168, + BlockKind::JungleWallSign => 169, + BlockKind::DarkOakWallSign => 170, + BlockKind::Lever => 171, + BlockKind::StonePressurePlate => 172, + BlockKind::IronDoor => 173, + BlockKind::OakPressurePlate => 174, + BlockKind::SprucePressurePlate => 175, + BlockKind::BirchPressurePlate => 176, + BlockKind::JunglePressurePlate => 177, + BlockKind::AcaciaPressurePlate => 178, + BlockKind::DarkOakPressurePlate => 179, + BlockKind::RedstoneOre => 180, + BlockKind::RedstoneTorch => 181, + BlockKind::RedstoneWallTorch => 182, + BlockKind::StoneButton => 183, + BlockKind::Snow => 184, + BlockKind::Ice => 185, + BlockKind::SnowBlock => 186, + BlockKind::Cactus => 187, + BlockKind::Clay => 188, + BlockKind::SugarCane => 189, + BlockKind::Jukebox => 190, + BlockKind::OakFence => 191, + BlockKind::Pumpkin => 192, + BlockKind::Netherrack => 193, + BlockKind::SoulSand => 194, + BlockKind::SoulSoil => 195, + BlockKind::Basalt => 196, + BlockKind::PolishedBasalt => 197, + BlockKind::SoulTorch => 198, + BlockKind::SoulWallTorch => 199, + BlockKind::Glowstone => 200, + BlockKind::NetherPortal => 201, + BlockKind::CarvedPumpkin => 202, + BlockKind::JackOLantern => 203, + BlockKind::Cake => 204, + BlockKind::Repeater => 205, + BlockKind::WhiteStainedGlass => 206, + BlockKind::OrangeStainedGlass => 207, + BlockKind::MagentaStainedGlass => 208, + BlockKind::LightBlueStainedGlass => 209, + BlockKind::YellowStainedGlass => 210, + BlockKind::LimeStainedGlass => 211, + BlockKind::PinkStainedGlass => 212, + BlockKind::GrayStainedGlass => 213, + BlockKind::LightGrayStainedGlass => 214, + BlockKind::CyanStainedGlass => 215, + BlockKind::PurpleStainedGlass => 216, + BlockKind::BlueStainedGlass => 217, + BlockKind::BrownStainedGlass => 218, + BlockKind::GreenStainedGlass => 219, + BlockKind::RedStainedGlass => 220, + BlockKind::BlackStainedGlass => 221, + BlockKind::OakTrapdoor => 222, + BlockKind::SpruceTrapdoor => 223, + BlockKind::BirchTrapdoor => 224, + BlockKind::JungleTrapdoor => 225, + BlockKind::AcaciaTrapdoor => 226, + BlockKind::DarkOakTrapdoor => 227, + BlockKind::StoneBricks => 228, + BlockKind::MossyStoneBricks => 229, + BlockKind::CrackedStoneBricks => 230, + BlockKind::ChiseledStoneBricks => 231, + BlockKind::InfestedStone => 232, + BlockKind::InfestedCobblestone => 233, + BlockKind::InfestedStoneBricks => 234, + BlockKind::InfestedMossyStoneBricks => 235, + BlockKind::InfestedCrackedStoneBricks => 236, + BlockKind::InfestedChiseledStoneBricks => 237, + BlockKind::BrownMushroomBlock => 238, + BlockKind::RedMushroomBlock => 239, + BlockKind::MushroomStem => 240, + BlockKind::IronBars => 241, + BlockKind::Chain => 242, + BlockKind::GlassPane => 243, + BlockKind::Melon => 244, + BlockKind::AttachedPumpkinStem => 245, + BlockKind::AttachedMelonStem => 246, + BlockKind::PumpkinStem => 247, + BlockKind::MelonStem => 248, + BlockKind::Vine => 249, + BlockKind::OakFenceGate => 250, + BlockKind::BrickStairs => 251, + BlockKind::StoneBrickStairs => 252, + BlockKind::Mycelium => 253, + BlockKind::LilyPad => 254, + BlockKind::NetherBricks => 255, + BlockKind::NetherBrickFence => 256, + BlockKind::NetherBrickStairs => 257, + BlockKind::NetherWart => 258, + BlockKind::EnchantingTable => 259, + BlockKind::BrewingStand => 260, + BlockKind::Cauldron => 261, + BlockKind::EndPortal => 262, + BlockKind::EndPortalFrame => 263, + BlockKind::EndStone => 264, + BlockKind::DragonEgg => 265, + BlockKind::RedstoneLamp => 266, + BlockKind::Cocoa => 267, + BlockKind::SandstoneStairs => 268, + BlockKind::EmeraldOre => 269, + BlockKind::EnderChest => 270, + BlockKind::TripwireHook => 271, + BlockKind::Tripwire => 272, + BlockKind::EmeraldBlock => 273, + BlockKind::SpruceStairs => 274, + BlockKind::BirchStairs => 275, + BlockKind::JungleStairs => 276, + BlockKind::CommandBlock => 277, + BlockKind::Beacon => 278, + BlockKind::CobblestoneWall => 279, + BlockKind::MossyCobblestoneWall => 280, + BlockKind::FlowerPot => 281, + BlockKind::PottedOakSapling => 282, + BlockKind::PottedSpruceSapling => 283, + BlockKind::PottedBirchSapling => 284, + BlockKind::PottedJungleSapling => 285, + BlockKind::PottedAcaciaSapling => 286, + BlockKind::PottedDarkOakSapling => 287, + BlockKind::PottedFern => 288, + BlockKind::PottedDandelion => 289, + BlockKind::PottedPoppy => 290, + BlockKind::PottedBlueOrchid => 291, + BlockKind::PottedAllium => 292, + BlockKind::PottedAzureBluet => 293, + BlockKind::PottedRedTulip => 294, + BlockKind::PottedOrangeTulip => 295, + BlockKind::PottedWhiteTulip => 296, + BlockKind::PottedPinkTulip => 297, + BlockKind::PottedOxeyeDaisy => 298, + BlockKind::PottedCornflower => 299, + BlockKind::PottedLilyOfTheValley => 300, + BlockKind::PottedWitherRose => 301, + BlockKind::PottedRedMushroom => 302, + BlockKind::PottedBrownMushroom => 303, + BlockKind::PottedDeadBush => 304, + BlockKind::PottedCactus => 305, + BlockKind::Carrots => 306, + BlockKind::Potatoes => 307, + BlockKind::OakButton => 308, + BlockKind::SpruceButton => 309, + BlockKind::BirchButton => 310, + BlockKind::JungleButton => 311, + BlockKind::AcaciaButton => 312, + BlockKind::DarkOakButton => 313, + BlockKind::SkeletonSkull => 314, + BlockKind::SkeletonWallSkull => 315, + BlockKind::WitherSkeletonSkull => 316, + BlockKind::WitherSkeletonWallSkull => 317, + BlockKind::ZombieHead => 318, + BlockKind::ZombieWallHead => 319, + BlockKind::PlayerHead => 320, + BlockKind::PlayerWallHead => 321, + BlockKind::CreeperHead => 322, + BlockKind::CreeperWallHead => 323, + BlockKind::DragonHead => 324, + BlockKind::DragonWallHead => 325, + BlockKind::Anvil => 326, + BlockKind::ChippedAnvil => 327, + BlockKind::DamagedAnvil => 328, + BlockKind::TrappedChest => 329, + BlockKind::LightWeightedPressurePlate => 330, + BlockKind::HeavyWeightedPressurePlate => 331, + BlockKind::Comparator => 332, + BlockKind::DaylightDetector => 333, + BlockKind::RedstoneBlock => 334, + BlockKind::NetherQuartzOre => 335, + BlockKind::Hopper => 336, + BlockKind::QuartzBlock => 337, + BlockKind::ChiseledQuartzBlock => 338, + BlockKind::QuartzPillar => 339, + BlockKind::QuartzStairs => 340, + BlockKind::ActivatorRail => 341, + BlockKind::Dropper => 342, + BlockKind::WhiteTerracotta => 343, + BlockKind::OrangeTerracotta => 344, + BlockKind::MagentaTerracotta => 345, + BlockKind::LightBlueTerracotta => 346, + BlockKind::YellowTerracotta => 347, + BlockKind::LimeTerracotta => 348, + BlockKind::PinkTerracotta => 349, + BlockKind::GrayTerracotta => 350, + BlockKind::LightGrayTerracotta => 351, + BlockKind::CyanTerracotta => 352, + BlockKind::PurpleTerracotta => 353, + BlockKind::BlueTerracotta => 354, + BlockKind::BrownTerracotta => 355, + BlockKind::GreenTerracotta => 356, + BlockKind::RedTerracotta => 357, + BlockKind::BlackTerracotta => 358, + BlockKind::WhiteStainedGlassPane => 359, + BlockKind::OrangeStainedGlassPane => 360, + BlockKind::MagentaStainedGlassPane => 361, + BlockKind::LightBlueStainedGlassPane => 362, + BlockKind::YellowStainedGlassPane => 363, + BlockKind::LimeStainedGlassPane => 364, + BlockKind::PinkStainedGlassPane => 365, + BlockKind::GrayStainedGlassPane => 366, + BlockKind::LightGrayStainedGlassPane => 367, + BlockKind::CyanStainedGlassPane => 368, + BlockKind::PurpleStainedGlassPane => 369, + BlockKind::BlueStainedGlassPane => 370, + BlockKind::BrownStainedGlassPane => 371, + BlockKind::GreenStainedGlassPane => 372, + BlockKind::RedStainedGlassPane => 373, + BlockKind::BlackStainedGlassPane => 374, + BlockKind::AcaciaStairs => 375, + BlockKind::DarkOakStairs => 376, + BlockKind::SlimeBlock => 377, + BlockKind::Barrier => 378, + BlockKind::IronTrapdoor => 379, + BlockKind::Prismarine => 380, + BlockKind::PrismarineBricks => 381, + BlockKind::DarkPrismarine => 382, + BlockKind::PrismarineStairs => 383, + BlockKind::PrismarineBrickStairs => 384, + BlockKind::DarkPrismarineStairs => 385, + BlockKind::PrismarineSlab => 386, + BlockKind::PrismarineBrickSlab => 387, + BlockKind::DarkPrismarineSlab => 388, + BlockKind::SeaLantern => 389, + BlockKind::HayBlock => 390, + BlockKind::WhiteCarpet => 391, + BlockKind::OrangeCarpet => 392, + BlockKind::MagentaCarpet => 393, + BlockKind::LightBlueCarpet => 394, + BlockKind::YellowCarpet => 395, + BlockKind::LimeCarpet => 396, + BlockKind::PinkCarpet => 397, + BlockKind::GrayCarpet => 398, + BlockKind::LightGrayCarpet => 399, + BlockKind::CyanCarpet => 400, + BlockKind::PurpleCarpet => 401, + BlockKind::BlueCarpet => 402, + BlockKind::BrownCarpet => 403, + BlockKind::GreenCarpet => 404, + BlockKind::RedCarpet => 405, + BlockKind::BlackCarpet => 406, + BlockKind::Terracotta => 407, + BlockKind::CoalBlock => 408, + BlockKind::PackedIce => 409, + BlockKind::Sunflower => 410, + BlockKind::Lilac => 411, + BlockKind::RoseBush => 412, + BlockKind::Peony => 413, + BlockKind::TallGrass => 414, + BlockKind::LargeFern => 415, + BlockKind::WhiteBanner => 416, + BlockKind::OrangeBanner => 417, + BlockKind::MagentaBanner => 418, + BlockKind::LightBlueBanner => 419, + BlockKind::YellowBanner => 420, + BlockKind::LimeBanner => 421, + BlockKind::PinkBanner => 422, + BlockKind::GrayBanner => 423, + BlockKind::LightGrayBanner => 424, + BlockKind::CyanBanner => 425, + BlockKind::PurpleBanner => 426, + BlockKind::BlueBanner => 427, + BlockKind::BrownBanner => 428, + BlockKind::GreenBanner => 429, + BlockKind::RedBanner => 430, + BlockKind::BlackBanner => 431, + BlockKind::WhiteWallBanner => 432, + BlockKind::OrangeWallBanner => 433, + BlockKind::MagentaWallBanner => 434, + BlockKind::LightBlueWallBanner => 435, + BlockKind::YellowWallBanner => 436, + BlockKind::LimeWallBanner => 437, + BlockKind::PinkWallBanner => 438, + BlockKind::GrayWallBanner => 439, + BlockKind::LightGrayWallBanner => 440, + BlockKind::CyanWallBanner => 441, + BlockKind::PurpleWallBanner => 442, + BlockKind::BlueWallBanner => 443, + BlockKind::BrownWallBanner => 444, + BlockKind::GreenWallBanner => 445, + BlockKind::RedWallBanner => 446, + BlockKind::BlackWallBanner => 447, + BlockKind::RedSandstone => 448, + BlockKind::ChiseledRedSandstone => 449, + BlockKind::CutRedSandstone => 450, + BlockKind::RedSandstoneStairs => 451, + BlockKind::OakSlab => 452, + BlockKind::SpruceSlab => 453, + BlockKind::BirchSlab => 454, + BlockKind::JungleSlab => 455, + BlockKind::AcaciaSlab => 456, + BlockKind::DarkOakSlab => 457, + BlockKind::StoneSlab => 458, + BlockKind::SmoothStoneSlab => 459, + BlockKind::SandstoneSlab => 460, + BlockKind::CutSandstoneSlab => 461, + BlockKind::PetrifiedOakSlab => 462, + BlockKind::CobblestoneSlab => 463, + BlockKind::BrickSlab => 464, + BlockKind::StoneBrickSlab => 465, + BlockKind::NetherBrickSlab => 466, + BlockKind::QuartzSlab => 467, + BlockKind::RedSandstoneSlab => 468, + BlockKind::CutRedSandstoneSlab => 469, + BlockKind::PurpurSlab => 470, + BlockKind::SmoothStone => 471, + BlockKind::SmoothSandstone => 472, + BlockKind::SmoothQuartz => 473, + BlockKind::SmoothRedSandstone => 474, + BlockKind::SpruceFenceGate => 475, + BlockKind::BirchFenceGate => 476, + BlockKind::JungleFenceGate => 477, + BlockKind::AcaciaFenceGate => 478, + BlockKind::DarkOakFenceGate => 479, + BlockKind::SpruceFence => 480, + BlockKind::BirchFence => 481, + BlockKind::JungleFence => 482, + BlockKind::AcaciaFence => 483, + BlockKind::DarkOakFence => 484, + BlockKind::SpruceDoor => 485, + BlockKind::BirchDoor => 486, + BlockKind::JungleDoor => 487, + BlockKind::AcaciaDoor => 488, + BlockKind::DarkOakDoor => 489, + BlockKind::EndRod => 490, + BlockKind::ChorusPlant => 491, + BlockKind::ChorusFlower => 492, + BlockKind::PurpurBlock => 493, + BlockKind::PurpurPillar => 494, + BlockKind::PurpurStairs => 495, + BlockKind::EndStoneBricks => 496, + BlockKind::Beetroots => 497, + BlockKind::GrassPath => 498, + BlockKind::EndGateway => 499, + BlockKind::RepeatingCommandBlock => 500, + BlockKind::ChainCommandBlock => 501, + BlockKind::FrostedIce => 502, + BlockKind::MagmaBlock => 503, + BlockKind::NetherWartBlock => 504, + BlockKind::RedNetherBricks => 505, + BlockKind::BoneBlock => 506, + BlockKind::StructureVoid => 507, + BlockKind::Observer => 508, + BlockKind::ShulkerBox => 509, + BlockKind::WhiteShulkerBox => 510, + BlockKind::OrangeShulkerBox => 511, + BlockKind::MagentaShulkerBox => 512, + BlockKind::LightBlueShulkerBox => 513, + BlockKind::YellowShulkerBox => 514, + BlockKind::LimeShulkerBox => 515, + BlockKind::PinkShulkerBox => 516, + BlockKind::GrayShulkerBox => 517, + BlockKind::LightGrayShulkerBox => 518, + BlockKind::CyanShulkerBox => 519, + BlockKind::PurpleShulkerBox => 520, + BlockKind::BlueShulkerBox => 521, + BlockKind::BrownShulkerBox => 522, + BlockKind::GreenShulkerBox => 523, + BlockKind::RedShulkerBox => 524, + BlockKind::BlackShulkerBox => 525, + BlockKind::WhiteGlazedTerracotta => 526, + BlockKind::OrangeGlazedTerracotta => 527, + BlockKind::MagentaGlazedTerracotta => 528, + BlockKind::LightBlueGlazedTerracotta => 529, + BlockKind::YellowGlazedTerracotta => 530, + BlockKind::LimeGlazedTerracotta => 531, + BlockKind::PinkGlazedTerracotta => 532, + BlockKind::GrayGlazedTerracotta => 533, + BlockKind::LightGrayGlazedTerracotta => 534, + BlockKind::CyanGlazedTerracotta => 535, + BlockKind::PurpleGlazedTerracotta => 536, + BlockKind::BlueGlazedTerracotta => 537, + BlockKind::BrownGlazedTerracotta => 538, + BlockKind::GreenGlazedTerracotta => 539, + BlockKind::RedGlazedTerracotta => 540, + BlockKind::BlackGlazedTerracotta => 541, + BlockKind::WhiteConcrete => 542, + BlockKind::OrangeConcrete => 543, + BlockKind::MagentaConcrete => 544, + BlockKind::LightBlueConcrete => 545, + BlockKind::YellowConcrete => 546, + BlockKind::LimeConcrete => 547, + BlockKind::PinkConcrete => 548, + BlockKind::GrayConcrete => 549, + BlockKind::LightGrayConcrete => 550, + BlockKind::CyanConcrete => 551, + BlockKind::PurpleConcrete => 552, + BlockKind::BlueConcrete => 553, + BlockKind::BrownConcrete => 554, + BlockKind::GreenConcrete => 555, + BlockKind::RedConcrete => 556, + BlockKind::BlackConcrete => 557, + BlockKind::WhiteConcretePowder => 558, + BlockKind::OrangeConcretePowder => 559, + BlockKind::MagentaConcretePowder => 560, + BlockKind::LightBlueConcretePowder => 561, + BlockKind::YellowConcretePowder => 562, + BlockKind::LimeConcretePowder => 563, + BlockKind::PinkConcretePowder => 564, + BlockKind::GrayConcretePowder => 565, + BlockKind::LightGrayConcretePowder => 566, + BlockKind::CyanConcretePowder => 567, + BlockKind::PurpleConcretePowder => 568, + BlockKind::BlueConcretePowder => 569, + BlockKind::BrownConcretePowder => 570, + BlockKind::GreenConcretePowder => 571, + BlockKind::RedConcretePowder => 572, + BlockKind::BlackConcretePowder => 573, + BlockKind::Kelp => 574, + BlockKind::KelpPlant => 575, + BlockKind::DriedKelpBlock => 576, + BlockKind::TurtleEgg => 577, + BlockKind::DeadTubeCoralBlock => 578, + BlockKind::DeadBrainCoralBlock => 579, + BlockKind::DeadBubbleCoralBlock => 580, + BlockKind::DeadFireCoralBlock => 581, + BlockKind::DeadHornCoralBlock => 582, + BlockKind::TubeCoralBlock => 583, + BlockKind::BrainCoralBlock => 584, + BlockKind::BubbleCoralBlock => 585, + BlockKind::FireCoralBlock => 586, + BlockKind::HornCoralBlock => 587, + BlockKind::DeadTubeCoral => 588, + BlockKind::DeadBrainCoral => 589, + BlockKind::DeadBubbleCoral => 590, + BlockKind::DeadFireCoral => 591, + BlockKind::DeadHornCoral => 592, + BlockKind::TubeCoral => 593, + BlockKind::BrainCoral => 594, + BlockKind::BubbleCoral => 595, + BlockKind::FireCoral => 596, + BlockKind::HornCoral => 597, + BlockKind::DeadTubeCoralFan => 598, + BlockKind::DeadBrainCoralFan => 599, + BlockKind::DeadBubbleCoralFan => 600, + BlockKind::DeadFireCoralFan => 601, + BlockKind::DeadHornCoralFan => 602, + BlockKind::TubeCoralFan => 603, + BlockKind::BrainCoralFan => 604, + BlockKind::BubbleCoralFan => 605, + BlockKind::FireCoralFan => 606, + BlockKind::HornCoralFan => 607, + BlockKind::DeadTubeCoralWallFan => 608, + BlockKind::DeadBrainCoralWallFan => 609, + BlockKind::DeadBubbleCoralWallFan => 610, + BlockKind::DeadFireCoralWallFan => 611, + BlockKind::DeadHornCoralWallFan => 612, + BlockKind::TubeCoralWallFan => 613, + BlockKind::BrainCoralWallFan => 614, + BlockKind::BubbleCoralWallFan => 615, + BlockKind::FireCoralWallFan => 616, + BlockKind::HornCoralWallFan => 617, + BlockKind::SeaPickle => 618, + BlockKind::BlueIce => 619, + BlockKind::Conduit => 620, + BlockKind::BambooSapling => 621, + BlockKind::Bamboo => 622, + BlockKind::PottedBamboo => 623, + BlockKind::VoidAir => 624, + BlockKind::CaveAir => 625, + BlockKind::BubbleColumn => 626, + BlockKind::PolishedGraniteStairs => 627, + BlockKind::SmoothRedSandstoneStairs => 628, + BlockKind::MossyStoneBrickStairs => 629, + BlockKind::PolishedDioriteStairs => 630, + BlockKind::MossyCobblestoneStairs => 631, + BlockKind::EndStoneBrickStairs => 632, + BlockKind::StoneStairs => 633, + BlockKind::SmoothSandstoneStairs => 634, + BlockKind::SmoothQuartzStairs => 635, + BlockKind::GraniteStairs => 636, + BlockKind::AndesiteStairs => 637, + BlockKind::RedNetherBrickStairs => 638, + BlockKind::PolishedAndesiteStairs => 639, + BlockKind::DioriteStairs => 640, + BlockKind::PolishedGraniteSlab => 641, + BlockKind::SmoothRedSandstoneSlab => 642, + BlockKind::MossyStoneBrickSlab => 643, + BlockKind::PolishedDioriteSlab => 644, + BlockKind::MossyCobblestoneSlab => 645, + BlockKind::EndStoneBrickSlab => 646, + BlockKind::SmoothSandstoneSlab => 647, + BlockKind::SmoothQuartzSlab => 648, + BlockKind::GraniteSlab => 649, + BlockKind::AndesiteSlab => 650, + BlockKind::RedNetherBrickSlab => 651, + BlockKind::PolishedAndesiteSlab => 652, + BlockKind::DioriteSlab => 653, + BlockKind::BrickWall => 654, + BlockKind::PrismarineWall => 655, + BlockKind::RedSandstoneWall => 656, + BlockKind::MossyStoneBrickWall => 657, + BlockKind::GraniteWall => 658, + BlockKind::StoneBrickWall => 659, + BlockKind::NetherBrickWall => 660, + BlockKind::AndesiteWall => 661, + BlockKind::RedNetherBrickWall => 662, + BlockKind::SandstoneWall => 663, + BlockKind::EndStoneBrickWall => 664, + BlockKind::DioriteWall => 665, + BlockKind::Scaffolding => 666, + BlockKind::Loom => 667, + BlockKind::Barrel => 668, + BlockKind::Smoker => 669, + BlockKind::BlastFurnace => 670, + BlockKind::CartographyTable => 671, + BlockKind::FletchingTable => 672, + BlockKind::Grindstone => 673, + BlockKind::Lectern => 674, + BlockKind::SmithingTable => 675, + BlockKind::Stonecutter => 676, + BlockKind::Bell => 677, + BlockKind::Lantern => 678, + BlockKind::SoulLantern => 679, + BlockKind::Campfire => 680, + BlockKind::SoulCampfire => 681, + BlockKind::SweetBerryBush => 682, + BlockKind::WarpedStem => 683, + BlockKind::StrippedWarpedStem => 684, + BlockKind::WarpedHyphae => 685, + BlockKind::StrippedWarpedHyphae => 686, + BlockKind::WarpedNylium => 687, + BlockKind::WarpedFungus => 688, + BlockKind::WarpedWartBlock => 689, + BlockKind::WarpedRoots => 690, + BlockKind::NetherSprouts => 691, + BlockKind::CrimsonStem => 692, + BlockKind::StrippedCrimsonStem => 693, + BlockKind::CrimsonHyphae => 694, + BlockKind::StrippedCrimsonHyphae => 695, + BlockKind::CrimsonNylium => 696, + BlockKind::CrimsonFungus => 697, + BlockKind::Shroomlight => 698, + BlockKind::WeepingVines => 699, + BlockKind::WeepingVinesPlant => 700, + BlockKind::TwistingVines => 701, + BlockKind::TwistingVinesPlant => 702, + BlockKind::CrimsonRoots => 703, + BlockKind::CrimsonPlanks => 704, + BlockKind::WarpedPlanks => 705, + BlockKind::CrimsonSlab => 706, + BlockKind::WarpedSlab => 707, + BlockKind::CrimsonPressurePlate => 708, + BlockKind::WarpedPressurePlate => 709, + BlockKind::CrimsonFence => 710, + BlockKind::WarpedFence => 711, + BlockKind::CrimsonTrapdoor => 712, + BlockKind::WarpedTrapdoor => 713, + BlockKind::CrimsonFenceGate => 714, + BlockKind::WarpedFenceGate => 715, + BlockKind::CrimsonStairs => 716, + BlockKind::WarpedStairs => 717, + BlockKind::CrimsonButton => 718, + BlockKind::WarpedButton => 719, + BlockKind::CrimsonDoor => 720, + BlockKind::WarpedDoor => 721, + BlockKind::CrimsonSign => 722, + BlockKind::WarpedSign => 723, + BlockKind::CrimsonWallSign => 724, + BlockKind::WarpedWallSign => 725, + BlockKind::StructureBlock => 726, + BlockKind::Jigsaw => 727, + BlockKind::Composter => 728, + BlockKind::Target => 729, + BlockKind::BeeNest => 730, + BlockKind::Beehive => 731, + BlockKind::HoneyBlock => 732, + BlockKind::HoneycombBlock => 733, + BlockKind::NetheriteBlock => 734, + BlockKind::AncientDebris => 735, + BlockKind::CryingObsidian => 736, + BlockKind::RespawnAnchor => 737, + BlockKind::PottedCrimsonFungus => 738, + BlockKind::PottedWarpedFungus => 739, + BlockKind::PottedCrimsonRoots => 740, + BlockKind::PottedWarpedRoots => 741, + BlockKind::Lodestone => 742, + BlockKind::Blackstone => 743, + BlockKind::BlackstoneStairs => 744, + BlockKind::BlackstoneWall => 745, + BlockKind::BlackstoneSlab => 746, + BlockKind::PolishedBlackstone => 747, + BlockKind::PolishedBlackstoneBricks => 748, + BlockKind::CrackedPolishedBlackstoneBricks => 749, + BlockKind::ChiseledPolishedBlackstone => 750, + BlockKind::PolishedBlackstoneBrickSlab => 751, + BlockKind::PolishedBlackstoneBrickStairs => 752, + BlockKind::PolishedBlackstoneBrickWall => 753, + BlockKind::GildedBlackstone => 754, + BlockKind::PolishedBlackstoneStairs => 755, + BlockKind::PolishedBlackstoneSlab => 756, + BlockKind::PolishedBlackstonePressurePlate => 757, + BlockKind::PolishedBlackstoneButton => 758, + BlockKind::PolishedBlackstoneWall => 759, + BlockKind::ChiseledNetherBricks => 760, + BlockKind::CrackedNetherBricks => 761, + BlockKind::QuartzBricks => 762, + } + } + + /// Gets a `BlockKind` by its `id`. + pub fn from_id(id: u32) -> Option<Self> { + match id { + 0 => Some(BlockKind::Air), + 1 => Some(BlockKind::Stone), + 2 => Some(BlockKind::Granite), + 3 => Some(BlockKind::PolishedGranite), + 4 => Some(BlockKind::Diorite), + 5 => Some(BlockKind::PolishedDiorite), + 6 => Some(BlockKind::Andesite), + 7 => Some(BlockKind::PolishedAndesite), + 8 => Some(BlockKind::GrassBlock), + 9 => Some(BlockKind::Dirt), + 10 => Some(BlockKind::CoarseDirt), + 11 => Some(BlockKind::Podzol), + 12 => Some(BlockKind::Cobblestone), + 13 => Some(BlockKind::OakPlanks), + 14 => Some(BlockKind::SprucePlanks), + 15 => Some(BlockKind::BirchPlanks), + 16 => Some(BlockKind::JunglePlanks), + 17 => Some(BlockKind::AcaciaPlanks), + 18 => Some(BlockKind::DarkOakPlanks), + 19 => Some(BlockKind::OakSapling), + 20 => Some(BlockKind::SpruceSapling), + 21 => Some(BlockKind::BirchSapling), + 22 => Some(BlockKind::JungleSapling), + 23 => Some(BlockKind::AcaciaSapling), + 24 => Some(BlockKind::DarkOakSapling), + 25 => Some(BlockKind::Bedrock), + 26 => Some(BlockKind::Water), + 27 => Some(BlockKind::Lava), + 28 => Some(BlockKind::Sand), + 29 => Some(BlockKind::RedSand), + 30 => Some(BlockKind::Gravel), + 31 => Some(BlockKind::GoldOre), + 32 => Some(BlockKind::IronOre), + 33 => Some(BlockKind::CoalOre), + 34 => Some(BlockKind::NetherGoldOre), + 35 => Some(BlockKind::OakLog), + 36 => Some(BlockKind::SpruceLog), + 37 => Some(BlockKind::BirchLog), + 38 => Some(BlockKind::JungleLog), + 39 => Some(BlockKind::AcaciaLog), + 40 => Some(BlockKind::DarkOakLog), + 41 => Some(BlockKind::StrippedSpruceLog), + 42 => Some(BlockKind::StrippedBirchLog), + 43 => Some(BlockKind::StrippedJungleLog), + 44 => Some(BlockKind::StrippedAcaciaLog), + 45 => Some(BlockKind::StrippedDarkOakLog), + 46 => Some(BlockKind::StrippedOakLog), + 47 => Some(BlockKind::OakWood), + 48 => Some(BlockKind::SpruceWood), + 49 => Some(BlockKind::BirchWood), + 50 => Some(BlockKind::JungleWood), + 51 => Some(BlockKind::AcaciaWood), + 52 => Some(BlockKind::DarkOakWood), + 53 => Some(BlockKind::StrippedOakWood), + 54 => Some(BlockKind::StrippedSpruceWood), + 55 => Some(BlockKind::StrippedBirchWood), + 56 => Some(BlockKind::StrippedJungleWood), + 57 => Some(BlockKind::StrippedAcaciaWood), + 58 => Some(BlockKind::StrippedDarkOakWood), + 59 => Some(BlockKind::OakLeaves), + 60 => Some(BlockKind::SpruceLeaves), + 61 => Some(BlockKind::BirchLeaves), + 62 => Some(BlockKind::JungleLeaves), + 63 => Some(BlockKind::AcaciaLeaves), + 64 => Some(BlockKind::DarkOakLeaves), + 65 => Some(BlockKind::Sponge), + 66 => Some(BlockKind::WetSponge), + 67 => Some(BlockKind::Glass), + 68 => Some(BlockKind::LapisOre), + 69 => Some(BlockKind::LapisBlock), + 70 => Some(BlockKind::Dispenser), + 71 => Some(BlockKind::Sandstone), + 72 => Some(BlockKind::ChiseledSandstone), + 73 => Some(BlockKind::CutSandstone), + 74 => Some(BlockKind::NoteBlock), + 75 => Some(BlockKind::WhiteBed), + 76 => Some(BlockKind::OrangeBed), + 77 => Some(BlockKind::MagentaBed), + 78 => Some(BlockKind::LightBlueBed), + 79 => Some(BlockKind::YellowBed), + 80 => Some(BlockKind::LimeBed), + 81 => Some(BlockKind::PinkBed), + 82 => Some(BlockKind::GrayBed), + 83 => Some(BlockKind::LightGrayBed), + 84 => Some(BlockKind::CyanBed), + 85 => Some(BlockKind::PurpleBed), + 86 => Some(BlockKind::BlueBed), + 87 => Some(BlockKind::BrownBed), + 88 => Some(BlockKind::GreenBed), + 89 => Some(BlockKind::RedBed), + 90 => Some(BlockKind::BlackBed), + 91 => Some(BlockKind::PoweredRail), + 92 => Some(BlockKind::DetectorRail), + 93 => Some(BlockKind::StickyPiston), + 94 => Some(BlockKind::Cobweb), + 95 => Some(BlockKind::Grass), + 96 => Some(BlockKind::Fern), + 97 => Some(BlockKind::DeadBush), + 98 => Some(BlockKind::Seagrass), + 99 => Some(BlockKind::TallSeagrass), + 100 => Some(BlockKind::Piston), + 101 => Some(BlockKind::PistonHead), + 102 => Some(BlockKind::WhiteWool), + 103 => Some(BlockKind::OrangeWool), + 104 => Some(BlockKind::MagentaWool), + 105 => Some(BlockKind::LightBlueWool), + 106 => Some(BlockKind::YellowWool), + 107 => Some(BlockKind::LimeWool), + 108 => Some(BlockKind::PinkWool), + 109 => Some(BlockKind::GrayWool), + 110 => Some(BlockKind::LightGrayWool), + 111 => Some(BlockKind::CyanWool), + 112 => Some(BlockKind::PurpleWool), + 113 => Some(BlockKind::BlueWool), + 114 => Some(BlockKind::BrownWool), + 115 => Some(BlockKind::GreenWool), + 116 => Some(BlockKind::RedWool), + 117 => Some(BlockKind::BlackWool), + 118 => Some(BlockKind::MovingPiston), + 119 => Some(BlockKind::Dandelion), + 120 => Some(BlockKind::Poppy), + 121 => Some(BlockKind::BlueOrchid), + 122 => Some(BlockKind::Allium), + 123 => Some(BlockKind::AzureBluet), + 124 => Some(BlockKind::RedTulip), + 125 => Some(BlockKind::OrangeTulip), + 126 => Some(BlockKind::WhiteTulip), + 127 => Some(BlockKind::PinkTulip), + 128 => Some(BlockKind::OxeyeDaisy), + 129 => Some(BlockKind::Cornflower), + 130 => Some(BlockKind::WitherRose), + 131 => Some(BlockKind::LilyOfTheValley), + 132 => Some(BlockKind::BrownMushroom), + 133 => Some(BlockKind::RedMushroom), + 134 => Some(BlockKind::GoldBlock), + 135 => Some(BlockKind::IronBlock), + 136 => Some(BlockKind::Bricks), + 137 => Some(BlockKind::Tnt), + 138 => Some(BlockKind::Bookshelf), + 139 => Some(BlockKind::MossyCobblestone), + 140 => Some(BlockKind::Obsidian), + 141 => Some(BlockKind::Torch), + 142 => Some(BlockKind::WallTorch), + 143 => Some(BlockKind::Fire), + 144 => Some(BlockKind::SoulFire), + 145 => Some(BlockKind::Spawner), + 146 => Some(BlockKind::OakStairs), + 147 => Some(BlockKind::Chest), + 148 => Some(BlockKind::RedstoneWire), + 149 => Some(BlockKind::DiamondOre), + 150 => Some(BlockKind::DiamondBlock), + 151 => Some(BlockKind::CraftingTable), + 152 => Some(BlockKind::Wheat), + 153 => Some(BlockKind::Farmland), + 154 => Some(BlockKind::Furnace), + 155 => Some(BlockKind::OakSign), + 156 => Some(BlockKind::SpruceSign), + 157 => Some(BlockKind::BirchSign), + 158 => Some(BlockKind::AcaciaSign), + 159 => Some(BlockKind::JungleSign), + 160 => Some(BlockKind::DarkOakSign), + 161 => Some(BlockKind::OakDoor), + 162 => Some(BlockKind::Ladder), + 163 => Some(BlockKind::Rail), + 164 => Some(BlockKind::CobblestoneStairs), + 165 => Some(BlockKind::OakWallSign), + 166 => Some(BlockKind::SpruceWallSign), + 167 => Some(BlockKind::BirchWallSign), + 168 => Some(BlockKind::AcaciaWallSign), + 169 => Some(BlockKind::JungleWallSign), + 170 => Some(BlockKind::DarkOakWallSign), + 171 => Some(BlockKind::Lever), + 172 => Some(BlockKind::StonePressurePlate), + 173 => Some(BlockKind::IronDoor), + 174 => Some(BlockKind::OakPressurePlate), + 175 => Some(BlockKind::SprucePressurePlate), + 176 => Some(BlockKind::BirchPressurePlate), + 177 => Some(BlockKind::JunglePressurePlate), + 178 => Some(BlockKind::AcaciaPressurePlate), + 179 => Some(BlockKind::DarkOakPressurePlate), + 180 => Some(BlockKind::RedstoneOre), + 181 => Some(BlockKind::RedstoneTorch), + 182 => Some(BlockKind::RedstoneWallTorch), + 183 => Some(BlockKind::StoneButton), + 184 => Some(BlockKind::Snow), + 185 => Some(BlockKind::Ice), + 186 => Some(BlockKind::SnowBlock), + 187 => Some(BlockKind::Cactus), + 188 => Some(BlockKind::Clay), + 189 => Some(BlockKind::SugarCane), + 190 => Some(BlockKind::Jukebox), + 191 => Some(BlockKind::OakFence), + 192 => Some(BlockKind::Pumpkin), + 193 => Some(BlockKind::Netherrack), + 194 => Some(BlockKind::SoulSand), + 195 => Some(BlockKind::SoulSoil), + 196 => Some(BlockKind::Basalt), + 197 => Some(BlockKind::PolishedBasalt), + 198 => Some(BlockKind::SoulTorch), + 199 => Some(BlockKind::SoulWallTorch), + 200 => Some(BlockKind::Glowstone), + 201 => Some(BlockKind::NetherPortal), + 202 => Some(BlockKind::CarvedPumpkin), + 203 => Some(BlockKind::JackOLantern), + 204 => Some(BlockKind::Cake), + 205 => Some(BlockKind::Repeater), + 206 => Some(BlockKind::WhiteStainedGlass), + 207 => Some(BlockKind::OrangeStainedGlass), + 208 => Some(BlockKind::MagentaStainedGlass), + 209 => Some(BlockKind::LightBlueStainedGlass), + 210 => Some(BlockKind::YellowStainedGlass), + 211 => Some(BlockKind::LimeStainedGlass), + 212 => Some(BlockKind::PinkStainedGlass), + 213 => Some(BlockKind::GrayStainedGlass), + 214 => Some(BlockKind::LightGrayStainedGlass), + 215 => Some(BlockKind::CyanStainedGlass), + 216 => Some(BlockKind::PurpleStainedGlass), + 217 => Some(BlockKind::BlueStainedGlass), + 218 => Some(BlockKind::BrownStainedGlass), + 219 => Some(BlockKind::GreenStainedGlass), + 220 => Some(BlockKind::RedStainedGlass), + 221 => Some(BlockKind::BlackStainedGlass), + 222 => Some(BlockKind::OakTrapdoor), + 223 => Some(BlockKind::SpruceTrapdoor), + 224 => Some(BlockKind::BirchTrapdoor), + 225 => Some(BlockKind::JungleTrapdoor), + 226 => Some(BlockKind::AcaciaTrapdoor), + 227 => Some(BlockKind::DarkOakTrapdoor), + 228 => Some(BlockKind::StoneBricks), + 229 => Some(BlockKind::MossyStoneBricks), + 230 => Some(BlockKind::CrackedStoneBricks), + 231 => Some(BlockKind::ChiseledStoneBricks), + 232 => Some(BlockKind::InfestedStone), + 233 => Some(BlockKind::InfestedCobblestone), + 234 => Some(BlockKind::InfestedStoneBricks), + 235 => Some(BlockKind::InfestedMossyStoneBricks), + 236 => Some(BlockKind::InfestedCrackedStoneBricks), + 237 => Some(BlockKind::InfestedChiseledStoneBricks), + 238 => Some(BlockKind::BrownMushroomBlock), + 239 => Some(BlockKind::RedMushroomBlock), + 240 => Some(BlockKind::MushroomStem), + 241 => Some(BlockKind::IronBars), + 242 => Some(BlockKind::Chain), + 243 => Some(BlockKind::GlassPane), + 244 => Some(BlockKind::Melon), + 245 => Some(BlockKind::AttachedPumpkinStem), + 246 => Some(BlockKind::AttachedMelonStem), + 247 => Some(BlockKind::PumpkinStem), + 248 => Some(BlockKind::MelonStem), + 249 => Some(BlockKind::Vine), + 250 => Some(BlockKind::OakFenceGate), + 251 => Some(BlockKind::BrickStairs), + 252 => Some(BlockKind::StoneBrickStairs), + 253 => Some(BlockKind::Mycelium), + 254 => Some(BlockKind::LilyPad), + 255 => Some(BlockKind::NetherBricks), + 256 => Some(BlockKind::NetherBrickFence), + 257 => Some(BlockKind::NetherBrickStairs), + 258 => Some(BlockKind::NetherWart), + 259 => Some(BlockKind::EnchantingTable), + 260 => Some(BlockKind::BrewingStand), + 261 => Some(BlockKind::Cauldron), + 262 => Some(BlockKind::EndPortal), + 263 => Some(BlockKind::EndPortalFrame), + 264 => Some(BlockKind::EndStone), + 265 => Some(BlockKind::DragonEgg), + 266 => Some(BlockKind::RedstoneLamp), + 267 => Some(BlockKind::Cocoa), + 268 => Some(BlockKind::SandstoneStairs), + 269 => Some(BlockKind::EmeraldOre), + 270 => Some(BlockKind::EnderChest), + 271 => Some(BlockKind::TripwireHook), + 272 => Some(BlockKind::Tripwire), + 273 => Some(BlockKind::EmeraldBlock), + 274 => Some(BlockKind::SpruceStairs), + 275 => Some(BlockKind::BirchStairs), + 276 => Some(BlockKind::JungleStairs), + 277 => Some(BlockKind::CommandBlock), + 278 => Some(BlockKind::Beacon), + 279 => Some(BlockKind::CobblestoneWall), + 280 => Some(BlockKind::MossyCobblestoneWall), + 281 => Some(BlockKind::FlowerPot), + 282 => Some(BlockKind::PottedOakSapling), + 283 => Some(BlockKind::PottedSpruceSapling), + 284 => Some(BlockKind::PottedBirchSapling), + 285 => Some(BlockKind::PottedJungleSapling), + 286 => Some(BlockKind::PottedAcaciaSapling), + 287 => Some(BlockKind::PottedDarkOakSapling), + 288 => Some(BlockKind::PottedFern), + 289 => Some(BlockKind::PottedDandelion), + 290 => Some(BlockKind::PottedPoppy), + 291 => Some(BlockKind::PottedBlueOrchid), + 292 => Some(BlockKind::PottedAllium), + 293 => Some(BlockKind::PottedAzureBluet), + 294 => Some(BlockKind::PottedRedTulip), + 295 => Some(BlockKind::PottedOrangeTulip), + 296 => Some(BlockKind::PottedWhiteTulip), + 297 => Some(BlockKind::PottedPinkTulip), + 298 => Some(BlockKind::PottedOxeyeDaisy), + 299 => Some(BlockKind::PottedCornflower), + 300 => Some(BlockKind::PottedLilyOfTheValley), + 301 => Some(BlockKind::PottedWitherRose), + 302 => Some(BlockKind::PottedRedMushroom), + 303 => Some(BlockKind::PottedBrownMushroom), + 304 => Some(BlockKind::PottedDeadBush), + 305 => Some(BlockKind::PottedCactus), + 306 => Some(BlockKind::Carrots), + 307 => Some(BlockKind::Potatoes), + 308 => Some(BlockKind::OakButton), + 309 => Some(BlockKind::SpruceButton), + 310 => Some(BlockKind::BirchButton), + 311 => Some(BlockKind::JungleButton), + 312 => Some(BlockKind::AcaciaButton), + 313 => Some(BlockKind::DarkOakButton), + 314 => Some(BlockKind::SkeletonSkull), + 315 => Some(BlockKind::SkeletonWallSkull), + 316 => Some(BlockKind::WitherSkeletonSkull), + 317 => Some(BlockKind::WitherSkeletonWallSkull), + 318 => Some(BlockKind::ZombieHead), + 319 => Some(BlockKind::ZombieWallHead), + 320 => Some(BlockKind::PlayerHead), + 321 => Some(BlockKind::PlayerWallHead), + 322 => Some(BlockKind::CreeperHead), + 323 => Some(BlockKind::CreeperWallHead), + 324 => Some(BlockKind::DragonHead), + 325 => Some(BlockKind::DragonWallHead), + 326 => Some(BlockKind::Anvil), + 327 => Some(BlockKind::ChippedAnvil), + 328 => Some(BlockKind::DamagedAnvil), + 329 => Some(BlockKind::TrappedChest), + 330 => Some(BlockKind::LightWeightedPressurePlate), + 331 => Some(BlockKind::HeavyWeightedPressurePlate), + 332 => Some(BlockKind::Comparator), + 333 => Some(BlockKind::DaylightDetector), + 334 => Some(BlockKind::RedstoneBlock), + 335 => Some(BlockKind::NetherQuartzOre), + 336 => Some(BlockKind::Hopper), + 337 => Some(BlockKind::QuartzBlock), + 338 => Some(BlockKind::ChiseledQuartzBlock), + 339 => Some(BlockKind::QuartzPillar), + 340 => Some(BlockKind::QuartzStairs), + 341 => Some(BlockKind::ActivatorRail), + 342 => Some(BlockKind::Dropper), + 343 => Some(BlockKind::WhiteTerracotta), + 344 => Some(BlockKind::OrangeTerracotta), + 345 => Some(BlockKind::MagentaTerracotta), + 346 => Some(BlockKind::LightBlueTerracotta), + 347 => Some(BlockKind::YellowTerracotta), + 348 => Some(BlockKind::LimeTerracotta), + 349 => Some(BlockKind::PinkTerracotta), + 350 => Some(BlockKind::GrayTerracotta), + 351 => Some(BlockKind::LightGrayTerracotta), + 352 => Some(BlockKind::CyanTerracotta), + 353 => Some(BlockKind::PurpleTerracotta), + 354 => Some(BlockKind::BlueTerracotta), + 355 => Some(BlockKind::BrownTerracotta), + 356 => Some(BlockKind::GreenTerracotta), + 357 => Some(BlockKind::RedTerracotta), + 358 => Some(BlockKind::BlackTerracotta), + 359 => Some(BlockKind::WhiteStainedGlassPane), + 360 => Some(BlockKind::OrangeStainedGlassPane), + 361 => Some(BlockKind::MagentaStainedGlassPane), + 362 => Some(BlockKind::LightBlueStainedGlassPane), + 363 => Some(BlockKind::YellowStainedGlassPane), + 364 => Some(BlockKind::LimeStainedGlassPane), + 365 => Some(BlockKind::PinkStainedGlassPane), + 366 => Some(BlockKind::GrayStainedGlassPane), + 367 => Some(BlockKind::LightGrayStainedGlassPane), + 368 => Some(BlockKind::CyanStainedGlassPane), + 369 => Some(BlockKind::PurpleStainedGlassPane), + 370 => Some(BlockKind::BlueStainedGlassPane), + 371 => Some(BlockKind::BrownStainedGlassPane), + 372 => Some(BlockKind::GreenStainedGlassPane), + 373 => Some(BlockKind::RedStainedGlassPane), + 374 => Some(BlockKind::BlackStainedGlassPane), + 375 => Some(BlockKind::AcaciaStairs), + 376 => Some(BlockKind::DarkOakStairs), + 377 => Some(BlockKind::SlimeBlock), + 378 => Some(BlockKind::Barrier), + 379 => Some(BlockKind::IronTrapdoor), + 380 => Some(BlockKind::Prismarine), + 381 => Some(BlockKind::PrismarineBricks), + 382 => Some(BlockKind::DarkPrismarine), + 383 => Some(BlockKind::PrismarineStairs), + 384 => Some(BlockKind::PrismarineBrickStairs), + 385 => Some(BlockKind::DarkPrismarineStairs), + 386 => Some(BlockKind::PrismarineSlab), + 387 => Some(BlockKind::PrismarineBrickSlab), + 388 => Some(BlockKind::DarkPrismarineSlab), + 389 => Some(BlockKind::SeaLantern), + 390 => Some(BlockKind::HayBlock), + 391 => Some(BlockKind::WhiteCarpet), + 392 => Some(BlockKind::OrangeCarpet), + 393 => Some(BlockKind::MagentaCarpet), + 394 => Some(BlockKind::LightBlueCarpet), + 395 => Some(BlockKind::YellowCarpet), + 396 => Some(BlockKind::LimeCarpet), + 397 => Some(BlockKind::PinkCarpet), + 398 => Some(BlockKind::GrayCarpet), + 399 => Some(BlockKind::LightGrayCarpet), + 400 => Some(BlockKind::CyanCarpet), + 401 => Some(BlockKind::PurpleCarpet), + 402 => Some(BlockKind::BlueCarpet), + 403 => Some(BlockKind::BrownCarpet), + 404 => Some(BlockKind::GreenCarpet), + 405 => Some(BlockKind::RedCarpet), + 406 => Some(BlockKind::BlackCarpet), + 407 => Some(BlockKind::Terracotta), + 408 => Some(BlockKind::CoalBlock), + 409 => Some(BlockKind::PackedIce), + 410 => Some(BlockKind::Sunflower), + 411 => Some(BlockKind::Lilac), + 412 => Some(BlockKind::RoseBush), + 413 => Some(BlockKind::Peony), + 414 => Some(BlockKind::TallGrass), + 415 => Some(BlockKind::LargeFern), + 416 => Some(BlockKind::WhiteBanner), + 417 => Some(BlockKind::OrangeBanner), + 418 => Some(BlockKind::MagentaBanner), + 419 => Some(BlockKind::LightBlueBanner), + 420 => Some(BlockKind::YellowBanner), + 421 => Some(BlockKind::LimeBanner), + 422 => Some(BlockKind::PinkBanner), + 423 => Some(BlockKind::GrayBanner), + 424 => Some(BlockKind::LightGrayBanner), + 425 => Some(BlockKind::CyanBanner), + 426 => Some(BlockKind::PurpleBanner), + 427 => Some(BlockKind::BlueBanner), + 428 => Some(BlockKind::BrownBanner), + 429 => Some(BlockKind::GreenBanner), + 430 => Some(BlockKind::RedBanner), + 431 => Some(BlockKind::BlackBanner), + 432 => Some(BlockKind::WhiteWallBanner), + 433 => Some(BlockKind::OrangeWallBanner), + 434 => Some(BlockKind::MagentaWallBanner), + 435 => Some(BlockKind::LightBlueWallBanner), + 436 => Some(BlockKind::YellowWallBanner), + 437 => Some(BlockKind::LimeWallBanner), + 438 => Some(BlockKind::PinkWallBanner), + 439 => Some(BlockKind::GrayWallBanner), + 440 => Some(BlockKind::LightGrayWallBanner), + 441 => Some(BlockKind::CyanWallBanner), + 442 => Some(BlockKind::PurpleWallBanner), + 443 => Some(BlockKind::BlueWallBanner), + 444 => Some(BlockKind::BrownWallBanner), + 445 => Some(BlockKind::GreenWallBanner), + 446 => Some(BlockKind::RedWallBanner), + 447 => Some(BlockKind::BlackWallBanner), + 448 => Some(BlockKind::RedSandstone), + 449 => Some(BlockKind::ChiseledRedSandstone), + 450 => Some(BlockKind::CutRedSandstone), + 451 => Some(BlockKind::RedSandstoneStairs), + 452 => Some(BlockKind::OakSlab), + 453 => Some(BlockKind::SpruceSlab), + 454 => Some(BlockKind::BirchSlab), + 455 => Some(BlockKind::JungleSlab), + 456 => Some(BlockKind::AcaciaSlab), + 457 => Some(BlockKind::DarkOakSlab), + 458 => Some(BlockKind::StoneSlab), + 459 => Some(BlockKind::SmoothStoneSlab), + 460 => Some(BlockKind::SandstoneSlab), + 461 => Some(BlockKind::CutSandstoneSlab), + 462 => Some(BlockKind::PetrifiedOakSlab), + 463 => Some(BlockKind::CobblestoneSlab), + 464 => Some(BlockKind::BrickSlab), + 465 => Some(BlockKind::StoneBrickSlab), + 466 => Some(BlockKind::NetherBrickSlab), + 467 => Some(BlockKind::QuartzSlab), + 468 => Some(BlockKind::RedSandstoneSlab), + 469 => Some(BlockKind::CutRedSandstoneSlab), + 470 => Some(BlockKind::PurpurSlab), + 471 => Some(BlockKind::SmoothStone), + 472 => Some(BlockKind::SmoothSandstone), + 473 => Some(BlockKind::SmoothQuartz), + 474 => Some(BlockKind::SmoothRedSandstone), + 475 => Some(BlockKind::SpruceFenceGate), + 476 => Some(BlockKind::BirchFenceGate), + 477 => Some(BlockKind::JungleFenceGate), + 478 => Some(BlockKind::AcaciaFenceGate), + 479 => Some(BlockKind::DarkOakFenceGate), + 480 => Some(BlockKind::SpruceFence), + 481 => Some(BlockKind::BirchFence), + 482 => Some(BlockKind::JungleFence), + 483 => Some(BlockKind::AcaciaFence), + 484 => Some(BlockKind::DarkOakFence), + 485 => Some(BlockKind::SpruceDoor), + 486 => Some(BlockKind::BirchDoor), + 487 => Some(BlockKind::JungleDoor), + 488 => Some(BlockKind::AcaciaDoor), + 489 => Some(BlockKind::DarkOakDoor), + 490 => Some(BlockKind::EndRod), + 491 => Some(BlockKind::ChorusPlant), + 492 => Some(BlockKind::ChorusFlower), + 493 => Some(BlockKind::PurpurBlock), + 494 => Some(BlockKind::PurpurPillar), + 495 => Some(BlockKind::PurpurStairs), + 496 => Some(BlockKind::EndStoneBricks), + 497 => Some(BlockKind::Beetroots), + 498 => Some(BlockKind::GrassPath), + 499 => Some(BlockKind::EndGateway), + 500 => Some(BlockKind::RepeatingCommandBlock), + 501 => Some(BlockKind::ChainCommandBlock), + 502 => Some(BlockKind::FrostedIce), + 503 => Some(BlockKind::MagmaBlock), + 504 => Some(BlockKind::NetherWartBlock), + 505 => Some(BlockKind::RedNetherBricks), + 506 => Some(BlockKind::BoneBlock), + 507 => Some(BlockKind::StructureVoid), + 508 => Some(BlockKind::Observer), + 509 => Some(BlockKind::ShulkerBox), + 510 => Some(BlockKind::WhiteShulkerBox), + 511 => Some(BlockKind::OrangeShulkerBox), + 512 => Some(BlockKind::MagentaShulkerBox), + 513 => Some(BlockKind::LightBlueShulkerBox), + 514 => Some(BlockKind::YellowShulkerBox), + 515 => Some(BlockKind::LimeShulkerBox), + 516 => Some(BlockKind::PinkShulkerBox), + 517 => Some(BlockKind::GrayShulkerBox), + 518 => Some(BlockKind::LightGrayShulkerBox), + 519 => Some(BlockKind::CyanShulkerBox), + 520 => Some(BlockKind::PurpleShulkerBox), + 521 => Some(BlockKind::BlueShulkerBox), + 522 => Some(BlockKind::BrownShulkerBox), + 523 => Some(BlockKind::GreenShulkerBox), + 524 => Some(BlockKind::RedShulkerBox), + 525 => Some(BlockKind::BlackShulkerBox), + 526 => Some(BlockKind::WhiteGlazedTerracotta), + 527 => Some(BlockKind::OrangeGlazedTerracotta), + 528 => Some(BlockKind::MagentaGlazedTerracotta), + 529 => Some(BlockKind::LightBlueGlazedTerracotta), + 530 => Some(BlockKind::YellowGlazedTerracotta), + 531 => Some(BlockKind::LimeGlazedTerracotta), + 532 => Some(BlockKind::PinkGlazedTerracotta), + 533 => Some(BlockKind::GrayGlazedTerracotta), + 534 => Some(BlockKind::LightGrayGlazedTerracotta), + 535 => Some(BlockKind::CyanGlazedTerracotta), + 536 => Some(BlockKind::PurpleGlazedTerracotta), + 537 => Some(BlockKind::BlueGlazedTerracotta), + 538 => Some(BlockKind::BrownGlazedTerracotta), + 539 => Some(BlockKind::GreenGlazedTerracotta), + 540 => Some(BlockKind::RedGlazedTerracotta), + 541 => Some(BlockKind::BlackGlazedTerracotta), + 542 => Some(BlockKind::WhiteConcrete), + 543 => Some(BlockKind::OrangeConcrete), + 544 => Some(BlockKind::MagentaConcrete), + 545 => Some(BlockKind::LightBlueConcrete), + 546 => Some(BlockKind::YellowConcrete), + 547 => Some(BlockKind::LimeConcrete), + 548 => Some(BlockKind::PinkConcrete), + 549 => Some(BlockKind::GrayConcrete), + 550 => Some(BlockKind::LightGrayConcrete), + 551 => Some(BlockKind::CyanConcrete), + 552 => Some(BlockKind::PurpleConcrete), + 553 => Some(BlockKind::BlueConcrete), + 554 => Some(BlockKind::BrownConcrete), + 555 => Some(BlockKind::GreenConcrete), + 556 => Some(BlockKind::RedConcrete), + 557 => Some(BlockKind::BlackConcrete), + 558 => Some(BlockKind::WhiteConcretePowder), + 559 => Some(BlockKind::OrangeConcretePowder), + 560 => Some(BlockKind::MagentaConcretePowder), + 561 => Some(BlockKind::LightBlueConcretePowder), + 562 => Some(BlockKind::YellowConcretePowder), + 563 => Some(BlockKind::LimeConcretePowder), + 564 => Some(BlockKind::PinkConcretePowder), + 565 => Some(BlockKind::GrayConcretePowder), + 566 => Some(BlockKind::LightGrayConcretePowder), + 567 => Some(BlockKind::CyanConcretePowder), + 568 => Some(BlockKind::PurpleConcretePowder), + 569 => Some(BlockKind::BlueConcretePowder), + 570 => Some(BlockKind::BrownConcretePowder), + 571 => Some(BlockKind::GreenConcretePowder), + 572 => Some(BlockKind::RedConcretePowder), + 573 => Some(BlockKind::BlackConcretePowder), + 574 => Some(BlockKind::Kelp), + 575 => Some(BlockKind::KelpPlant), + 576 => Some(BlockKind::DriedKelpBlock), + 577 => Some(BlockKind::TurtleEgg), + 578 => Some(BlockKind::DeadTubeCoralBlock), + 579 => Some(BlockKind::DeadBrainCoralBlock), + 580 => Some(BlockKind::DeadBubbleCoralBlock), + 581 => Some(BlockKind::DeadFireCoralBlock), + 582 => Some(BlockKind::DeadHornCoralBlock), + 583 => Some(BlockKind::TubeCoralBlock), + 584 => Some(BlockKind::BrainCoralBlock), + 585 => Some(BlockKind::BubbleCoralBlock), + 586 => Some(BlockKind::FireCoralBlock), + 587 => Some(BlockKind::HornCoralBlock), + 588 => Some(BlockKind::DeadTubeCoral), + 589 => Some(BlockKind::DeadBrainCoral), + 590 => Some(BlockKind::DeadBubbleCoral), + 591 => Some(BlockKind::DeadFireCoral), + 592 => Some(BlockKind::DeadHornCoral), + 593 => Some(BlockKind::TubeCoral), + 594 => Some(BlockKind::BrainCoral), + 595 => Some(BlockKind::BubbleCoral), + 596 => Some(BlockKind::FireCoral), + 597 => Some(BlockKind::HornCoral), + 598 => Some(BlockKind::DeadTubeCoralFan), + 599 => Some(BlockKind::DeadBrainCoralFan), + 600 => Some(BlockKind::DeadBubbleCoralFan), + 601 => Some(BlockKind::DeadFireCoralFan), + 602 => Some(BlockKind::DeadHornCoralFan), + 603 => Some(BlockKind::TubeCoralFan), + 604 => Some(BlockKind::BrainCoralFan), + 605 => Some(BlockKind::BubbleCoralFan), + 606 => Some(BlockKind::FireCoralFan), + 607 => Some(BlockKind::HornCoralFan), + 608 => Some(BlockKind::DeadTubeCoralWallFan), + 609 => Some(BlockKind::DeadBrainCoralWallFan), + 610 => Some(BlockKind::DeadBubbleCoralWallFan), + 611 => Some(BlockKind::DeadFireCoralWallFan), + 612 => Some(BlockKind::DeadHornCoralWallFan), + 613 => Some(BlockKind::TubeCoralWallFan), + 614 => Some(BlockKind::BrainCoralWallFan), + 615 => Some(BlockKind::BubbleCoralWallFan), + 616 => Some(BlockKind::FireCoralWallFan), + 617 => Some(BlockKind::HornCoralWallFan), + 618 => Some(BlockKind::SeaPickle), + 619 => Some(BlockKind::BlueIce), + 620 => Some(BlockKind::Conduit), + 621 => Some(BlockKind::BambooSapling), + 622 => Some(BlockKind::Bamboo), + 623 => Some(BlockKind::PottedBamboo), + 624 => Some(BlockKind::VoidAir), + 625 => Some(BlockKind::CaveAir), + 626 => Some(BlockKind::BubbleColumn), + 627 => Some(BlockKind::PolishedGraniteStairs), + 628 => Some(BlockKind::SmoothRedSandstoneStairs), + 629 => Some(BlockKind::MossyStoneBrickStairs), + 630 => Some(BlockKind::PolishedDioriteStairs), + 631 => Some(BlockKind::MossyCobblestoneStairs), + 632 => Some(BlockKind::EndStoneBrickStairs), + 633 => Some(BlockKind::StoneStairs), + 634 => Some(BlockKind::SmoothSandstoneStairs), + 635 => Some(BlockKind::SmoothQuartzStairs), + 636 => Some(BlockKind::GraniteStairs), + 637 => Some(BlockKind::AndesiteStairs), + 638 => Some(BlockKind::RedNetherBrickStairs), + 639 => Some(BlockKind::PolishedAndesiteStairs), + 640 => Some(BlockKind::DioriteStairs), + 641 => Some(BlockKind::PolishedGraniteSlab), + 642 => Some(BlockKind::SmoothRedSandstoneSlab), + 643 => Some(BlockKind::MossyStoneBrickSlab), + 644 => Some(BlockKind::PolishedDioriteSlab), + 645 => Some(BlockKind::MossyCobblestoneSlab), + 646 => Some(BlockKind::EndStoneBrickSlab), + 647 => Some(BlockKind::SmoothSandstoneSlab), + 648 => Some(BlockKind::SmoothQuartzSlab), + 649 => Some(BlockKind::GraniteSlab), + 650 => Some(BlockKind::AndesiteSlab), + 651 => Some(BlockKind::RedNetherBrickSlab), + 652 => Some(BlockKind::PolishedAndesiteSlab), + 653 => Some(BlockKind::DioriteSlab), + 654 => Some(BlockKind::BrickWall), + 655 => Some(BlockKind::PrismarineWall), + 656 => Some(BlockKind::RedSandstoneWall), + 657 => Some(BlockKind::MossyStoneBrickWall), + 658 => Some(BlockKind::GraniteWall), + 659 => Some(BlockKind::StoneBrickWall), + 660 => Some(BlockKind::NetherBrickWall), + 661 => Some(BlockKind::AndesiteWall), + 662 => Some(BlockKind::RedNetherBrickWall), + 663 => Some(BlockKind::SandstoneWall), + 664 => Some(BlockKind::EndStoneBrickWall), + 665 => Some(BlockKind::DioriteWall), + 666 => Some(BlockKind::Scaffolding), + 667 => Some(BlockKind::Loom), + 668 => Some(BlockKind::Barrel), + 669 => Some(BlockKind::Smoker), + 670 => Some(BlockKind::BlastFurnace), + 671 => Some(BlockKind::CartographyTable), + 672 => Some(BlockKind::FletchingTable), + 673 => Some(BlockKind::Grindstone), + 674 => Some(BlockKind::Lectern), + 675 => Some(BlockKind::SmithingTable), + 676 => Some(BlockKind::Stonecutter), + 677 => Some(BlockKind::Bell), + 678 => Some(BlockKind::Lantern), + 679 => Some(BlockKind::SoulLantern), + 680 => Some(BlockKind::Campfire), + 681 => Some(BlockKind::SoulCampfire), + 682 => Some(BlockKind::SweetBerryBush), + 683 => Some(BlockKind::WarpedStem), + 684 => Some(BlockKind::StrippedWarpedStem), + 685 => Some(BlockKind::WarpedHyphae), + 686 => Some(BlockKind::StrippedWarpedHyphae), + 687 => Some(BlockKind::WarpedNylium), + 688 => Some(BlockKind::WarpedFungus), + 689 => Some(BlockKind::WarpedWartBlock), + 690 => Some(BlockKind::WarpedRoots), + 691 => Some(BlockKind::NetherSprouts), + 692 => Some(BlockKind::CrimsonStem), + 693 => Some(BlockKind::StrippedCrimsonStem), + 694 => Some(BlockKind::CrimsonHyphae), + 695 => Some(BlockKind::StrippedCrimsonHyphae), + 696 => Some(BlockKind::CrimsonNylium), + 697 => Some(BlockKind::CrimsonFungus), + 698 => Some(BlockKind::Shroomlight), + 699 => Some(BlockKind::WeepingVines), + 700 => Some(BlockKind::WeepingVinesPlant), + 701 => Some(BlockKind::TwistingVines), + 702 => Some(BlockKind::TwistingVinesPlant), + 703 => Some(BlockKind::CrimsonRoots), + 704 => Some(BlockKind::CrimsonPlanks), + 705 => Some(BlockKind::WarpedPlanks), + 706 => Some(BlockKind::CrimsonSlab), + 707 => Some(BlockKind::WarpedSlab), + 708 => Some(BlockKind::CrimsonPressurePlate), + 709 => Some(BlockKind::WarpedPressurePlate), + 710 => Some(BlockKind::CrimsonFence), + 711 => Some(BlockKind::WarpedFence), + 712 => Some(BlockKind::CrimsonTrapdoor), + 713 => Some(BlockKind::WarpedTrapdoor), + 714 => Some(BlockKind::CrimsonFenceGate), + 715 => Some(BlockKind::WarpedFenceGate), + 716 => Some(BlockKind::CrimsonStairs), + 717 => Some(BlockKind::WarpedStairs), + 718 => Some(BlockKind::CrimsonButton), + 719 => Some(BlockKind::WarpedButton), + 720 => Some(BlockKind::CrimsonDoor), + 721 => Some(BlockKind::WarpedDoor), + 722 => Some(BlockKind::CrimsonSign), + 723 => Some(BlockKind::WarpedSign), + 724 => Some(BlockKind::CrimsonWallSign), + 725 => Some(BlockKind::WarpedWallSign), + 726 => Some(BlockKind::StructureBlock), + 727 => Some(BlockKind::Jigsaw), + 728 => Some(BlockKind::Composter), + 729 => Some(BlockKind::Target), + 730 => Some(BlockKind::BeeNest), + 731 => Some(BlockKind::Beehive), + 732 => Some(BlockKind::HoneyBlock), + 733 => Some(BlockKind::HoneycombBlock), + 734 => Some(BlockKind::NetheriteBlock), + 735 => Some(BlockKind::AncientDebris), + 736 => Some(BlockKind::CryingObsidian), + 737 => Some(BlockKind::RespawnAnchor), + 738 => Some(BlockKind::PottedCrimsonFungus), + 739 => Some(BlockKind::PottedWarpedFungus), + 740 => Some(BlockKind::PottedCrimsonRoots), + 741 => Some(BlockKind::PottedWarpedRoots), + 742 => Some(BlockKind::Lodestone), + 743 => Some(BlockKind::Blackstone), + 744 => Some(BlockKind::BlackstoneStairs), + 745 => Some(BlockKind::BlackstoneWall), + 746 => Some(BlockKind::BlackstoneSlab), + 747 => Some(BlockKind::PolishedBlackstone), + 748 => Some(BlockKind::PolishedBlackstoneBricks), + 749 => Some(BlockKind::CrackedPolishedBlackstoneBricks), + 750 => Some(BlockKind::ChiseledPolishedBlackstone), + 751 => Some(BlockKind::PolishedBlackstoneBrickSlab), + 752 => Some(BlockKind::PolishedBlackstoneBrickStairs), + 753 => Some(BlockKind::PolishedBlackstoneBrickWall), + 754 => Some(BlockKind::GildedBlackstone), + 755 => Some(BlockKind::PolishedBlackstoneStairs), + 756 => Some(BlockKind::PolishedBlackstoneSlab), + 757 => Some(BlockKind::PolishedBlackstonePressurePlate), + 758 => Some(BlockKind::PolishedBlackstoneButton), + 759 => Some(BlockKind::PolishedBlackstoneWall), + 760 => Some(BlockKind::ChiseledNetherBricks), + 761 => Some(BlockKind::CrackedNetherBricks), + 762 => Some(BlockKind::QuartzBricks), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `name` property of this `BlockKind`. + pub fn name(&self) -> &'static str { + match self { + BlockKind::Air => "air", + BlockKind::Stone => "stone", + BlockKind::Granite => "granite", + BlockKind::PolishedGranite => "polished_granite", + BlockKind::Diorite => "diorite", + BlockKind::PolishedDiorite => "polished_diorite", + BlockKind::Andesite => "andesite", + BlockKind::PolishedAndesite => "polished_andesite", + BlockKind::GrassBlock => "grass_block", + BlockKind::Dirt => "dirt", + BlockKind::CoarseDirt => "coarse_dirt", + BlockKind::Podzol => "podzol", + BlockKind::Cobblestone => "cobblestone", + BlockKind::OakPlanks => "oak_planks", + BlockKind::SprucePlanks => "spruce_planks", + BlockKind::BirchPlanks => "birch_planks", + BlockKind::JunglePlanks => "jungle_planks", + BlockKind::AcaciaPlanks => "acacia_planks", + BlockKind::DarkOakPlanks => "dark_oak_planks", + BlockKind::OakSapling => "oak_sapling", + BlockKind::SpruceSapling => "spruce_sapling", + BlockKind::BirchSapling => "birch_sapling", + BlockKind::JungleSapling => "jungle_sapling", + BlockKind::AcaciaSapling => "acacia_sapling", + BlockKind::DarkOakSapling => "dark_oak_sapling", + BlockKind::Bedrock => "bedrock", + BlockKind::Water => "water", + BlockKind::Lava => "lava", + BlockKind::Sand => "sand", + BlockKind::RedSand => "red_sand", + BlockKind::Gravel => "gravel", + BlockKind::GoldOre => "gold_ore", + BlockKind::IronOre => "iron_ore", + BlockKind::CoalOre => "coal_ore", + BlockKind::NetherGoldOre => "nether_gold_ore", + BlockKind::OakLog => "oak_log", + BlockKind::SpruceLog => "spruce_log", + BlockKind::BirchLog => "birch_log", + BlockKind::JungleLog => "jungle_log", + BlockKind::AcaciaLog => "acacia_log", + BlockKind::DarkOakLog => "dark_oak_log", + BlockKind::StrippedSpruceLog => "stripped_spruce_log", + BlockKind::StrippedBirchLog => "stripped_birch_log", + BlockKind::StrippedJungleLog => "stripped_jungle_log", + BlockKind::StrippedAcaciaLog => "stripped_acacia_log", + BlockKind::StrippedDarkOakLog => "stripped_dark_oak_log", + BlockKind::StrippedOakLog => "stripped_oak_log", + BlockKind::OakWood => "oak_wood", + BlockKind::SpruceWood => "spruce_wood", + BlockKind::BirchWood => "birch_wood", + BlockKind::JungleWood => "jungle_wood", + BlockKind::AcaciaWood => "acacia_wood", + BlockKind::DarkOakWood => "dark_oak_wood", + BlockKind::StrippedOakWood => "stripped_oak_wood", + BlockKind::StrippedSpruceWood => "stripped_spruce_wood", + BlockKind::StrippedBirchWood => "stripped_birch_wood", + BlockKind::StrippedJungleWood => "stripped_jungle_wood", + BlockKind::StrippedAcaciaWood => "stripped_acacia_wood", + BlockKind::StrippedDarkOakWood => "stripped_dark_oak_wood", + BlockKind::OakLeaves => "oak_leaves", + BlockKind::SpruceLeaves => "spruce_leaves", + BlockKind::BirchLeaves => "birch_leaves", + BlockKind::JungleLeaves => "jungle_leaves", + BlockKind::AcaciaLeaves => "acacia_leaves", + BlockKind::DarkOakLeaves => "dark_oak_leaves", + BlockKind::Sponge => "sponge", + BlockKind::WetSponge => "wet_sponge", + BlockKind::Glass => "glass", + BlockKind::LapisOre => "lapis_ore", + BlockKind::LapisBlock => "lapis_block", + BlockKind::Dispenser => "dispenser", + BlockKind::Sandstone => "sandstone", + BlockKind::ChiseledSandstone => "chiseled_sandstone", + BlockKind::CutSandstone => "cut_sandstone", + BlockKind::NoteBlock => "note_block", + BlockKind::WhiteBed => "white_bed", + BlockKind::OrangeBed => "orange_bed", + BlockKind::MagentaBed => "magenta_bed", + BlockKind::LightBlueBed => "light_blue_bed", + BlockKind::YellowBed => "yellow_bed", + BlockKind::LimeBed => "lime_bed", + BlockKind::PinkBed => "pink_bed", + BlockKind::GrayBed => "gray_bed", + BlockKind::LightGrayBed => "light_gray_bed", + BlockKind::CyanBed => "cyan_bed", + BlockKind::PurpleBed => "purple_bed", + BlockKind::BlueBed => "blue_bed", + BlockKind::BrownBed => "brown_bed", + BlockKind::GreenBed => "green_bed", + BlockKind::RedBed => "red_bed", + BlockKind::BlackBed => "black_bed", + BlockKind::PoweredRail => "powered_rail", + BlockKind::DetectorRail => "detector_rail", + BlockKind::StickyPiston => "sticky_piston", + BlockKind::Cobweb => "cobweb", + BlockKind::Grass => "grass", + BlockKind::Fern => "fern", + BlockKind::DeadBush => "dead_bush", + BlockKind::Seagrass => "seagrass", + BlockKind::TallSeagrass => "tall_seagrass", + BlockKind::Piston => "piston", + BlockKind::PistonHead => "piston_head", + BlockKind::WhiteWool => "white_wool", + BlockKind::OrangeWool => "orange_wool", + BlockKind::MagentaWool => "magenta_wool", + BlockKind::LightBlueWool => "light_blue_wool", + BlockKind::YellowWool => "yellow_wool", + BlockKind::LimeWool => "lime_wool", + BlockKind::PinkWool => "pink_wool", + BlockKind::GrayWool => "gray_wool", + BlockKind::LightGrayWool => "light_gray_wool", + BlockKind::CyanWool => "cyan_wool", + BlockKind::PurpleWool => "purple_wool", + BlockKind::BlueWool => "blue_wool", + BlockKind::BrownWool => "brown_wool", + BlockKind::GreenWool => "green_wool", + BlockKind::RedWool => "red_wool", + BlockKind::BlackWool => "black_wool", + BlockKind::MovingPiston => "moving_piston", + BlockKind::Dandelion => "dandelion", + BlockKind::Poppy => "poppy", + BlockKind::BlueOrchid => "blue_orchid", + BlockKind::Allium => "allium", + BlockKind::AzureBluet => "azure_bluet", + BlockKind::RedTulip => "red_tulip", + BlockKind::OrangeTulip => "orange_tulip", + BlockKind::WhiteTulip => "white_tulip", + BlockKind::PinkTulip => "pink_tulip", + BlockKind::OxeyeDaisy => "oxeye_daisy", + BlockKind::Cornflower => "cornflower", + BlockKind::WitherRose => "wither_rose", + BlockKind::LilyOfTheValley => "lily_of_the_valley", + BlockKind::BrownMushroom => "brown_mushroom", + BlockKind::RedMushroom => "red_mushroom", + BlockKind::GoldBlock => "gold_block", + BlockKind::IronBlock => "iron_block", + BlockKind::Bricks => "bricks", + BlockKind::Tnt => "tnt", + BlockKind::Bookshelf => "bookshelf", + BlockKind::MossyCobblestone => "mossy_cobblestone", + BlockKind::Obsidian => "obsidian", + BlockKind::Torch => "torch", + BlockKind::WallTorch => "wall_torch", + BlockKind::Fire => "fire", + BlockKind::SoulFire => "soul_fire", + BlockKind::Spawner => "spawner", + BlockKind::OakStairs => "oak_stairs", + BlockKind::Chest => "chest", + BlockKind::RedstoneWire => "redstone_wire", + BlockKind::DiamondOre => "diamond_ore", + BlockKind::DiamondBlock => "diamond_block", + BlockKind::CraftingTable => "crafting_table", + BlockKind::Wheat => "wheat", + BlockKind::Farmland => "farmland", + BlockKind::Furnace => "furnace", + BlockKind::OakSign => "oak_sign", + BlockKind::SpruceSign => "spruce_sign", + BlockKind::BirchSign => "birch_sign", + BlockKind::AcaciaSign => "acacia_sign", + BlockKind::JungleSign => "jungle_sign", + BlockKind::DarkOakSign => "dark_oak_sign", + BlockKind::OakDoor => "oak_door", + BlockKind::Ladder => "ladder", + BlockKind::Rail => "rail", + BlockKind::CobblestoneStairs => "cobblestone_stairs", + BlockKind::OakWallSign => "oak_wall_sign", + BlockKind::SpruceWallSign => "spruce_wall_sign", + BlockKind::BirchWallSign => "birch_wall_sign", + BlockKind::AcaciaWallSign => "acacia_wall_sign", + BlockKind::JungleWallSign => "jungle_wall_sign", + BlockKind::DarkOakWallSign => "dark_oak_wall_sign", + BlockKind::Lever => "lever", + BlockKind::StonePressurePlate => "stone_pressure_plate", + BlockKind::IronDoor => "iron_door", + BlockKind::OakPressurePlate => "oak_pressure_plate", + BlockKind::SprucePressurePlate => "spruce_pressure_plate", + BlockKind::BirchPressurePlate => "birch_pressure_plate", + BlockKind::JunglePressurePlate => "jungle_pressure_plate", + BlockKind::AcaciaPressurePlate => "acacia_pressure_plate", + BlockKind::DarkOakPressurePlate => "dark_oak_pressure_plate", + BlockKind::RedstoneOre => "redstone_ore", + BlockKind::RedstoneTorch => "redstone_torch", + BlockKind::RedstoneWallTorch => "redstone_wall_torch", + BlockKind::StoneButton => "stone_button", + BlockKind::Snow => "snow", + BlockKind::Ice => "ice", + BlockKind::SnowBlock => "snow_block", + BlockKind::Cactus => "cactus", + BlockKind::Clay => "clay", + BlockKind::SugarCane => "sugar_cane", + BlockKind::Jukebox => "jukebox", + BlockKind::OakFence => "oak_fence", + BlockKind::Pumpkin => "pumpkin", + BlockKind::Netherrack => "netherrack", + BlockKind::SoulSand => "soul_sand", + BlockKind::SoulSoil => "soul_soil", + BlockKind::Basalt => "basalt", + BlockKind::PolishedBasalt => "polished_basalt", + BlockKind::SoulTorch => "soul_torch", + BlockKind::SoulWallTorch => "soul_wall_torch", + BlockKind::Glowstone => "glowstone", + BlockKind::NetherPortal => "nether_portal", + BlockKind::CarvedPumpkin => "carved_pumpkin", + BlockKind::JackOLantern => "jack_o_lantern", + BlockKind::Cake => "cake", + BlockKind::Repeater => "repeater", + BlockKind::WhiteStainedGlass => "white_stained_glass", + BlockKind::OrangeStainedGlass => "orange_stained_glass", + BlockKind::MagentaStainedGlass => "magenta_stained_glass", + BlockKind::LightBlueStainedGlass => "light_blue_stained_glass", + BlockKind::YellowStainedGlass => "yellow_stained_glass", + BlockKind::LimeStainedGlass => "lime_stained_glass", + BlockKind::PinkStainedGlass => "pink_stained_glass", + BlockKind::GrayStainedGlass => "gray_stained_glass", + BlockKind::LightGrayStainedGlass => "light_gray_stained_glass", + BlockKind::CyanStainedGlass => "cyan_stained_glass", + BlockKind::PurpleStainedGlass => "purple_stained_glass", + BlockKind::BlueStainedGlass => "blue_stained_glass", + BlockKind::BrownStainedGlass => "brown_stained_glass", + BlockKind::GreenStainedGlass => "green_stained_glass", + BlockKind::RedStainedGlass => "red_stained_glass", + BlockKind::BlackStainedGlass => "black_stained_glass", + BlockKind::OakTrapdoor => "oak_trapdoor", + BlockKind::SpruceTrapdoor => "spruce_trapdoor", + BlockKind::BirchTrapdoor => "birch_trapdoor", + BlockKind::JungleTrapdoor => "jungle_trapdoor", + BlockKind::AcaciaTrapdoor => "acacia_trapdoor", + BlockKind::DarkOakTrapdoor => "dark_oak_trapdoor", + BlockKind::StoneBricks => "stone_bricks", + BlockKind::MossyStoneBricks => "mossy_stone_bricks", + BlockKind::CrackedStoneBricks => "cracked_stone_bricks", + BlockKind::ChiseledStoneBricks => "chiseled_stone_bricks", + BlockKind::InfestedStone => "infested_stone", + BlockKind::InfestedCobblestone => "infested_cobblestone", + BlockKind::InfestedStoneBricks => "infested_stone_bricks", + BlockKind::InfestedMossyStoneBricks => "infested_mossy_stone_bricks", + BlockKind::InfestedCrackedStoneBricks => "infested_cracked_stone_bricks", + BlockKind::InfestedChiseledStoneBricks => "infested_chiseled_stone_bricks", + BlockKind::BrownMushroomBlock => "brown_mushroom_block", + BlockKind::RedMushroomBlock => "red_mushroom_block", + BlockKind::MushroomStem => "mushroom_stem", + BlockKind::IronBars => "iron_bars", + BlockKind::Chain => "chain", + BlockKind::GlassPane => "glass_pane", + BlockKind::Melon => "melon", + BlockKind::AttachedPumpkinStem => "attached_pumpkin_stem", + BlockKind::AttachedMelonStem => "attached_melon_stem", + BlockKind::PumpkinStem => "pumpkin_stem", + BlockKind::MelonStem => "melon_stem", + BlockKind::Vine => "vine", + BlockKind::OakFenceGate => "oak_fence_gate", + BlockKind::BrickStairs => "brick_stairs", + BlockKind::StoneBrickStairs => "stone_brick_stairs", + BlockKind::Mycelium => "mycelium", + BlockKind::LilyPad => "lily_pad", + BlockKind::NetherBricks => "nether_bricks", + BlockKind::NetherBrickFence => "nether_brick_fence", + BlockKind::NetherBrickStairs => "nether_brick_stairs", + BlockKind::NetherWart => "nether_wart", + BlockKind::EnchantingTable => "enchanting_table", + BlockKind::BrewingStand => "brewing_stand", + BlockKind::Cauldron => "cauldron", + BlockKind::EndPortal => "end_portal", + BlockKind::EndPortalFrame => "end_portal_frame", + BlockKind::EndStone => "end_stone", + BlockKind::DragonEgg => "dragon_egg", + BlockKind::RedstoneLamp => "redstone_lamp", + BlockKind::Cocoa => "cocoa", + BlockKind::SandstoneStairs => "sandstone_stairs", + BlockKind::EmeraldOre => "emerald_ore", + BlockKind::EnderChest => "ender_chest", + BlockKind::TripwireHook => "tripwire_hook", + BlockKind::Tripwire => "tripwire", + BlockKind::EmeraldBlock => "emerald_block", + BlockKind::SpruceStairs => "spruce_stairs", + BlockKind::BirchStairs => "birch_stairs", + BlockKind::JungleStairs => "jungle_stairs", + BlockKind::CommandBlock => "command_block", + BlockKind::Beacon => "beacon", + BlockKind::CobblestoneWall => "cobblestone_wall", + BlockKind::MossyCobblestoneWall => "mossy_cobblestone_wall", + BlockKind::FlowerPot => "flower_pot", + BlockKind::PottedOakSapling => "potted_oak_sapling", + BlockKind::PottedSpruceSapling => "potted_spruce_sapling", + BlockKind::PottedBirchSapling => "potted_birch_sapling", + BlockKind::PottedJungleSapling => "potted_jungle_sapling", + BlockKind::PottedAcaciaSapling => "potted_acacia_sapling", + BlockKind::PottedDarkOakSapling => "potted_dark_oak_sapling", + BlockKind::PottedFern => "potted_fern", + BlockKind::PottedDandelion => "potted_dandelion", + BlockKind::PottedPoppy => "potted_poppy", + BlockKind::PottedBlueOrchid => "potted_blue_orchid", + BlockKind::PottedAllium => "potted_allium", + BlockKind::PottedAzureBluet => "potted_azure_bluet", + BlockKind::PottedRedTulip => "potted_red_tulip", + BlockKind::PottedOrangeTulip => "potted_orange_tulip", + BlockKind::PottedWhiteTulip => "potted_white_tulip", + BlockKind::PottedPinkTulip => "potted_pink_tulip", + BlockKind::PottedOxeyeDaisy => "potted_oxeye_daisy", + BlockKind::PottedCornflower => "potted_cornflower", + BlockKind::PottedLilyOfTheValley => "potted_lily_of_the_valley", + BlockKind::PottedWitherRose => "potted_wither_rose", + BlockKind::PottedRedMushroom => "potted_red_mushroom", + BlockKind::PottedBrownMushroom => "potted_brown_mushroom", + BlockKind::PottedDeadBush => "potted_dead_bush", + BlockKind::PottedCactus => "potted_cactus", + BlockKind::Carrots => "carrots", + BlockKind::Potatoes => "potatoes", + BlockKind::OakButton => "oak_button", + BlockKind::SpruceButton => "spruce_button", + BlockKind::BirchButton => "birch_button", + BlockKind::JungleButton => "jungle_button", + BlockKind::AcaciaButton => "acacia_button", + BlockKind::DarkOakButton => "dark_oak_button", + BlockKind::SkeletonSkull => "skeleton_skull", + BlockKind::SkeletonWallSkull => "skeleton_wall_skull", + BlockKind::WitherSkeletonSkull => "wither_skeleton_skull", + BlockKind::WitherSkeletonWallSkull => "wither_skeleton_wall_skull", + BlockKind::ZombieHead => "zombie_head", + BlockKind::ZombieWallHead => "zombie_wall_head", + BlockKind::PlayerHead => "player_head", + BlockKind::PlayerWallHead => "player_wall_head", + BlockKind::CreeperHead => "creeper_head", + BlockKind::CreeperWallHead => "creeper_wall_head", + BlockKind::DragonHead => "dragon_head", + BlockKind::DragonWallHead => "dragon_wall_head", + BlockKind::Anvil => "anvil", + BlockKind::ChippedAnvil => "chipped_anvil", + BlockKind::DamagedAnvil => "damaged_anvil", + BlockKind::TrappedChest => "trapped_chest", + BlockKind::LightWeightedPressurePlate => "light_weighted_pressure_plate", + BlockKind::HeavyWeightedPressurePlate => "heavy_weighted_pressure_plate", + BlockKind::Comparator => "comparator", + BlockKind::DaylightDetector => "daylight_detector", + BlockKind::RedstoneBlock => "redstone_block", + BlockKind::NetherQuartzOre => "nether_quartz_ore", + BlockKind::Hopper => "hopper", + BlockKind::QuartzBlock => "quartz_block", + BlockKind::ChiseledQuartzBlock => "chiseled_quartz_block", + BlockKind::QuartzPillar => "quartz_pillar", + BlockKind::QuartzStairs => "quartz_stairs", + BlockKind::ActivatorRail => "activator_rail", + BlockKind::Dropper => "dropper", + BlockKind::WhiteTerracotta => "white_terracotta", + BlockKind::OrangeTerracotta => "orange_terracotta", + BlockKind::MagentaTerracotta => "magenta_terracotta", + BlockKind::LightBlueTerracotta => "light_blue_terracotta", + BlockKind::YellowTerracotta => "yellow_terracotta", + BlockKind::LimeTerracotta => "lime_terracotta", + BlockKind::PinkTerracotta => "pink_terracotta", + BlockKind::GrayTerracotta => "gray_terracotta", + BlockKind::LightGrayTerracotta => "light_gray_terracotta", + BlockKind::CyanTerracotta => "cyan_terracotta", + BlockKind::PurpleTerracotta => "purple_terracotta", + BlockKind::BlueTerracotta => "blue_terracotta", + BlockKind::BrownTerracotta => "brown_terracotta", + BlockKind::GreenTerracotta => "green_terracotta", + BlockKind::RedTerracotta => "red_terracotta", + BlockKind::BlackTerracotta => "black_terracotta", + BlockKind::WhiteStainedGlassPane => "white_stained_glass_pane", + BlockKind::OrangeStainedGlassPane => "orange_stained_glass_pane", + BlockKind::MagentaStainedGlassPane => "magenta_stained_glass_pane", + BlockKind::LightBlueStainedGlassPane => "light_blue_stained_glass_pane", + BlockKind::YellowStainedGlassPane => "yellow_stained_glass_pane", + BlockKind::LimeStainedGlassPane => "lime_stained_glass_pane", + BlockKind::PinkStainedGlassPane => "pink_stained_glass_pane", + BlockKind::GrayStainedGlassPane => "gray_stained_glass_pane", + BlockKind::LightGrayStainedGlassPane => "light_gray_stained_glass_pane", + BlockKind::CyanStainedGlassPane => "cyan_stained_glass_pane", + BlockKind::PurpleStainedGlassPane => "purple_stained_glass_pane", + BlockKind::BlueStainedGlassPane => "blue_stained_glass_pane", + BlockKind::BrownStainedGlassPane => "brown_stained_glass_pane", + BlockKind::GreenStainedGlassPane => "green_stained_glass_pane", + BlockKind::RedStainedGlassPane => "red_stained_glass_pane", + BlockKind::BlackStainedGlassPane => "black_stained_glass_pane", + BlockKind::AcaciaStairs => "acacia_stairs", + BlockKind::DarkOakStairs => "dark_oak_stairs", + BlockKind::SlimeBlock => "slime_block", + BlockKind::Barrier => "barrier", + BlockKind::IronTrapdoor => "iron_trapdoor", + BlockKind::Prismarine => "prismarine", + BlockKind::PrismarineBricks => "prismarine_bricks", + BlockKind::DarkPrismarine => "dark_prismarine", + BlockKind::PrismarineStairs => "prismarine_stairs", + BlockKind::PrismarineBrickStairs => "prismarine_brick_stairs", + BlockKind::DarkPrismarineStairs => "dark_prismarine_stairs", + BlockKind::PrismarineSlab => "prismarine_slab", + BlockKind::PrismarineBrickSlab => "prismarine_brick_slab", + BlockKind::DarkPrismarineSlab => "dark_prismarine_slab", + BlockKind::SeaLantern => "sea_lantern", + BlockKind::HayBlock => "hay_block", + BlockKind::WhiteCarpet => "white_carpet", + BlockKind::OrangeCarpet => "orange_carpet", + BlockKind::MagentaCarpet => "magenta_carpet", + BlockKind::LightBlueCarpet => "light_blue_carpet", + BlockKind::YellowCarpet => "yellow_carpet", + BlockKind::LimeCarpet => "lime_carpet", + BlockKind::PinkCarpet => "pink_carpet", + BlockKind::GrayCarpet => "gray_carpet", + BlockKind::LightGrayCarpet => "light_gray_carpet", + BlockKind::CyanCarpet => "cyan_carpet", + BlockKind::PurpleCarpet => "purple_carpet", + BlockKind::BlueCarpet => "blue_carpet", + BlockKind::BrownCarpet => "brown_carpet", + BlockKind::GreenCarpet => "green_carpet", + BlockKind::RedCarpet => "red_carpet", + BlockKind::BlackCarpet => "black_carpet", + BlockKind::Terracotta => "terracotta", + BlockKind::CoalBlock => "coal_block", + BlockKind::PackedIce => "packed_ice", + BlockKind::Sunflower => "sunflower", + BlockKind::Lilac => "lilac", + BlockKind::RoseBush => "rose_bush", + BlockKind::Peony => "peony", + BlockKind::TallGrass => "tall_grass", + BlockKind::LargeFern => "large_fern", + BlockKind::WhiteBanner => "white_banner", + BlockKind::OrangeBanner => "orange_banner", + BlockKind::MagentaBanner => "magenta_banner", + BlockKind::LightBlueBanner => "light_blue_banner", + BlockKind::YellowBanner => "yellow_banner", + BlockKind::LimeBanner => "lime_banner", + BlockKind::PinkBanner => "pink_banner", + BlockKind::GrayBanner => "gray_banner", + BlockKind::LightGrayBanner => "light_gray_banner", + BlockKind::CyanBanner => "cyan_banner", + BlockKind::PurpleBanner => "purple_banner", + BlockKind::BlueBanner => "blue_banner", + BlockKind::BrownBanner => "brown_banner", + BlockKind::GreenBanner => "green_banner", + BlockKind::RedBanner => "red_banner", + BlockKind::BlackBanner => "black_banner", + BlockKind::WhiteWallBanner => "white_wall_banner", + BlockKind::OrangeWallBanner => "orange_wall_banner", + BlockKind::MagentaWallBanner => "magenta_wall_banner", + BlockKind::LightBlueWallBanner => "light_blue_wall_banner", + BlockKind::YellowWallBanner => "yellow_wall_banner", + BlockKind::LimeWallBanner => "lime_wall_banner", + BlockKind::PinkWallBanner => "pink_wall_banner", + BlockKind::GrayWallBanner => "gray_wall_banner", + BlockKind::LightGrayWallBanner => "light_gray_wall_banner", + BlockKind::CyanWallBanner => "cyan_wall_banner", + BlockKind::PurpleWallBanner => "purple_wall_banner", + BlockKind::BlueWallBanner => "blue_wall_banner", + BlockKind::BrownWallBanner => "brown_wall_banner", + BlockKind::GreenWallBanner => "green_wall_banner", + BlockKind::RedWallBanner => "red_wall_banner", + BlockKind::BlackWallBanner => "black_wall_banner", + BlockKind::RedSandstone => "red_sandstone", + BlockKind::ChiseledRedSandstone => "chiseled_red_sandstone", + BlockKind::CutRedSandstone => "cut_red_sandstone", + BlockKind::RedSandstoneStairs => "red_sandstone_stairs", + BlockKind::OakSlab => "oak_slab", + BlockKind::SpruceSlab => "spruce_slab", + BlockKind::BirchSlab => "birch_slab", + BlockKind::JungleSlab => "jungle_slab", + BlockKind::AcaciaSlab => "acacia_slab", + BlockKind::DarkOakSlab => "dark_oak_slab", + BlockKind::StoneSlab => "stone_slab", + BlockKind::SmoothStoneSlab => "smooth_stone_slab", + BlockKind::SandstoneSlab => "sandstone_slab", + BlockKind::CutSandstoneSlab => "cut_sandstone_slab", + BlockKind::PetrifiedOakSlab => "petrified_oak_slab", + BlockKind::CobblestoneSlab => "cobblestone_slab", + BlockKind::BrickSlab => "brick_slab", + BlockKind::StoneBrickSlab => "stone_brick_slab", + BlockKind::NetherBrickSlab => "nether_brick_slab", + BlockKind::QuartzSlab => "quartz_slab", + BlockKind::RedSandstoneSlab => "red_sandstone_slab", + BlockKind::CutRedSandstoneSlab => "cut_red_sandstone_slab", + BlockKind::PurpurSlab => "purpur_slab", + BlockKind::SmoothStone => "smooth_stone", + BlockKind::SmoothSandstone => "smooth_sandstone", + BlockKind::SmoothQuartz => "smooth_quartz", + BlockKind::SmoothRedSandstone => "smooth_red_sandstone", + BlockKind::SpruceFenceGate => "spruce_fence_gate", + BlockKind::BirchFenceGate => "birch_fence_gate", + BlockKind::JungleFenceGate => "jungle_fence_gate", + BlockKind::AcaciaFenceGate => "acacia_fence_gate", + BlockKind::DarkOakFenceGate => "dark_oak_fence_gate", + BlockKind::SpruceFence => "spruce_fence", + BlockKind::BirchFence => "birch_fence", + BlockKind::JungleFence => "jungle_fence", + BlockKind::AcaciaFence => "acacia_fence", + BlockKind::DarkOakFence => "dark_oak_fence", + BlockKind::SpruceDoor => "spruce_door", + BlockKind::BirchDoor => "birch_door", + BlockKind::JungleDoor => "jungle_door", + BlockKind::AcaciaDoor => "acacia_door", + BlockKind::DarkOakDoor => "dark_oak_door", + BlockKind::EndRod => "end_rod", + BlockKind::ChorusPlant => "chorus_plant", + BlockKind::ChorusFlower => "chorus_flower", + BlockKind::PurpurBlock => "purpur_block", + BlockKind::PurpurPillar => "purpur_pillar", + BlockKind::PurpurStairs => "purpur_stairs", + BlockKind::EndStoneBricks => "end_stone_bricks", + BlockKind::Beetroots => "beetroots", + BlockKind::GrassPath => "grass_path", + BlockKind::EndGateway => "end_gateway", + BlockKind::RepeatingCommandBlock => "repeating_command_block", + BlockKind::ChainCommandBlock => "chain_command_block", + BlockKind::FrostedIce => "frosted_ice", + BlockKind::MagmaBlock => "magma_block", + BlockKind::NetherWartBlock => "nether_wart_block", + BlockKind::RedNetherBricks => "red_nether_bricks", + BlockKind::BoneBlock => "bone_block", + BlockKind::StructureVoid => "structure_void", + BlockKind::Observer => "observer", + BlockKind::ShulkerBox => "shulker_box", + BlockKind::WhiteShulkerBox => "white_shulker_box", + BlockKind::OrangeShulkerBox => "orange_shulker_box", + BlockKind::MagentaShulkerBox => "magenta_shulker_box", + BlockKind::LightBlueShulkerBox => "light_blue_shulker_box", + BlockKind::YellowShulkerBox => "yellow_shulker_box", + BlockKind::LimeShulkerBox => "lime_shulker_box", + BlockKind::PinkShulkerBox => "pink_shulker_box", + BlockKind::GrayShulkerBox => "gray_shulker_box", + BlockKind::LightGrayShulkerBox => "light_gray_shulker_box", + BlockKind::CyanShulkerBox => "cyan_shulker_box", + BlockKind::PurpleShulkerBox => "purple_shulker_box", + BlockKind::BlueShulkerBox => "blue_shulker_box", + BlockKind::BrownShulkerBox => "brown_shulker_box", + BlockKind::GreenShulkerBox => "green_shulker_box", + BlockKind::RedShulkerBox => "red_shulker_box", + BlockKind::BlackShulkerBox => "black_shulker_box", + BlockKind::WhiteGlazedTerracotta => "white_glazed_terracotta", + BlockKind::OrangeGlazedTerracotta => "orange_glazed_terracotta", + BlockKind::MagentaGlazedTerracotta => "magenta_glazed_terracotta", + BlockKind::LightBlueGlazedTerracotta => "light_blue_glazed_terracotta", + BlockKind::YellowGlazedTerracotta => "yellow_glazed_terracotta", + BlockKind::LimeGlazedTerracotta => "lime_glazed_terracotta", + BlockKind::PinkGlazedTerracotta => "pink_glazed_terracotta", + BlockKind::GrayGlazedTerracotta => "gray_glazed_terracotta", + BlockKind::LightGrayGlazedTerracotta => "light_gray_glazed_terracotta", + BlockKind::CyanGlazedTerracotta => "cyan_glazed_terracotta", + BlockKind::PurpleGlazedTerracotta => "purple_glazed_terracotta", + BlockKind::BlueGlazedTerracotta => "blue_glazed_terracotta", + BlockKind::BrownGlazedTerracotta => "brown_glazed_terracotta", + BlockKind::GreenGlazedTerracotta => "green_glazed_terracotta", + BlockKind::RedGlazedTerracotta => "red_glazed_terracotta", + BlockKind::BlackGlazedTerracotta => "black_glazed_terracotta", + BlockKind::WhiteConcrete => "white_concrete", + BlockKind::OrangeConcrete => "orange_concrete", + BlockKind::MagentaConcrete => "magenta_concrete", + BlockKind::LightBlueConcrete => "light_blue_concrete", + BlockKind::YellowConcrete => "yellow_concrete", + BlockKind::LimeConcrete => "lime_concrete", + BlockKind::PinkConcrete => "pink_concrete", + BlockKind::GrayConcrete => "gray_concrete", + BlockKind::LightGrayConcrete => "light_gray_concrete", + BlockKind::CyanConcrete => "cyan_concrete", + BlockKind::PurpleConcrete => "purple_concrete", + BlockKind::BlueConcrete => "blue_concrete", + BlockKind::BrownConcrete => "brown_concrete", + BlockKind::GreenConcrete => "green_concrete", + BlockKind::RedConcrete => "red_concrete", + BlockKind::BlackConcrete => "black_concrete", + BlockKind::WhiteConcretePowder => "white_concrete_powder", + BlockKind::OrangeConcretePowder => "orange_concrete_powder", + BlockKind::MagentaConcretePowder => "magenta_concrete_powder", + BlockKind::LightBlueConcretePowder => "light_blue_concrete_powder", + BlockKind::YellowConcretePowder => "yellow_concrete_powder", + BlockKind::LimeConcretePowder => "lime_concrete_powder", + BlockKind::PinkConcretePowder => "pink_concrete_powder", + BlockKind::GrayConcretePowder => "gray_concrete_powder", + BlockKind::LightGrayConcretePowder => "light_gray_concrete_powder", + BlockKind::CyanConcretePowder => "cyan_concrete_powder", + BlockKind::PurpleConcretePowder => "purple_concrete_powder", + BlockKind::BlueConcretePowder => "blue_concrete_powder", + BlockKind::BrownConcretePowder => "brown_concrete_powder", + BlockKind::GreenConcretePowder => "green_concrete_powder", + BlockKind::RedConcretePowder => "red_concrete_powder", + BlockKind::BlackConcretePowder => "black_concrete_powder", + BlockKind::Kelp => "kelp", + BlockKind::KelpPlant => "kelp_plant", + BlockKind::DriedKelpBlock => "dried_kelp_block", + BlockKind::TurtleEgg => "turtle_egg", + BlockKind::DeadTubeCoralBlock => "dead_tube_coral_block", + BlockKind::DeadBrainCoralBlock => "dead_brain_coral_block", + BlockKind::DeadBubbleCoralBlock => "dead_bubble_coral_block", + BlockKind::DeadFireCoralBlock => "dead_fire_coral_block", + BlockKind::DeadHornCoralBlock => "dead_horn_coral_block", + BlockKind::TubeCoralBlock => "tube_coral_block", + BlockKind::BrainCoralBlock => "brain_coral_block", + BlockKind::BubbleCoralBlock => "bubble_coral_block", + BlockKind::FireCoralBlock => "fire_coral_block", + BlockKind::HornCoralBlock => "horn_coral_block", + BlockKind::DeadTubeCoral => "dead_tube_coral", + BlockKind::DeadBrainCoral => "dead_brain_coral", + BlockKind::DeadBubbleCoral => "dead_bubble_coral", + BlockKind::DeadFireCoral => "dead_fire_coral", + BlockKind::DeadHornCoral => "dead_horn_coral", + BlockKind::TubeCoral => "tube_coral", + BlockKind::BrainCoral => "brain_coral", + BlockKind::BubbleCoral => "bubble_coral", + BlockKind::FireCoral => "fire_coral", + BlockKind::HornCoral => "horn_coral", + BlockKind::DeadTubeCoralFan => "dead_tube_coral_fan", + BlockKind::DeadBrainCoralFan => "dead_brain_coral_fan", + BlockKind::DeadBubbleCoralFan => "dead_bubble_coral_fan", + BlockKind::DeadFireCoralFan => "dead_fire_coral_fan", + BlockKind::DeadHornCoralFan => "dead_horn_coral_fan", + BlockKind::TubeCoralFan => "tube_coral_fan", + BlockKind::BrainCoralFan => "brain_coral_fan", + BlockKind::BubbleCoralFan => "bubble_coral_fan", + BlockKind::FireCoralFan => "fire_coral_fan", + BlockKind::HornCoralFan => "horn_coral_fan", + BlockKind::DeadTubeCoralWallFan => "dead_tube_coral_wall_fan", + BlockKind::DeadBrainCoralWallFan => "dead_brain_coral_wall_fan", + BlockKind::DeadBubbleCoralWallFan => "dead_bubble_coral_wall_fan", + BlockKind::DeadFireCoralWallFan => "dead_fire_coral_wall_fan", + BlockKind::DeadHornCoralWallFan => "dead_horn_coral_wall_fan", + BlockKind::TubeCoralWallFan => "tube_coral_wall_fan", + BlockKind::BrainCoralWallFan => "brain_coral_wall_fan", + BlockKind::BubbleCoralWallFan => "bubble_coral_wall_fan", + BlockKind::FireCoralWallFan => "fire_coral_wall_fan", + BlockKind::HornCoralWallFan => "horn_coral_wall_fan", + BlockKind::SeaPickle => "sea_pickle", + BlockKind::BlueIce => "blue_ice", + BlockKind::Conduit => "conduit", + BlockKind::BambooSapling => "bamboo_sapling", + BlockKind::Bamboo => "bamboo", + BlockKind::PottedBamboo => "potted_bamboo", + BlockKind::VoidAir => "void_air", + BlockKind::CaveAir => "cave_air", + BlockKind::BubbleColumn => "bubble_column", + BlockKind::PolishedGraniteStairs => "polished_granite_stairs", + BlockKind::SmoothRedSandstoneStairs => "smooth_red_sandstone_stairs", + BlockKind::MossyStoneBrickStairs => "mossy_stone_brick_stairs", + BlockKind::PolishedDioriteStairs => "polished_diorite_stairs", + BlockKind::MossyCobblestoneStairs => "mossy_cobblestone_stairs", + BlockKind::EndStoneBrickStairs => "end_stone_brick_stairs", + BlockKind::StoneStairs => "stone_stairs", + BlockKind::SmoothSandstoneStairs => "smooth_sandstone_stairs", + BlockKind::SmoothQuartzStairs => "smooth_quartz_stairs", + BlockKind::GraniteStairs => "granite_stairs", + BlockKind::AndesiteStairs => "andesite_stairs", + BlockKind::RedNetherBrickStairs => "red_nether_brick_stairs", + BlockKind::PolishedAndesiteStairs => "polished_andesite_stairs", + BlockKind::DioriteStairs => "diorite_stairs", + BlockKind::PolishedGraniteSlab => "polished_granite_slab", + BlockKind::SmoothRedSandstoneSlab => "smooth_red_sandstone_slab", + BlockKind::MossyStoneBrickSlab => "mossy_stone_brick_slab", + BlockKind::PolishedDioriteSlab => "polished_diorite_slab", + BlockKind::MossyCobblestoneSlab => "mossy_cobblestone_slab", + BlockKind::EndStoneBrickSlab => "end_stone_brick_slab", + BlockKind::SmoothSandstoneSlab => "smooth_sandstone_slab", + BlockKind::SmoothQuartzSlab => "smooth_quartz_slab", + BlockKind::GraniteSlab => "granite_slab", + BlockKind::AndesiteSlab => "andesite_slab", + BlockKind::RedNetherBrickSlab => "red_nether_brick_slab", + BlockKind::PolishedAndesiteSlab => "polished_andesite_slab", + BlockKind::DioriteSlab => "diorite_slab", + BlockKind::BrickWall => "brick_wall", + BlockKind::PrismarineWall => "prismarine_wall", + BlockKind::RedSandstoneWall => "red_sandstone_wall", + BlockKind::MossyStoneBrickWall => "mossy_stone_brick_wall", + BlockKind::GraniteWall => "granite_wall", + BlockKind::StoneBrickWall => "stone_brick_wall", + BlockKind::NetherBrickWall => "nether_brick_wall", + BlockKind::AndesiteWall => "andesite_wall", + BlockKind::RedNetherBrickWall => "red_nether_brick_wall", + BlockKind::SandstoneWall => "sandstone_wall", + BlockKind::EndStoneBrickWall => "end_stone_brick_wall", + BlockKind::DioriteWall => "diorite_wall", + BlockKind::Scaffolding => "scaffolding", + BlockKind::Loom => "loom", + BlockKind::Barrel => "barrel", + BlockKind::Smoker => "smoker", + BlockKind::BlastFurnace => "blast_furnace", + BlockKind::CartographyTable => "cartography_table", + BlockKind::FletchingTable => "fletching_table", + BlockKind::Grindstone => "grindstone", + BlockKind::Lectern => "lectern", + BlockKind::SmithingTable => "smithing_table", + BlockKind::Stonecutter => "stonecutter", + BlockKind::Bell => "bell", + BlockKind::Lantern => "lantern", + BlockKind::SoulLantern => "soul_lantern", + BlockKind::Campfire => "campfire", + BlockKind::SoulCampfire => "soul_campfire", + BlockKind::SweetBerryBush => "sweet_berry_bush", + BlockKind::WarpedStem => "warped_stem", + BlockKind::StrippedWarpedStem => "stripped_warped_stem", + BlockKind::WarpedHyphae => "warped_hyphae", + BlockKind::StrippedWarpedHyphae => "stripped_warped_hyphae", + BlockKind::WarpedNylium => "warped_nylium", + BlockKind::WarpedFungus => "warped_fungus", + BlockKind::WarpedWartBlock => "warped_wart_block", + BlockKind::WarpedRoots => "warped_roots", + BlockKind::NetherSprouts => "nether_sprouts", + BlockKind::CrimsonStem => "crimson_stem", + BlockKind::StrippedCrimsonStem => "stripped_crimson_stem", + BlockKind::CrimsonHyphae => "crimson_hyphae", + BlockKind::StrippedCrimsonHyphae => "stripped_crimson_hyphae", + BlockKind::CrimsonNylium => "crimson_nylium", + BlockKind::CrimsonFungus => "crimson_fungus", + BlockKind::Shroomlight => "shroomlight", + BlockKind::WeepingVines => "weeping_vines", + BlockKind::WeepingVinesPlant => "weeping_vines_plant", + BlockKind::TwistingVines => "twisting_vines", + BlockKind::TwistingVinesPlant => "twisting_vines_plant", + BlockKind::CrimsonRoots => "crimson_roots", + BlockKind::CrimsonPlanks => "crimson_planks", + BlockKind::WarpedPlanks => "warped_planks", + BlockKind::CrimsonSlab => "crimson_slab", + BlockKind::WarpedSlab => "warped_slab", + BlockKind::CrimsonPressurePlate => "crimson_pressure_plate", + BlockKind::WarpedPressurePlate => "warped_pressure_plate", + BlockKind::CrimsonFence => "crimson_fence", + BlockKind::WarpedFence => "warped_fence", + BlockKind::CrimsonTrapdoor => "crimson_trapdoor", + BlockKind::WarpedTrapdoor => "warped_trapdoor", + BlockKind::CrimsonFenceGate => "crimson_fence_gate", + BlockKind::WarpedFenceGate => "warped_fence_gate", + BlockKind::CrimsonStairs => "crimson_stairs", + BlockKind::WarpedStairs => "warped_stairs", + BlockKind::CrimsonButton => "crimson_button", + BlockKind::WarpedButton => "warped_button", + BlockKind::CrimsonDoor => "crimson_door", + BlockKind::WarpedDoor => "warped_door", + BlockKind::CrimsonSign => "crimson_sign", + BlockKind::WarpedSign => "warped_sign", + BlockKind::CrimsonWallSign => "crimson_wall_sign", + BlockKind::WarpedWallSign => "warped_wall_sign", + BlockKind::StructureBlock => "structure_block", + BlockKind::Jigsaw => "jigsaw", + BlockKind::Composter => "composter", + BlockKind::Target => "target", + BlockKind::BeeNest => "bee_nest", + BlockKind::Beehive => "beehive", + BlockKind::HoneyBlock => "honey_block", + BlockKind::HoneycombBlock => "honeycomb_block", + BlockKind::NetheriteBlock => "netherite_block", + BlockKind::AncientDebris => "ancient_debris", + BlockKind::CryingObsidian => "crying_obsidian", + BlockKind::RespawnAnchor => "respawn_anchor", + BlockKind::PottedCrimsonFungus => "potted_crimson_fungus", + BlockKind::PottedWarpedFungus => "potted_warped_fungus", + BlockKind::PottedCrimsonRoots => "potted_crimson_roots", + BlockKind::PottedWarpedRoots => "potted_warped_roots", + BlockKind::Lodestone => "lodestone", + BlockKind::Blackstone => "blackstone", + BlockKind::BlackstoneStairs => "blackstone_stairs", + BlockKind::BlackstoneWall => "blackstone_wall", + BlockKind::BlackstoneSlab => "blackstone_slab", + BlockKind::PolishedBlackstone => "polished_blackstone", + BlockKind::PolishedBlackstoneBricks => "polished_blackstone_bricks", + BlockKind::CrackedPolishedBlackstoneBricks => "cracked_polished_blackstone_bricks", + BlockKind::ChiseledPolishedBlackstone => "chiseled_polished_blackstone", + BlockKind::PolishedBlackstoneBrickSlab => "polished_blackstone_brick_slab", + BlockKind::PolishedBlackstoneBrickStairs => "polished_blackstone_brick_stairs", + BlockKind::PolishedBlackstoneBrickWall => "polished_blackstone_brick_wall", + BlockKind::GildedBlackstone => "gilded_blackstone", + BlockKind::PolishedBlackstoneStairs => "polished_blackstone_stairs", + BlockKind::PolishedBlackstoneSlab => "polished_blackstone_slab", + BlockKind::PolishedBlackstonePressurePlate => "polished_blackstone_pressure_plate", + BlockKind::PolishedBlackstoneButton => "polished_blackstone_button", + BlockKind::PolishedBlackstoneWall => "polished_blackstone_wall", + BlockKind::ChiseledNetherBricks => "chiseled_nether_bricks", + BlockKind::CrackedNetherBricks => "cracked_nether_bricks", + BlockKind::QuartzBricks => "quartz_bricks", + } + } + + /// Gets a `BlockKind` by its `name`. + pub fn from_name(name: &str) -> Option<Self> { + match name { + "air" => Some(BlockKind::Air), + "stone" => Some(BlockKind::Stone), + "granite" => Some(BlockKind::Granite), + "polished_granite" => Some(BlockKind::PolishedGranite), + "diorite" => Some(BlockKind::Diorite), + "polished_diorite" => Some(BlockKind::PolishedDiorite), + "andesite" => Some(BlockKind::Andesite), + "polished_andesite" => Some(BlockKind::PolishedAndesite), + "grass_block" => Some(BlockKind::GrassBlock), + "dirt" => Some(BlockKind::Dirt), + "coarse_dirt" => Some(BlockKind::CoarseDirt), + "podzol" => Some(BlockKind::Podzol), + "cobblestone" => Some(BlockKind::Cobblestone), + "oak_planks" => Some(BlockKind::OakPlanks), + "spruce_planks" => Some(BlockKind::SprucePlanks), + "birch_planks" => Some(BlockKind::BirchPlanks), + "jungle_planks" => Some(BlockKind::JunglePlanks), + "acacia_planks" => Some(BlockKind::AcaciaPlanks), + "dark_oak_planks" => Some(BlockKind::DarkOakPlanks), + "oak_sapling" => Some(BlockKind::OakSapling), + "spruce_sapling" => Some(BlockKind::SpruceSapling), + "birch_sapling" => Some(BlockKind::BirchSapling), + "jungle_sapling" => Some(BlockKind::JungleSapling), + "acacia_sapling" => Some(BlockKind::AcaciaSapling), + "dark_oak_sapling" => Some(BlockKind::DarkOakSapling), + "bedrock" => Some(BlockKind::Bedrock), + "water" => Some(BlockKind::Water), + "lava" => Some(BlockKind::Lava), + "sand" => Some(BlockKind::Sand), + "red_sand" => Some(BlockKind::RedSand), + "gravel" => Some(BlockKind::Gravel), + "gold_ore" => Some(BlockKind::GoldOre), + "iron_ore" => Some(BlockKind::IronOre), + "coal_ore" => Some(BlockKind::CoalOre), + "nether_gold_ore" => Some(BlockKind::NetherGoldOre), + "oak_log" => Some(BlockKind::OakLog), + "spruce_log" => Some(BlockKind::SpruceLog), + "birch_log" => Some(BlockKind::BirchLog), + "jungle_log" => Some(BlockKind::JungleLog), + "acacia_log" => Some(BlockKind::AcaciaLog), + "dark_oak_log" => Some(BlockKind::DarkOakLog), + "stripped_spruce_log" => Some(BlockKind::StrippedSpruceLog), + "stripped_birch_log" => Some(BlockKind::StrippedBirchLog), + "stripped_jungle_log" => Some(BlockKind::StrippedJungleLog), + "stripped_acacia_log" => Some(BlockKind::StrippedAcaciaLog), + "stripped_dark_oak_log" => Some(BlockKind::StrippedDarkOakLog), + "stripped_oak_log" => Some(BlockKind::StrippedOakLog), + "oak_wood" => Some(BlockKind::OakWood), + "spruce_wood" => Some(BlockKind::SpruceWood), + "birch_wood" => Some(BlockKind::BirchWood), + "jungle_wood" => Some(BlockKind::JungleWood), + "acacia_wood" => Some(BlockKind::AcaciaWood), + "dark_oak_wood" => Some(BlockKind::DarkOakWood), + "stripped_oak_wood" => Some(BlockKind::StrippedOakWood), + "stripped_spruce_wood" => Some(BlockKind::StrippedSpruceWood), + "stripped_birch_wood" => Some(BlockKind::StrippedBirchWood), + "stripped_jungle_wood" => Some(BlockKind::StrippedJungleWood), + "stripped_acacia_wood" => Some(BlockKind::StrippedAcaciaWood), + "stripped_dark_oak_wood" => Some(BlockKind::StrippedDarkOakWood), + "oak_leaves" => Some(BlockKind::OakLeaves), + "spruce_leaves" => Some(BlockKind::SpruceLeaves), + "birch_leaves" => Some(BlockKind::BirchLeaves), + "jungle_leaves" => Some(BlockKind::JungleLeaves), + "acacia_leaves" => Some(BlockKind::AcaciaLeaves), + "dark_oak_leaves" => Some(BlockKind::DarkOakLeaves), + "sponge" => Some(BlockKind::Sponge), + "wet_sponge" => Some(BlockKind::WetSponge), + "glass" => Some(BlockKind::Glass), + "lapis_ore" => Some(BlockKind::LapisOre), + "lapis_block" => Some(BlockKind::LapisBlock), + "dispenser" => Some(BlockKind::Dispenser), + "sandstone" => Some(BlockKind::Sandstone), + "chiseled_sandstone" => Some(BlockKind::ChiseledSandstone), + "cut_sandstone" => Some(BlockKind::CutSandstone), + "note_block" => Some(BlockKind::NoteBlock), + "white_bed" => Some(BlockKind::WhiteBed), + "orange_bed" => Some(BlockKind::OrangeBed), + "magenta_bed" => Some(BlockKind::MagentaBed), + "light_blue_bed" => Some(BlockKind::LightBlueBed), + "yellow_bed" => Some(BlockKind::YellowBed), + "lime_bed" => Some(BlockKind::LimeBed), + "pink_bed" => Some(BlockKind::PinkBed), + "gray_bed" => Some(BlockKind::GrayBed), + "light_gray_bed" => Some(BlockKind::LightGrayBed), + "cyan_bed" => Some(BlockKind::CyanBed), + "purple_bed" => Some(BlockKind::PurpleBed), + "blue_bed" => Some(BlockKind::BlueBed), + "brown_bed" => Some(BlockKind::BrownBed), + "green_bed" => Some(BlockKind::GreenBed), + "red_bed" => Some(BlockKind::RedBed), + "black_bed" => Some(BlockKind::BlackBed), + "powered_rail" => Some(BlockKind::PoweredRail), + "detector_rail" => Some(BlockKind::DetectorRail), + "sticky_piston" => Some(BlockKind::StickyPiston), + "cobweb" => Some(BlockKind::Cobweb), + "grass" => Some(BlockKind::Grass), + "fern" => Some(BlockKind::Fern), + "dead_bush" => Some(BlockKind::DeadBush), + "seagrass" => Some(BlockKind::Seagrass), + "tall_seagrass" => Some(BlockKind::TallSeagrass), + "piston" => Some(BlockKind::Piston), + "piston_head" => Some(BlockKind::PistonHead), + "white_wool" => Some(BlockKind::WhiteWool), + "orange_wool" => Some(BlockKind::OrangeWool), + "magenta_wool" => Some(BlockKind::MagentaWool), + "light_blue_wool" => Some(BlockKind::LightBlueWool), + "yellow_wool" => Some(BlockKind::YellowWool), + "lime_wool" => Some(BlockKind::LimeWool), + "pink_wool" => Some(BlockKind::PinkWool), + "gray_wool" => Some(BlockKind::GrayWool), + "light_gray_wool" => Some(BlockKind::LightGrayWool), + "cyan_wool" => Some(BlockKind::CyanWool), + "purple_wool" => Some(BlockKind::PurpleWool), + "blue_wool" => Some(BlockKind::BlueWool), + "brown_wool" => Some(BlockKind::BrownWool), + "green_wool" => Some(BlockKind::GreenWool), + "red_wool" => Some(BlockKind::RedWool), + "black_wool" => Some(BlockKind::BlackWool), + "moving_piston" => Some(BlockKind::MovingPiston), + "dandelion" => Some(BlockKind::Dandelion), + "poppy" => Some(BlockKind::Poppy), + "blue_orchid" => Some(BlockKind::BlueOrchid), + "allium" => Some(BlockKind::Allium), + "azure_bluet" => Some(BlockKind::AzureBluet), + "red_tulip" => Some(BlockKind::RedTulip), + "orange_tulip" => Some(BlockKind::OrangeTulip), + "white_tulip" => Some(BlockKind::WhiteTulip), + "pink_tulip" => Some(BlockKind::PinkTulip), + "oxeye_daisy" => Some(BlockKind::OxeyeDaisy), + "cornflower" => Some(BlockKind::Cornflower), + "wither_rose" => Some(BlockKind::WitherRose), + "lily_of_the_valley" => Some(BlockKind::LilyOfTheValley), + "brown_mushroom" => Some(BlockKind::BrownMushroom), + "red_mushroom" => Some(BlockKind::RedMushroom), + "gold_block" => Some(BlockKind::GoldBlock), + "iron_block" => Some(BlockKind::IronBlock), + "bricks" => Some(BlockKind::Bricks), + "tnt" => Some(BlockKind::Tnt), + "bookshelf" => Some(BlockKind::Bookshelf), + "mossy_cobblestone" => Some(BlockKind::MossyCobblestone), + "obsidian" => Some(BlockKind::Obsidian), + "torch" => Some(BlockKind::Torch), + "wall_torch" => Some(BlockKind::WallTorch), + "fire" => Some(BlockKind::Fire), + "soul_fire" => Some(BlockKind::SoulFire), + "spawner" => Some(BlockKind::Spawner), + "oak_stairs" => Some(BlockKind::OakStairs), + "chest" => Some(BlockKind::Chest), + "redstone_wire" => Some(BlockKind::RedstoneWire), + "diamond_ore" => Some(BlockKind::DiamondOre), + "diamond_block" => Some(BlockKind::DiamondBlock), + "crafting_table" => Some(BlockKind::CraftingTable), + "wheat" => Some(BlockKind::Wheat), + "farmland" => Some(BlockKind::Farmland), + "furnace" => Some(BlockKind::Furnace), + "oak_sign" => Some(BlockKind::OakSign), + "spruce_sign" => Some(BlockKind::SpruceSign), + "birch_sign" => Some(BlockKind::BirchSign), + "acacia_sign" => Some(BlockKind::AcaciaSign), + "jungle_sign" => Some(BlockKind::JungleSign), + "dark_oak_sign" => Some(BlockKind::DarkOakSign), + "oak_door" => Some(BlockKind::OakDoor), + "ladder" => Some(BlockKind::Ladder), + "rail" => Some(BlockKind::Rail), + "cobblestone_stairs" => Some(BlockKind::CobblestoneStairs), + "oak_wall_sign" => Some(BlockKind::OakWallSign), + "spruce_wall_sign" => Some(BlockKind::SpruceWallSign), + "birch_wall_sign" => Some(BlockKind::BirchWallSign), + "acacia_wall_sign" => Some(BlockKind::AcaciaWallSign), + "jungle_wall_sign" => Some(BlockKind::JungleWallSign), + "dark_oak_wall_sign" => Some(BlockKind::DarkOakWallSign), + "lever" => Some(BlockKind::Lever), + "stone_pressure_plate" => Some(BlockKind::StonePressurePlate), + "iron_door" => Some(BlockKind::IronDoor), + "oak_pressure_plate" => Some(BlockKind::OakPressurePlate), + "spruce_pressure_plate" => Some(BlockKind::SprucePressurePlate), + "birch_pressure_plate" => Some(BlockKind::BirchPressurePlate), + "jungle_pressure_plate" => Some(BlockKind::JunglePressurePlate), + "acacia_pressure_plate" => Some(BlockKind::AcaciaPressurePlate), + "dark_oak_pressure_plate" => Some(BlockKind::DarkOakPressurePlate), + "redstone_ore" => Some(BlockKind::RedstoneOre), + "redstone_torch" => Some(BlockKind::RedstoneTorch), + "redstone_wall_torch" => Some(BlockKind::RedstoneWallTorch), + "stone_button" => Some(BlockKind::StoneButton), + "snow" => Some(BlockKind::Snow), + "ice" => Some(BlockKind::Ice), + "snow_block" => Some(BlockKind::SnowBlock), + "cactus" => Some(BlockKind::Cactus), + "clay" => Some(BlockKind::Clay), + "sugar_cane" => Some(BlockKind::SugarCane), + "jukebox" => Some(BlockKind::Jukebox), + "oak_fence" => Some(BlockKind::OakFence), + "pumpkin" => Some(BlockKind::Pumpkin), + "netherrack" => Some(BlockKind::Netherrack), + "soul_sand" => Some(BlockKind::SoulSand), + "soul_soil" => Some(BlockKind::SoulSoil), + "basalt" => Some(BlockKind::Basalt), + "polished_basalt" => Some(BlockKind::PolishedBasalt), + "soul_torch" => Some(BlockKind::SoulTorch), + "soul_wall_torch" => Some(BlockKind::SoulWallTorch), + "glowstone" => Some(BlockKind::Glowstone), + "nether_portal" => Some(BlockKind::NetherPortal), + "carved_pumpkin" => Some(BlockKind::CarvedPumpkin), + "jack_o_lantern" => Some(BlockKind::JackOLantern), + "cake" => Some(BlockKind::Cake), + "repeater" => Some(BlockKind::Repeater), + "white_stained_glass" => Some(BlockKind::WhiteStainedGlass), + "orange_stained_glass" => Some(BlockKind::OrangeStainedGlass), + "magenta_stained_glass" => Some(BlockKind::MagentaStainedGlass), + "light_blue_stained_glass" => Some(BlockKind::LightBlueStainedGlass), + "yellow_stained_glass" => Some(BlockKind::YellowStainedGlass), + "lime_stained_glass" => Some(BlockKind::LimeStainedGlass), + "pink_stained_glass" => Some(BlockKind::PinkStainedGlass), + "gray_stained_glass" => Some(BlockKind::GrayStainedGlass), + "light_gray_stained_glass" => Some(BlockKind::LightGrayStainedGlass), + "cyan_stained_glass" => Some(BlockKind::CyanStainedGlass), + "purple_stained_glass" => Some(BlockKind::PurpleStainedGlass), + "blue_stained_glass" => Some(BlockKind::BlueStainedGlass), + "brown_stained_glass" => Some(BlockKind::BrownStainedGlass), + "green_stained_glass" => Some(BlockKind::GreenStainedGlass), + "red_stained_glass" => Some(BlockKind::RedStainedGlass), + "black_stained_glass" => Some(BlockKind::BlackStainedGlass), + "oak_trapdoor" => Some(BlockKind::OakTrapdoor), + "spruce_trapdoor" => Some(BlockKind::SpruceTrapdoor), + "birch_trapdoor" => Some(BlockKind::BirchTrapdoor), + "jungle_trapdoor" => Some(BlockKind::JungleTrapdoor), + "acacia_trapdoor" => Some(BlockKind::AcaciaTrapdoor), + "dark_oak_trapdoor" => Some(BlockKind::DarkOakTrapdoor), + "stone_bricks" => Some(BlockKind::StoneBricks), + "mossy_stone_bricks" => Some(BlockKind::MossyStoneBricks), + "cracked_stone_bricks" => Some(BlockKind::CrackedStoneBricks), + "chiseled_stone_bricks" => Some(BlockKind::ChiseledStoneBricks), + "infested_stone" => Some(BlockKind::InfestedStone), + "infested_cobblestone" => Some(BlockKind::InfestedCobblestone), + "infested_stone_bricks" => Some(BlockKind::InfestedStoneBricks), + "infested_mossy_stone_bricks" => Some(BlockKind::InfestedMossyStoneBricks), + "infested_cracked_stone_bricks" => Some(BlockKind::InfestedCrackedStoneBricks), + "infested_chiseled_stone_bricks" => Some(BlockKind::InfestedChiseledStoneBricks), + "brown_mushroom_block" => Some(BlockKind::BrownMushroomBlock), + "red_mushroom_block" => Some(BlockKind::RedMushroomBlock), + "mushroom_stem" => Some(BlockKind::MushroomStem), + "iron_bars" => Some(BlockKind::IronBars), + "chain" => Some(BlockKind::Chain), + "glass_pane" => Some(BlockKind::GlassPane), + "melon" => Some(BlockKind::Melon), + "attached_pumpkin_stem" => Some(BlockKind::AttachedPumpkinStem), + "attached_melon_stem" => Some(BlockKind::AttachedMelonStem), + "pumpkin_stem" => Some(BlockKind::PumpkinStem), + "melon_stem" => Some(BlockKind::MelonStem), + "vine" => Some(BlockKind::Vine), + "oak_fence_gate" => Some(BlockKind::OakFenceGate), + "brick_stairs" => Some(BlockKind::BrickStairs), + "stone_brick_stairs" => Some(BlockKind::StoneBrickStairs), + "mycelium" => Some(BlockKind::Mycelium), + "lily_pad" => Some(BlockKind::LilyPad), + "nether_bricks" => Some(BlockKind::NetherBricks), + "nether_brick_fence" => Some(BlockKind::NetherBrickFence), + "nether_brick_stairs" => Some(BlockKind::NetherBrickStairs), + "nether_wart" => Some(BlockKind::NetherWart), + "enchanting_table" => Some(BlockKind::EnchantingTable), + "brewing_stand" => Some(BlockKind::BrewingStand), + "cauldron" => Some(BlockKind::Cauldron), + "end_portal" => Some(BlockKind::EndPortal), + "end_portal_frame" => Some(BlockKind::EndPortalFrame), + "end_stone" => Some(BlockKind::EndStone), + "dragon_egg" => Some(BlockKind::DragonEgg), + "redstone_lamp" => Some(BlockKind::RedstoneLamp), + "cocoa" => Some(BlockKind::Cocoa), + "sandstone_stairs" => Some(BlockKind::SandstoneStairs), + "emerald_ore" => Some(BlockKind::EmeraldOre), + "ender_chest" => Some(BlockKind::EnderChest), + "tripwire_hook" => Some(BlockKind::TripwireHook), + "tripwire" => Some(BlockKind::Tripwire), + "emerald_block" => Some(BlockKind::EmeraldBlock), + "spruce_stairs" => Some(BlockKind::SpruceStairs), + "birch_stairs" => Some(BlockKind::BirchStairs), + "jungle_stairs" => Some(BlockKind::JungleStairs), + "command_block" => Some(BlockKind::CommandBlock), + "beacon" => Some(BlockKind::Beacon), + "cobblestone_wall" => Some(BlockKind::CobblestoneWall), + "mossy_cobblestone_wall" => Some(BlockKind::MossyCobblestoneWall), + "flower_pot" => Some(BlockKind::FlowerPot), + "potted_oak_sapling" => Some(BlockKind::PottedOakSapling), + "potted_spruce_sapling" => Some(BlockKind::PottedSpruceSapling), + "potted_birch_sapling" => Some(BlockKind::PottedBirchSapling), + "potted_jungle_sapling" => Some(BlockKind::PottedJungleSapling), + "potted_acacia_sapling" => Some(BlockKind::PottedAcaciaSapling), + "potted_dark_oak_sapling" => Some(BlockKind::PottedDarkOakSapling), + "potted_fern" => Some(BlockKind::PottedFern), + "potted_dandelion" => Some(BlockKind::PottedDandelion), + "potted_poppy" => Some(BlockKind::PottedPoppy), + "potted_blue_orchid" => Some(BlockKind::PottedBlueOrchid), + "potted_allium" => Some(BlockKind::PottedAllium), + "potted_azure_bluet" => Some(BlockKind::PottedAzureBluet), + "potted_red_tulip" => Some(BlockKind::PottedRedTulip), + "potted_orange_tulip" => Some(BlockKind::PottedOrangeTulip), + "potted_white_tulip" => Some(BlockKind::PottedWhiteTulip), + "potted_pink_tulip" => Some(BlockKind::PottedPinkTulip), + "potted_oxeye_daisy" => Some(BlockKind::PottedOxeyeDaisy), + "potted_cornflower" => Some(BlockKind::PottedCornflower), + "potted_lily_of_the_valley" => Some(BlockKind::PottedLilyOfTheValley), + "potted_wither_rose" => Some(BlockKind::PottedWitherRose), + "potted_red_mushroom" => Some(BlockKind::PottedRedMushroom), + "potted_brown_mushroom" => Some(BlockKind::PottedBrownMushroom), + "potted_dead_bush" => Some(BlockKind::PottedDeadBush), + "potted_cactus" => Some(BlockKind::PottedCactus), + "carrots" => Some(BlockKind::Carrots), + "potatoes" => Some(BlockKind::Potatoes), + "oak_button" => Some(BlockKind::OakButton), + "spruce_button" => Some(BlockKind::SpruceButton), + "birch_button" => Some(BlockKind::BirchButton), + "jungle_button" => Some(BlockKind::JungleButton), + "acacia_button" => Some(BlockKind::AcaciaButton), + "dark_oak_button" => Some(BlockKind::DarkOakButton), + "skeleton_skull" => Some(BlockKind::SkeletonSkull), + "skeleton_wall_skull" => Some(BlockKind::SkeletonWallSkull), + "wither_skeleton_skull" => Some(BlockKind::WitherSkeletonSkull), + "wither_skeleton_wall_skull" => Some(BlockKind::WitherSkeletonWallSkull), + "zombie_head" => Some(BlockKind::ZombieHead), + "zombie_wall_head" => Some(BlockKind::ZombieWallHead), + "player_head" => Some(BlockKind::PlayerHead), + "player_wall_head" => Some(BlockKind::PlayerWallHead), + "creeper_head" => Some(BlockKind::CreeperHead), + "creeper_wall_head" => Some(BlockKind::CreeperWallHead), + "dragon_head" => Some(BlockKind::DragonHead), + "dragon_wall_head" => Some(BlockKind::DragonWallHead), + "anvil" => Some(BlockKind::Anvil), + "chipped_anvil" => Some(BlockKind::ChippedAnvil), + "damaged_anvil" => Some(BlockKind::DamagedAnvil), + "trapped_chest" => Some(BlockKind::TrappedChest), + "light_weighted_pressure_plate" => Some(BlockKind::LightWeightedPressurePlate), + "heavy_weighted_pressure_plate" => Some(BlockKind::HeavyWeightedPressurePlate), + "comparator" => Some(BlockKind::Comparator), + "daylight_detector" => Some(BlockKind::DaylightDetector), + "redstone_block" => Some(BlockKind::RedstoneBlock), + "nether_quartz_ore" => Some(BlockKind::NetherQuartzOre), + "hopper" => Some(BlockKind::Hopper), + "quartz_block" => Some(BlockKind::QuartzBlock), + "chiseled_quartz_block" => Some(BlockKind::ChiseledQuartzBlock), + "quartz_pillar" => Some(BlockKind::QuartzPillar), + "quartz_stairs" => Some(BlockKind::QuartzStairs), + "activator_rail" => Some(BlockKind::ActivatorRail), + "dropper" => Some(BlockKind::Dropper), + "white_terracotta" => Some(BlockKind::WhiteTerracotta), + "orange_terracotta" => Some(BlockKind::OrangeTerracotta), + "magenta_terracotta" => Some(BlockKind::MagentaTerracotta), + "light_blue_terracotta" => Some(BlockKind::LightBlueTerracotta), + "yellow_terracotta" => Some(BlockKind::YellowTerracotta), + "lime_terracotta" => Some(BlockKind::LimeTerracotta), + "pink_terracotta" => Some(BlockKind::PinkTerracotta), + "gray_terracotta" => Some(BlockKind::GrayTerracotta), + "light_gray_terracotta" => Some(BlockKind::LightGrayTerracotta), + "cyan_terracotta" => Some(BlockKind::CyanTerracotta), + "purple_terracotta" => Some(BlockKind::PurpleTerracotta), + "blue_terracotta" => Some(BlockKind::BlueTerracotta), + "brown_terracotta" => Some(BlockKind::BrownTerracotta), + "green_terracotta" => Some(BlockKind::GreenTerracotta), + "red_terracotta" => Some(BlockKind::RedTerracotta), + "black_terracotta" => Some(BlockKind::BlackTerracotta), + "white_stained_glass_pane" => Some(BlockKind::WhiteStainedGlassPane), + "orange_stained_glass_pane" => Some(BlockKind::OrangeStainedGlassPane), + "magenta_stained_glass_pane" => Some(BlockKind::MagentaStainedGlassPane), + "light_blue_stained_glass_pane" => Some(BlockKind::LightBlueStainedGlassPane), + "yellow_stained_glass_pane" => Some(BlockKind::YellowStainedGlassPane), + "lime_stained_glass_pane" => Some(BlockKind::LimeStainedGlassPane), + "pink_stained_glass_pane" => Some(BlockKind::PinkStainedGlassPane), + "gray_stained_glass_pane" => Some(BlockKind::GrayStainedGlassPane), + "light_gray_stained_glass_pane" => Some(BlockKind::LightGrayStainedGlassPane), + "cyan_stained_glass_pane" => Some(BlockKind::CyanStainedGlassPane), + "purple_stained_glass_pane" => Some(BlockKind::PurpleStainedGlassPane), + "blue_stained_glass_pane" => Some(BlockKind::BlueStainedGlassPane), + "brown_stained_glass_pane" => Some(BlockKind::BrownStainedGlassPane), + "green_stained_glass_pane" => Some(BlockKind::GreenStainedGlassPane), + "red_stained_glass_pane" => Some(BlockKind::RedStainedGlassPane), + "black_stained_glass_pane" => Some(BlockKind::BlackStainedGlassPane), + "acacia_stairs" => Some(BlockKind::AcaciaStairs), + "dark_oak_stairs" => Some(BlockKind::DarkOakStairs), + "slime_block" => Some(BlockKind::SlimeBlock), + "barrier" => Some(BlockKind::Barrier), + "iron_trapdoor" => Some(BlockKind::IronTrapdoor), + "prismarine" => Some(BlockKind::Prismarine), + "prismarine_bricks" => Some(BlockKind::PrismarineBricks), + "dark_prismarine" => Some(BlockKind::DarkPrismarine), + "prismarine_stairs" => Some(BlockKind::PrismarineStairs), + "prismarine_brick_stairs" => Some(BlockKind::PrismarineBrickStairs), + "dark_prismarine_stairs" => Some(BlockKind::DarkPrismarineStairs), + "prismarine_slab" => Some(BlockKind::PrismarineSlab), + "prismarine_brick_slab" => Some(BlockKind::PrismarineBrickSlab), + "dark_prismarine_slab" => Some(BlockKind::DarkPrismarineSlab), + "sea_lantern" => Some(BlockKind::SeaLantern), + "hay_block" => Some(BlockKind::HayBlock), + "white_carpet" => Some(BlockKind::WhiteCarpet), + "orange_carpet" => Some(BlockKind::OrangeCarpet), + "magenta_carpet" => Some(BlockKind::MagentaCarpet), + "light_blue_carpet" => Some(BlockKind::LightBlueCarpet), + "yellow_carpet" => Some(BlockKind::YellowCarpet), + "lime_carpet" => Some(BlockKind::LimeCarpet), + "pink_carpet" => Some(BlockKind::PinkCarpet), + "gray_carpet" => Some(BlockKind::GrayCarpet), + "light_gray_carpet" => Some(BlockKind::LightGrayCarpet), + "cyan_carpet" => Some(BlockKind::CyanCarpet), + "purple_carpet" => Some(BlockKind::PurpleCarpet), + "blue_carpet" => Some(BlockKind::BlueCarpet), + "brown_carpet" => Some(BlockKind::BrownCarpet), + "green_carpet" => Some(BlockKind::GreenCarpet), + "red_carpet" => Some(BlockKind::RedCarpet), + "black_carpet" => Some(BlockKind::BlackCarpet), + "terracotta" => Some(BlockKind::Terracotta), + "coal_block" => Some(BlockKind::CoalBlock), + "packed_ice" => Some(BlockKind::PackedIce), + "sunflower" => Some(BlockKind::Sunflower), + "lilac" => Some(BlockKind::Lilac), + "rose_bush" => Some(BlockKind::RoseBush), + "peony" => Some(BlockKind::Peony), + "tall_grass" => Some(BlockKind::TallGrass), + "large_fern" => Some(BlockKind::LargeFern), + "white_banner" => Some(BlockKind::WhiteBanner), + "orange_banner" => Some(BlockKind::OrangeBanner), + "magenta_banner" => Some(BlockKind::MagentaBanner), + "light_blue_banner" => Some(BlockKind::LightBlueBanner), + "yellow_banner" => Some(BlockKind::YellowBanner), + "lime_banner" => Some(BlockKind::LimeBanner), + "pink_banner" => Some(BlockKind::PinkBanner), + "gray_banner" => Some(BlockKind::GrayBanner), + "light_gray_banner" => Some(BlockKind::LightGrayBanner), + "cyan_banner" => Some(BlockKind::CyanBanner), + "purple_banner" => Some(BlockKind::PurpleBanner), + "blue_banner" => Some(BlockKind::BlueBanner), + "brown_banner" => Some(BlockKind::BrownBanner), + "green_banner" => Some(BlockKind::GreenBanner), + "red_banner" => Some(BlockKind::RedBanner), + "black_banner" => Some(BlockKind::BlackBanner), + "white_wall_banner" => Some(BlockKind::WhiteWallBanner), + "orange_wall_banner" => Some(BlockKind::OrangeWallBanner), + "magenta_wall_banner" => Some(BlockKind::MagentaWallBanner), + "light_blue_wall_banner" => Some(BlockKind::LightBlueWallBanner), + "yellow_wall_banner" => Some(BlockKind::YellowWallBanner), + "lime_wall_banner" => Some(BlockKind::LimeWallBanner), + "pink_wall_banner" => Some(BlockKind::PinkWallBanner), + "gray_wall_banner" => Some(BlockKind::GrayWallBanner), + "light_gray_wall_banner" => Some(BlockKind::LightGrayWallBanner), + "cyan_wall_banner" => Some(BlockKind::CyanWallBanner), + "purple_wall_banner" => Some(BlockKind::PurpleWallBanner), + "blue_wall_banner" => Some(BlockKind::BlueWallBanner), + "brown_wall_banner" => Some(BlockKind::BrownWallBanner), + "green_wall_banner" => Some(BlockKind::GreenWallBanner), + "red_wall_banner" => Some(BlockKind::RedWallBanner), + "black_wall_banner" => Some(BlockKind::BlackWallBanner), + "red_sandstone" => Some(BlockKind::RedSandstone), + "chiseled_red_sandstone" => Some(BlockKind::ChiseledRedSandstone), + "cut_red_sandstone" => Some(BlockKind::CutRedSandstone), + "red_sandstone_stairs" => Some(BlockKind::RedSandstoneStairs), + "oak_slab" => Some(BlockKind::OakSlab), + "spruce_slab" => Some(BlockKind::SpruceSlab), + "birch_slab" => Some(BlockKind::BirchSlab), + "jungle_slab" => Some(BlockKind::JungleSlab), + "acacia_slab" => Some(BlockKind::AcaciaSlab), + "dark_oak_slab" => Some(BlockKind::DarkOakSlab), + "stone_slab" => Some(BlockKind::StoneSlab), + "smooth_stone_slab" => Some(BlockKind::SmoothStoneSlab), + "sandstone_slab" => Some(BlockKind::SandstoneSlab), + "cut_sandstone_slab" => Some(BlockKind::CutSandstoneSlab), + "petrified_oak_slab" => Some(BlockKind::PetrifiedOakSlab), + "cobblestone_slab" => Some(BlockKind::CobblestoneSlab), + "brick_slab" => Some(BlockKind::BrickSlab), + "stone_brick_slab" => Some(BlockKind::StoneBrickSlab), + "nether_brick_slab" => Some(BlockKind::NetherBrickSlab), + "quartz_slab" => Some(BlockKind::QuartzSlab), + "red_sandstone_slab" => Some(BlockKind::RedSandstoneSlab), + "cut_red_sandstone_slab" => Some(BlockKind::CutRedSandstoneSlab), + "purpur_slab" => Some(BlockKind::PurpurSlab), + "smooth_stone" => Some(BlockKind::SmoothStone), + "smooth_sandstone" => Some(BlockKind::SmoothSandstone), + "smooth_quartz" => Some(BlockKind::SmoothQuartz), + "smooth_red_sandstone" => Some(BlockKind::SmoothRedSandstone), + "spruce_fence_gate" => Some(BlockKind::SpruceFenceGate), + "birch_fence_gate" => Some(BlockKind::BirchFenceGate), + "jungle_fence_gate" => Some(BlockKind::JungleFenceGate), + "acacia_fence_gate" => Some(BlockKind::AcaciaFenceGate), + "dark_oak_fence_gate" => Some(BlockKind::DarkOakFenceGate), + "spruce_fence" => Some(BlockKind::SpruceFence), + "birch_fence" => Some(BlockKind::BirchFence), + "jungle_fence" => Some(BlockKind::JungleFence), + "acacia_fence" => Some(BlockKind::AcaciaFence), + "dark_oak_fence" => Some(BlockKind::DarkOakFence), + "spruce_door" => Some(BlockKind::SpruceDoor), + "birch_door" => Some(BlockKind::BirchDoor), + "jungle_door" => Some(BlockKind::JungleDoor), + "acacia_door" => Some(BlockKind::AcaciaDoor), + "dark_oak_door" => Some(BlockKind::DarkOakDoor), + "end_rod" => Some(BlockKind::EndRod), + "chorus_plant" => Some(BlockKind::ChorusPlant), + "chorus_flower" => Some(BlockKind::ChorusFlower), + "purpur_block" => Some(BlockKind::PurpurBlock), + "purpur_pillar" => Some(BlockKind::PurpurPillar), + "purpur_stairs" => Some(BlockKind::PurpurStairs), + "end_stone_bricks" => Some(BlockKind::EndStoneBricks), + "beetroots" => Some(BlockKind::Beetroots), + "grass_path" => Some(BlockKind::GrassPath), + "end_gateway" => Some(BlockKind::EndGateway), + "repeating_command_block" => Some(BlockKind::RepeatingCommandBlock), + "chain_command_block" => Some(BlockKind::ChainCommandBlock), + "frosted_ice" => Some(BlockKind::FrostedIce), + "magma_block" => Some(BlockKind::MagmaBlock), + "nether_wart_block" => Some(BlockKind::NetherWartBlock), + "red_nether_bricks" => Some(BlockKind::RedNetherBricks), + "bone_block" => Some(BlockKind::BoneBlock), + "structure_void" => Some(BlockKind::StructureVoid), + "observer" => Some(BlockKind::Observer), + "shulker_box" => Some(BlockKind::ShulkerBox), + "white_shulker_box" => Some(BlockKind::WhiteShulkerBox), + "orange_shulker_box" => Some(BlockKind::OrangeShulkerBox), + "magenta_shulker_box" => Some(BlockKind::MagentaShulkerBox), + "light_blue_shulker_box" => Some(BlockKind::LightBlueShulkerBox), + "yellow_shulker_box" => Some(BlockKind::YellowShulkerBox), + "lime_shulker_box" => Some(BlockKind::LimeShulkerBox), + "pink_shulker_box" => Some(BlockKind::PinkShulkerBox), + "gray_shulker_box" => Some(BlockKind::GrayShulkerBox), + "light_gray_shulker_box" => Some(BlockKind::LightGrayShulkerBox), + "cyan_shulker_box" => Some(BlockKind::CyanShulkerBox), + "purple_shulker_box" => Some(BlockKind::PurpleShulkerBox), + "blue_shulker_box" => Some(BlockKind::BlueShulkerBox), + "brown_shulker_box" => Some(BlockKind::BrownShulkerBox), + "green_shulker_box" => Some(BlockKind::GreenShulkerBox), + "red_shulker_box" => Some(BlockKind::RedShulkerBox), + "black_shulker_box" => Some(BlockKind::BlackShulkerBox), + "white_glazed_terracotta" => Some(BlockKind::WhiteGlazedTerracotta), + "orange_glazed_terracotta" => Some(BlockKind::OrangeGlazedTerracotta), + "magenta_glazed_terracotta" => Some(BlockKind::MagentaGlazedTerracotta), + "light_blue_glazed_terracotta" => Some(BlockKind::LightBlueGlazedTerracotta), + "yellow_glazed_terracotta" => Some(BlockKind::YellowGlazedTerracotta), + "lime_glazed_terracotta" => Some(BlockKind::LimeGlazedTerracotta), + "pink_glazed_terracotta" => Some(BlockKind::PinkGlazedTerracotta), + "gray_glazed_terracotta" => Some(BlockKind::GrayGlazedTerracotta), + "light_gray_glazed_terracotta" => Some(BlockKind::LightGrayGlazedTerracotta), + "cyan_glazed_terracotta" => Some(BlockKind::CyanGlazedTerracotta), + "purple_glazed_terracotta" => Some(BlockKind::PurpleGlazedTerracotta), + "blue_glazed_terracotta" => Some(BlockKind::BlueGlazedTerracotta), + "brown_glazed_terracotta" => Some(BlockKind::BrownGlazedTerracotta), + "green_glazed_terracotta" => Some(BlockKind::GreenGlazedTerracotta), + "red_glazed_terracotta" => Some(BlockKind::RedGlazedTerracotta), + "black_glazed_terracotta" => Some(BlockKind::BlackGlazedTerracotta), + "white_concrete" => Some(BlockKind::WhiteConcrete), + "orange_concrete" => Some(BlockKind::OrangeConcrete), + "magenta_concrete" => Some(BlockKind::MagentaConcrete), + "light_blue_concrete" => Some(BlockKind::LightBlueConcrete), + "yellow_concrete" => Some(BlockKind::YellowConcrete), + "lime_concrete" => Some(BlockKind::LimeConcrete), + "pink_concrete" => Some(BlockKind::PinkConcrete), + "gray_concrete" => Some(BlockKind::GrayConcrete), + "light_gray_concrete" => Some(BlockKind::LightGrayConcrete), + "cyan_concrete" => Some(BlockKind::CyanConcrete), + "purple_concrete" => Some(BlockKind::PurpleConcrete), + "blue_concrete" => Some(BlockKind::BlueConcrete), + "brown_concrete" => Some(BlockKind::BrownConcrete), + "green_concrete" => Some(BlockKind::GreenConcrete), + "red_concrete" => Some(BlockKind::RedConcrete), + "black_concrete" => Some(BlockKind::BlackConcrete), + "white_concrete_powder" => Some(BlockKind::WhiteConcretePowder), + "orange_concrete_powder" => Some(BlockKind::OrangeConcretePowder), + "magenta_concrete_powder" => Some(BlockKind::MagentaConcretePowder), + "light_blue_concrete_powder" => Some(BlockKind::LightBlueConcretePowder), + "yellow_concrete_powder" => Some(BlockKind::YellowConcretePowder), + "lime_concrete_powder" => Some(BlockKind::LimeConcretePowder), + "pink_concrete_powder" => Some(BlockKind::PinkConcretePowder), + "gray_concrete_powder" => Some(BlockKind::GrayConcretePowder), + "light_gray_concrete_powder" => Some(BlockKind::LightGrayConcretePowder), + "cyan_concrete_powder" => Some(BlockKind::CyanConcretePowder), + "purple_concrete_powder" => Some(BlockKind::PurpleConcretePowder), + "blue_concrete_powder" => Some(BlockKind::BlueConcretePowder), + "brown_concrete_powder" => Some(BlockKind::BrownConcretePowder), + "green_concrete_powder" => Some(BlockKind::GreenConcretePowder), + "red_concrete_powder" => Some(BlockKind::RedConcretePowder), + "black_concrete_powder" => Some(BlockKind::BlackConcretePowder), + "kelp" => Some(BlockKind::Kelp), + "kelp_plant" => Some(BlockKind::KelpPlant), + "dried_kelp_block" => Some(BlockKind::DriedKelpBlock), + "turtle_egg" => Some(BlockKind::TurtleEgg), + "dead_tube_coral_block" => Some(BlockKind::DeadTubeCoralBlock), + "dead_brain_coral_block" => Some(BlockKind::DeadBrainCoralBlock), + "dead_bubble_coral_block" => Some(BlockKind::DeadBubbleCoralBlock), + "dead_fire_coral_block" => Some(BlockKind::DeadFireCoralBlock), + "dead_horn_coral_block" => Some(BlockKind::DeadHornCoralBlock), + "tube_coral_block" => Some(BlockKind::TubeCoralBlock), + "brain_coral_block" => Some(BlockKind::BrainCoralBlock), + "bubble_coral_block" => Some(BlockKind::BubbleCoralBlock), + "fire_coral_block" => Some(BlockKind::FireCoralBlock), + "horn_coral_block" => Some(BlockKind::HornCoralBlock), + "dead_tube_coral" => Some(BlockKind::DeadTubeCoral), + "dead_brain_coral" => Some(BlockKind::DeadBrainCoral), + "dead_bubble_coral" => Some(BlockKind::DeadBubbleCoral), + "dead_fire_coral" => Some(BlockKind::DeadFireCoral), + "dead_horn_coral" => Some(BlockKind::DeadHornCoral), + "tube_coral" => Some(BlockKind::TubeCoral), + "brain_coral" => Some(BlockKind::BrainCoral), + "bubble_coral" => Some(BlockKind::BubbleCoral), + "fire_coral" => Some(BlockKind::FireCoral), + "horn_coral" => Some(BlockKind::HornCoral), + "dead_tube_coral_fan" => Some(BlockKind::DeadTubeCoralFan), + "dead_brain_coral_fan" => Some(BlockKind::DeadBrainCoralFan), + "dead_bubble_coral_fan" => Some(BlockKind::DeadBubbleCoralFan), + "dead_fire_coral_fan" => Some(BlockKind::DeadFireCoralFan), + "dead_horn_coral_fan" => Some(BlockKind::DeadHornCoralFan), + "tube_coral_fan" => Some(BlockKind::TubeCoralFan), + "brain_coral_fan" => Some(BlockKind::BrainCoralFan), + "bubble_coral_fan" => Some(BlockKind::BubbleCoralFan), + "fire_coral_fan" => Some(BlockKind::FireCoralFan), + "horn_coral_fan" => Some(BlockKind::HornCoralFan), + "dead_tube_coral_wall_fan" => Some(BlockKind::DeadTubeCoralWallFan), + "dead_brain_coral_wall_fan" => Some(BlockKind::DeadBrainCoralWallFan), + "dead_bubble_coral_wall_fan" => Some(BlockKind::DeadBubbleCoralWallFan), + "dead_fire_coral_wall_fan" => Some(BlockKind::DeadFireCoralWallFan), + "dead_horn_coral_wall_fan" => Some(BlockKind::DeadHornCoralWallFan), + "tube_coral_wall_fan" => Some(BlockKind::TubeCoralWallFan), + "brain_coral_wall_fan" => Some(BlockKind::BrainCoralWallFan), + "bubble_coral_wall_fan" => Some(BlockKind::BubbleCoralWallFan), + "fire_coral_wall_fan" => Some(BlockKind::FireCoralWallFan), + "horn_coral_wall_fan" => Some(BlockKind::HornCoralWallFan), + "sea_pickle" => Some(BlockKind::SeaPickle), + "blue_ice" => Some(BlockKind::BlueIce), + "conduit" => Some(BlockKind::Conduit), + "bamboo_sapling" => Some(BlockKind::BambooSapling), + "bamboo" => Some(BlockKind::Bamboo), + "potted_bamboo" => Some(BlockKind::PottedBamboo), + "void_air" => Some(BlockKind::VoidAir), + "cave_air" => Some(BlockKind::CaveAir), + "bubble_column" => Some(BlockKind::BubbleColumn), + "polished_granite_stairs" => Some(BlockKind::PolishedGraniteStairs), + "smooth_red_sandstone_stairs" => Some(BlockKind::SmoothRedSandstoneStairs), + "mossy_stone_brick_stairs" => Some(BlockKind::MossyStoneBrickStairs), + "polished_diorite_stairs" => Some(BlockKind::PolishedDioriteStairs), + "mossy_cobblestone_stairs" => Some(BlockKind::MossyCobblestoneStairs), + "end_stone_brick_stairs" => Some(BlockKind::EndStoneBrickStairs), + "stone_stairs" => Some(BlockKind::StoneStairs), + "smooth_sandstone_stairs" => Some(BlockKind::SmoothSandstoneStairs), + "smooth_quartz_stairs" => Some(BlockKind::SmoothQuartzStairs), + "granite_stairs" => Some(BlockKind::GraniteStairs), + "andesite_stairs" => Some(BlockKind::AndesiteStairs), + "red_nether_brick_stairs" => Some(BlockKind::RedNetherBrickStairs), + "polished_andesite_stairs" => Some(BlockKind::PolishedAndesiteStairs), + "diorite_stairs" => Some(BlockKind::DioriteStairs), + "polished_granite_slab" => Some(BlockKind::PolishedGraniteSlab), + "smooth_red_sandstone_slab" => Some(BlockKind::SmoothRedSandstoneSlab), + "mossy_stone_brick_slab" => Some(BlockKind::MossyStoneBrickSlab), + "polished_diorite_slab" => Some(BlockKind::PolishedDioriteSlab), + "mossy_cobblestone_slab" => Some(BlockKind::MossyCobblestoneSlab), + "end_stone_brick_slab" => Some(BlockKind::EndStoneBrickSlab), + "smooth_sandstone_slab" => Some(BlockKind::SmoothSandstoneSlab), + "smooth_quartz_slab" => Some(BlockKind::SmoothQuartzSlab), + "granite_slab" => Some(BlockKind::GraniteSlab), + "andesite_slab" => Some(BlockKind::AndesiteSlab), + "red_nether_brick_slab" => Some(BlockKind::RedNetherBrickSlab), + "polished_andesite_slab" => Some(BlockKind::PolishedAndesiteSlab), + "diorite_slab" => Some(BlockKind::DioriteSlab), + "brick_wall" => Some(BlockKind::BrickWall), + "prismarine_wall" => Some(BlockKind::PrismarineWall), + "red_sandstone_wall" => Some(BlockKind::RedSandstoneWall), + "mossy_stone_brick_wall" => Some(BlockKind::MossyStoneBrickWall), + "granite_wall" => Some(BlockKind::GraniteWall), + "stone_brick_wall" => Some(BlockKind::StoneBrickWall), + "nether_brick_wall" => Some(BlockKind::NetherBrickWall), + "andesite_wall" => Some(BlockKind::AndesiteWall), + "red_nether_brick_wall" => Some(BlockKind::RedNetherBrickWall), + "sandstone_wall" => Some(BlockKind::SandstoneWall), + "end_stone_brick_wall" => Some(BlockKind::EndStoneBrickWall), + "diorite_wall" => Some(BlockKind::DioriteWall), + "scaffolding" => Some(BlockKind::Scaffolding), + "loom" => Some(BlockKind::Loom), + "barrel" => Some(BlockKind::Barrel), + "smoker" => Some(BlockKind::Smoker), + "blast_furnace" => Some(BlockKind::BlastFurnace), + "cartography_table" => Some(BlockKind::CartographyTable), + "fletching_table" => Some(BlockKind::FletchingTable), + "grindstone" => Some(BlockKind::Grindstone), + "lectern" => Some(BlockKind::Lectern), + "smithing_table" => Some(BlockKind::SmithingTable), + "stonecutter" => Some(BlockKind::Stonecutter), + "bell" => Some(BlockKind::Bell), + "lantern" => Some(BlockKind::Lantern), + "soul_lantern" => Some(BlockKind::SoulLantern), + "campfire" => Some(BlockKind::Campfire), + "soul_campfire" => Some(BlockKind::SoulCampfire), + "sweet_berry_bush" => Some(BlockKind::SweetBerryBush), + "warped_stem" => Some(BlockKind::WarpedStem), + "stripped_warped_stem" => Some(BlockKind::StrippedWarpedStem), + "warped_hyphae" => Some(BlockKind::WarpedHyphae), + "stripped_warped_hyphae" => Some(BlockKind::StrippedWarpedHyphae), + "warped_nylium" => Some(BlockKind::WarpedNylium), + "warped_fungus" => Some(BlockKind::WarpedFungus), + "warped_wart_block" => Some(BlockKind::WarpedWartBlock), + "warped_roots" => Some(BlockKind::WarpedRoots), + "nether_sprouts" => Some(BlockKind::NetherSprouts), + "crimson_stem" => Some(BlockKind::CrimsonStem), + "stripped_crimson_stem" => Some(BlockKind::StrippedCrimsonStem), + "crimson_hyphae" => Some(BlockKind::CrimsonHyphae), + "stripped_crimson_hyphae" => Some(BlockKind::StrippedCrimsonHyphae), + "crimson_nylium" => Some(BlockKind::CrimsonNylium), + "crimson_fungus" => Some(BlockKind::CrimsonFungus), + "shroomlight" => Some(BlockKind::Shroomlight), + "weeping_vines" => Some(BlockKind::WeepingVines), + "weeping_vines_plant" => Some(BlockKind::WeepingVinesPlant), + "twisting_vines" => Some(BlockKind::TwistingVines), + "twisting_vines_plant" => Some(BlockKind::TwistingVinesPlant), + "crimson_roots" => Some(BlockKind::CrimsonRoots), + "crimson_planks" => Some(BlockKind::CrimsonPlanks), + "warped_planks" => Some(BlockKind::WarpedPlanks), + "crimson_slab" => Some(BlockKind::CrimsonSlab), + "warped_slab" => Some(BlockKind::WarpedSlab), + "crimson_pressure_plate" => Some(BlockKind::CrimsonPressurePlate), + "warped_pressure_plate" => Some(BlockKind::WarpedPressurePlate), + "crimson_fence" => Some(BlockKind::CrimsonFence), + "warped_fence" => Some(BlockKind::WarpedFence), + "crimson_trapdoor" => Some(BlockKind::CrimsonTrapdoor), + "warped_trapdoor" => Some(BlockKind::WarpedTrapdoor), + "crimson_fence_gate" => Some(BlockKind::CrimsonFenceGate), + "warped_fence_gate" => Some(BlockKind::WarpedFenceGate), + "crimson_stairs" => Some(BlockKind::CrimsonStairs), + "warped_stairs" => Some(BlockKind::WarpedStairs), + "crimson_button" => Some(BlockKind::CrimsonButton), + "warped_button" => Some(BlockKind::WarpedButton), + "crimson_door" => Some(BlockKind::CrimsonDoor), + "warped_door" => Some(BlockKind::WarpedDoor), + "crimson_sign" => Some(BlockKind::CrimsonSign), + "warped_sign" => Some(BlockKind::WarpedSign), + "crimson_wall_sign" => Some(BlockKind::CrimsonWallSign), + "warped_wall_sign" => Some(BlockKind::WarpedWallSign), + "structure_block" => Some(BlockKind::StructureBlock), + "jigsaw" => Some(BlockKind::Jigsaw), + "composter" => Some(BlockKind::Composter), + "target" => Some(BlockKind::Target), + "bee_nest" => Some(BlockKind::BeeNest), + "beehive" => Some(BlockKind::Beehive), + "honey_block" => Some(BlockKind::HoneyBlock), + "honeycomb_block" => Some(BlockKind::HoneycombBlock), + "netherite_block" => Some(BlockKind::NetheriteBlock), + "ancient_debris" => Some(BlockKind::AncientDebris), + "crying_obsidian" => Some(BlockKind::CryingObsidian), + "respawn_anchor" => Some(BlockKind::RespawnAnchor), + "potted_crimson_fungus" => Some(BlockKind::PottedCrimsonFungus), + "potted_warped_fungus" => Some(BlockKind::PottedWarpedFungus), + "potted_crimson_roots" => Some(BlockKind::PottedCrimsonRoots), + "potted_warped_roots" => Some(BlockKind::PottedWarpedRoots), + "lodestone" => Some(BlockKind::Lodestone), + "blackstone" => Some(BlockKind::Blackstone), + "blackstone_stairs" => Some(BlockKind::BlackstoneStairs), + "blackstone_wall" => Some(BlockKind::BlackstoneWall), + "blackstone_slab" => Some(BlockKind::BlackstoneSlab), + "polished_blackstone" => Some(BlockKind::PolishedBlackstone), + "polished_blackstone_bricks" => Some(BlockKind::PolishedBlackstoneBricks), + "cracked_polished_blackstone_bricks" => { + Some(BlockKind::CrackedPolishedBlackstoneBricks) + } + "chiseled_polished_blackstone" => Some(BlockKind::ChiseledPolishedBlackstone), + "polished_blackstone_brick_slab" => Some(BlockKind::PolishedBlackstoneBrickSlab), + "polished_blackstone_brick_stairs" => Some(BlockKind::PolishedBlackstoneBrickStairs), + "polished_blackstone_brick_wall" => Some(BlockKind::PolishedBlackstoneBrickWall), + "gilded_blackstone" => Some(BlockKind::GildedBlackstone), + "polished_blackstone_stairs" => Some(BlockKind::PolishedBlackstoneStairs), + "polished_blackstone_slab" => Some(BlockKind::PolishedBlackstoneSlab), + "polished_blackstone_pressure_plate" => { + Some(BlockKind::PolishedBlackstonePressurePlate) + } + "polished_blackstone_button" => Some(BlockKind::PolishedBlackstoneButton), + "polished_blackstone_wall" => Some(BlockKind::PolishedBlackstoneWall), + "chiseled_nether_bricks" => Some(BlockKind::ChiseledNetherBricks), + "cracked_nether_bricks" => Some(BlockKind::CrackedNetherBricks), + "quartz_bricks" => Some(BlockKind::QuartzBricks), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `display_name` property of this `BlockKind`. + pub fn display_name(&self) -> &'static str { + match self { + BlockKind::Air => "Air", + BlockKind::Stone => "Stone", + BlockKind::Granite => "Granite", + BlockKind::PolishedGranite => "Polished Granite", + BlockKind::Diorite => "Diorite", + BlockKind::PolishedDiorite => "Polished Diorite", + BlockKind::Andesite => "Andesite", + BlockKind::PolishedAndesite => "Polished Andesite", + BlockKind::GrassBlock => "Grass Block", + BlockKind::Dirt => "Dirt", + BlockKind::CoarseDirt => "Coarse Dirt", + BlockKind::Podzol => "Podzol", + BlockKind::Cobblestone => "Cobblestone", + BlockKind::OakPlanks => "Oak Planks", + BlockKind::SprucePlanks => "Spruce Planks", + BlockKind::BirchPlanks => "Birch Planks", + BlockKind::JunglePlanks => "Jungle Planks", + BlockKind::AcaciaPlanks => "Acacia Planks", + BlockKind::DarkOakPlanks => "Dark Oak Planks", + BlockKind::OakSapling => "Oak Sapling", + BlockKind::SpruceSapling => "Spruce Sapling", + BlockKind::BirchSapling => "Birch Sapling", + BlockKind::JungleSapling => "Jungle Sapling", + BlockKind::AcaciaSapling => "Acacia Sapling", + BlockKind::DarkOakSapling => "Dark Oak Sapling", + BlockKind::Bedrock => "Bedrock", + BlockKind::Water => "Water", + BlockKind::Lava => "Lava", + BlockKind::Sand => "Sand", + BlockKind::RedSand => "Red Sand", + BlockKind::Gravel => "Gravel", + BlockKind::GoldOre => "Gold Ore", + BlockKind::IronOre => "Iron Ore", + BlockKind::CoalOre => "Coal Ore", + BlockKind::NetherGoldOre => "Nether Gold Ore", + BlockKind::OakLog => "Oak Log", + BlockKind::SpruceLog => "Spruce Log", + BlockKind::BirchLog => "Birch Log", + BlockKind::JungleLog => "Jungle Log", + BlockKind::AcaciaLog => "Acacia Log", + BlockKind::DarkOakLog => "Dark Oak Log", + BlockKind::StrippedSpruceLog => "Stripped Spruce Log", + BlockKind::StrippedBirchLog => "Stripped Birch Log", + BlockKind::StrippedJungleLog => "Stripped Jungle Log", + BlockKind::StrippedAcaciaLog => "Stripped Acacia Log", + BlockKind::StrippedDarkOakLog => "Stripped Dark Oak Log", + BlockKind::StrippedOakLog => "Stripped Oak Log", + BlockKind::OakWood => "Oak Wood", + BlockKind::SpruceWood => "Spruce Wood", + BlockKind::BirchWood => "Birch Wood", + BlockKind::JungleWood => "Jungle Wood", + BlockKind::AcaciaWood => "Acacia Wood", + BlockKind::DarkOakWood => "Dark Oak Wood", + BlockKind::StrippedOakWood => "Stripped Oak Wood", + BlockKind::StrippedSpruceWood => "Stripped Spruce Wood", + BlockKind::StrippedBirchWood => "Stripped Birch Wood", + BlockKind::StrippedJungleWood => "Stripped Jungle Wood", + BlockKind::StrippedAcaciaWood => "Stripped Acacia Wood", + BlockKind::StrippedDarkOakWood => "Stripped Dark Oak Wood", + BlockKind::OakLeaves => "Oak Leaves", + BlockKind::SpruceLeaves => "Spruce Leaves", + BlockKind::BirchLeaves => "Birch Leaves", + BlockKind::JungleLeaves => "Jungle Leaves", + BlockKind::AcaciaLeaves => "Acacia Leaves", + BlockKind::DarkOakLeaves => "Dark Oak Leaves", + BlockKind::Sponge => "Sponge", + BlockKind::WetSponge => "Wet Sponge", + BlockKind::Glass => "Glass", + BlockKind::LapisOre => "Lapis Lazuli Ore", + BlockKind::LapisBlock => "Lapis Lazuli Block", + BlockKind::Dispenser => "Dispenser", + BlockKind::Sandstone => "Sandstone", + BlockKind::ChiseledSandstone => "Chiseled Sandstone", + BlockKind::CutSandstone => "Cut Sandstone", + BlockKind::NoteBlock => "Note Block", + BlockKind::WhiteBed => "White Bed", + BlockKind::OrangeBed => "Orange Bed", + BlockKind::MagentaBed => "Magenta Bed", + BlockKind::LightBlueBed => "Light Blue Bed", + BlockKind::YellowBed => "Yellow Bed", + BlockKind::LimeBed => "Lime Bed", + BlockKind::PinkBed => "Pink Bed", + BlockKind::GrayBed => "Gray Bed", + BlockKind::LightGrayBed => "Light Gray Bed", + BlockKind::CyanBed => "Cyan Bed", + BlockKind::PurpleBed => "Purple Bed", + BlockKind::BlueBed => "Blue Bed", + BlockKind::BrownBed => "Brown Bed", + BlockKind::GreenBed => "Green Bed", + BlockKind::RedBed => "Red Bed", + BlockKind::BlackBed => "Black Bed", + BlockKind::PoweredRail => "Powered Rail", + BlockKind::DetectorRail => "Detector Rail", + BlockKind::StickyPiston => "Sticky Piston", + BlockKind::Cobweb => "Cobweb", + BlockKind::Grass => "Grass", + BlockKind::Fern => "Fern", + BlockKind::DeadBush => "Dead Bush", + BlockKind::Seagrass => "Seagrass", + BlockKind::TallSeagrass => "Tall Seagrass", + BlockKind::Piston => "Piston", + BlockKind::PistonHead => "Piston Head", + BlockKind::WhiteWool => "White Wool", + BlockKind::OrangeWool => "Orange Wool", + BlockKind::MagentaWool => "Magenta Wool", + BlockKind::LightBlueWool => "Light Blue Wool", + BlockKind::YellowWool => "Yellow Wool", + BlockKind::LimeWool => "Lime Wool", + BlockKind::PinkWool => "Pink Wool", + BlockKind::GrayWool => "Gray Wool", + BlockKind::LightGrayWool => "Light Gray Wool", + BlockKind::CyanWool => "Cyan Wool", + BlockKind::PurpleWool => "Purple Wool", + BlockKind::BlueWool => "Blue Wool", + BlockKind::BrownWool => "Brown Wool", + BlockKind::GreenWool => "Green Wool", + BlockKind::RedWool => "Red Wool", + BlockKind::BlackWool => "Black Wool", + BlockKind::MovingPiston => "Moving Piston", + BlockKind::Dandelion => "Dandelion", + BlockKind::Poppy => "Poppy", + BlockKind::BlueOrchid => "Blue Orchid", + BlockKind::Allium => "Allium", + BlockKind::AzureBluet => "Azure Bluet", + BlockKind::RedTulip => "Red Tulip", + BlockKind::OrangeTulip => "Orange Tulip", + BlockKind::WhiteTulip => "White Tulip", + BlockKind::PinkTulip => "Pink Tulip", + BlockKind::OxeyeDaisy => "Oxeye Daisy", + BlockKind::Cornflower => "Cornflower", + BlockKind::WitherRose => "Wither Rose", + BlockKind::LilyOfTheValley => "Lily of the Valley", + BlockKind::BrownMushroom => "Brown Mushroom", + BlockKind::RedMushroom => "Red Mushroom", + BlockKind::GoldBlock => "Block of Gold", + BlockKind::IronBlock => "Block of Iron", + BlockKind::Bricks => "Bricks", + BlockKind::Tnt => "TNT", + BlockKind::Bookshelf => "Bookshelf", + BlockKind::MossyCobblestone => "Mossy Cobblestone", + BlockKind::Obsidian => "Obsidian", + BlockKind::Torch => "Torch", + BlockKind::WallTorch => "Wall Torch", + BlockKind::Fire => "Fire", + BlockKind::SoulFire => "Soul Fire", + BlockKind::Spawner => "Spawner", + BlockKind::OakStairs => "Oak Stairs", + BlockKind::Chest => "Chest", + BlockKind::RedstoneWire => "Redstone Wire", + BlockKind::DiamondOre => "Diamond Ore", + BlockKind::DiamondBlock => "Block of Diamond", + BlockKind::CraftingTable => "Crafting Table", + BlockKind::Wheat => "Wheat Crops", + BlockKind::Farmland => "Farmland", + BlockKind::Furnace => "Furnace", + BlockKind::OakSign => "Oak Sign", + BlockKind::SpruceSign => "Spruce Sign", + BlockKind::BirchSign => "Birch Sign", + BlockKind::AcaciaSign => "Acacia Sign", + BlockKind::JungleSign => "Jungle Sign", + BlockKind::DarkOakSign => "Dark Oak Sign", + BlockKind::OakDoor => "Oak Door", + BlockKind::Ladder => "Ladder", + BlockKind::Rail => "Rail", + BlockKind::CobblestoneStairs => "Cobblestone Stairs", + BlockKind::OakWallSign => "Oak Wall Sign", + BlockKind::SpruceWallSign => "Spruce Wall Sign", + BlockKind::BirchWallSign => "Birch Wall Sign", + BlockKind::AcaciaWallSign => "Acacia Wall Sign", + BlockKind::JungleWallSign => "Jungle Wall Sign", + BlockKind::DarkOakWallSign => "Dark Oak Wall Sign", + BlockKind::Lever => "Lever", + BlockKind::StonePressurePlate => "Stone Pressure Plate", + BlockKind::IronDoor => "Iron Door", + BlockKind::OakPressurePlate => "Oak Pressure Plate", + BlockKind::SprucePressurePlate => "Spruce Pressure Plate", + BlockKind::BirchPressurePlate => "Birch Pressure Plate", + BlockKind::JunglePressurePlate => "Jungle Pressure Plate", + BlockKind::AcaciaPressurePlate => "Acacia Pressure Plate", + BlockKind::DarkOakPressurePlate => "Dark Oak Pressure Plate", + BlockKind::RedstoneOre => "Redstone Ore", + BlockKind::RedstoneTorch => "Redstone Torch", + BlockKind::RedstoneWallTorch => "Redstone Wall Torch", + BlockKind::StoneButton => "Stone Button", + BlockKind::Snow => "Snow", + BlockKind::Ice => "Ice", + BlockKind::SnowBlock => "Snow Block", + BlockKind::Cactus => "Cactus", + BlockKind::Clay => "Clay", + BlockKind::SugarCane => "Sugar Cane", + BlockKind::Jukebox => "Jukebox", + BlockKind::OakFence => "Oak Fence", + BlockKind::Pumpkin => "Pumpkin", + BlockKind::Netherrack => "Netherrack", + BlockKind::SoulSand => "Soul Sand", + BlockKind::SoulSoil => "Soul Soil", + BlockKind::Basalt => "Basalt", + BlockKind::PolishedBasalt => "Polished Basalt", + BlockKind::SoulTorch => "Soul Torch", + BlockKind::SoulWallTorch => "Soul Wall Torch", + BlockKind::Glowstone => "Glowstone", + BlockKind::NetherPortal => "Nether Portal", + BlockKind::CarvedPumpkin => "Carved Pumpkin", + BlockKind::JackOLantern => "Jack o'Lantern", + BlockKind::Cake => "Cake", + BlockKind::Repeater => "Redstone Repeater", + BlockKind::WhiteStainedGlass => "White Stained Glass", + BlockKind::OrangeStainedGlass => "Orange Stained Glass", + BlockKind::MagentaStainedGlass => "Magenta Stained Glass", + BlockKind::LightBlueStainedGlass => "Light Blue Stained Glass", + BlockKind::YellowStainedGlass => "Yellow Stained Glass", + BlockKind::LimeStainedGlass => "Lime Stained Glass", + BlockKind::PinkStainedGlass => "Pink Stained Glass", + BlockKind::GrayStainedGlass => "Gray Stained Glass", + BlockKind::LightGrayStainedGlass => "Light Gray Stained Glass", + BlockKind::CyanStainedGlass => "Cyan Stained Glass", + BlockKind::PurpleStainedGlass => "Purple Stained Glass", + BlockKind::BlueStainedGlass => "Blue Stained Glass", + BlockKind::BrownStainedGlass => "Brown Stained Glass", + BlockKind::GreenStainedGlass => "Green Stained Glass", + BlockKind::RedStainedGlass => "Red Stained Glass", + BlockKind::BlackStainedGlass => "Black Stained Glass", + BlockKind::OakTrapdoor => "Oak Trapdoor", + BlockKind::SpruceTrapdoor => "Spruce Trapdoor", + BlockKind::BirchTrapdoor => "Birch Trapdoor", + BlockKind::JungleTrapdoor => "Jungle Trapdoor", + BlockKind::AcaciaTrapdoor => "Acacia Trapdoor", + BlockKind::DarkOakTrapdoor => "Dark Oak Trapdoor", + BlockKind::StoneBricks => "Stone Bricks", + BlockKind::MossyStoneBricks => "Mossy Stone Bricks", + BlockKind::CrackedStoneBricks => "Cracked Stone Bricks", + BlockKind::ChiseledStoneBricks => "Chiseled Stone Bricks", + BlockKind::InfestedStone => "Infested Stone", + BlockKind::InfestedCobblestone => "Infested Cobblestone", + BlockKind::InfestedStoneBricks => "Infested Stone Bricks", + BlockKind::InfestedMossyStoneBricks => "Infested Mossy Stone Bricks", + BlockKind::InfestedCrackedStoneBricks => "Infested Cracked Stone Bricks", + BlockKind::InfestedChiseledStoneBricks => "Infested Chiseled Stone Bricks", + BlockKind::BrownMushroomBlock => "Brown Mushroom Block", + BlockKind::RedMushroomBlock => "Red Mushroom Block", + BlockKind::MushroomStem => "Mushroom Stem", + BlockKind::IronBars => "Iron Bars", + BlockKind::Chain => "Chain", + BlockKind::GlassPane => "Glass Pane", + BlockKind::Melon => "Melon", + BlockKind::AttachedPumpkinStem => "Attached Pumpkin Stem", + BlockKind::AttachedMelonStem => "Attached Melon Stem", + BlockKind::PumpkinStem => "Pumpkin Stem", + BlockKind::MelonStem => "Melon Stem", + BlockKind::Vine => "Vines", + BlockKind::OakFenceGate => "Oak Fence Gate", + BlockKind::BrickStairs => "Brick Stairs", + BlockKind::StoneBrickStairs => "Stone Brick Stairs", + BlockKind::Mycelium => "Mycelium", + BlockKind::LilyPad => "Lily Pad", + BlockKind::NetherBricks => "Nether Bricks", + BlockKind::NetherBrickFence => "Nether Brick Fence", + BlockKind::NetherBrickStairs => "Nether Brick Stairs", + BlockKind::NetherWart => "Nether Wart", + BlockKind::EnchantingTable => "Enchanting Table", + BlockKind::BrewingStand => "Brewing Stand", + BlockKind::Cauldron => "Cauldron", + BlockKind::EndPortal => "End Portal", + BlockKind::EndPortalFrame => "End Portal Frame", + BlockKind::EndStone => "End Stone", + BlockKind::DragonEgg => "Dragon Egg", + BlockKind::RedstoneLamp => "Redstone Lamp", + BlockKind::Cocoa => "Cocoa", + BlockKind::SandstoneStairs => "Sandstone Stairs", + BlockKind::EmeraldOre => "Emerald Ore", + BlockKind::EnderChest => "Ender Chest", + BlockKind::TripwireHook => "Tripwire Hook", + BlockKind::Tripwire => "Tripwire", + BlockKind::EmeraldBlock => "Block of Emerald", + BlockKind::SpruceStairs => "Spruce Stairs", + BlockKind::BirchStairs => "Birch Stairs", + BlockKind::JungleStairs => "Jungle Stairs", + BlockKind::CommandBlock => "Command Block", + BlockKind::Beacon => "Beacon", + BlockKind::CobblestoneWall => "Cobblestone Wall", + BlockKind::MossyCobblestoneWall => "Mossy Cobblestone Wall", + BlockKind::FlowerPot => "Flower Pot", + BlockKind::PottedOakSapling => "Potted Oak Sapling", + BlockKind::PottedSpruceSapling => "Potted Spruce Sapling", + BlockKind::PottedBirchSapling => "Potted Birch Sapling", + BlockKind::PottedJungleSapling => "Potted Jungle Sapling", + BlockKind::PottedAcaciaSapling => "Potted Acacia Sapling", + BlockKind::PottedDarkOakSapling => "Potted Dark Oak Sapling", + BlockKind::PottedFern => "Potted Fern", + BlockKind::PottedDandelion => "Potted Dandelion", + BlockKind::PottedPoppy => "Potted Poppy", + BlockKind::PottedBlueOrchid => "Potted Blue Orchid", + BlockKind::PottedAllium => "Potted Allium", + BlockKind::PottedAzureBluet => "Potted Azure Bluet", + BlockKind::PottedRedTulip => "Potted Red Tulip", + BlockKind::PottedOrangeTulip => "Potted Orange Tulip", + BlockKind::PottedWhiteTulip => "Potted White Tulip", + BlockKind::PottedPinkTulip => "Potted Pink Tulip", + BlockKind::PottedOxeyeDaisy => "Potted Oxeye Daisy", + BlockKind::PottedCornflower => "Potted Cornflower", + BlockKind::PottedLilyOfTheValley => "Potted Lily of the Valley", + BlockKind::PottedWitherRose => "Potted Wither Rose", + BlockKind::PottedRedMushroom => "Potted Red Mushroom", + BlockKind::PottedBrownMushroom => "Potted Brown Mushroom", + BlockKind::PottedDeadBush => "Potted Dead Bush", + BlockKind::PottedCactus => "Potted Cactus", + BlockKind::Carrots => "Carrots", + BlockKind::Potatoes => "Potatoes", + BlockKind::OakButton => "Oak Button", + BlockKind::SpruceButton => "Spruce Button", + BlockKind::BirchButton => "Birch Button", + BlockKind::JungleButton => "Jungle Button", + BlockKind::AcaciaButton => "Acacia Button", + BlockKind::DarkOakButton => "Dark Oak Button", + BlockKind::SkeletonSkull => "Skeleton Skull", + BlockKind::SkeletonWallSkull => "Skeleton Wall Skull", + BlockKind::WitherSkeletonSkull => "Wither Skeleton Skull", + BlockKind::WitherSkeletonWallSkull => "Wither Skeleton Wall Skull", + BlockKind::ZombieHead => "Zombie Head", + BlockKind::ZombieWallHead => "Zombie Wall Head", + BlockKind::PlayerHead => "Player Head", + BlockKind::PlayerWallHead => "Player Wall Head", + BlockKind::CreeperHead => "Creeper Head", + BlockKind::CreeperWallHead => "Creeper Wall Head", + BlockKind::DragonHead => "Dragon Head", + BlockKind::DragonWallHead => "Dragon Wall Head", + BlockKind::Anvil => "Anvil", + BlockKind::ChippedAnvil => "Chipped Anvil", + BlockKind::DamagedAnvil => "Damaged Anvil", + BlockKind::TrappedChest => "Trapped Chest", + BlockKind::LightWeightedPressurePlate => "Light Weighted Pressure Plate", + BlockKind::HeavyWeightedPressurePlate => "Heavy Weighted Pressure Plate", + BlockKind::Comparator => "Redstone Comparator", + BlockKind::DaylightDetector => "Daylight Detector", + BlockKind::RedstoneBlock => "Block of Redstone", + BlockKind::NetherQuartzOre => "Nether Quartz Ore", + BlockKind::Hopper => "Hopper", + BlockKind::QuartzBlock => "Block of Quartz", + BlockKind::ChiseledQuartzBlock => "Chiseled Quartz Block", + BlockKind::QuartzPillar => "Quartz Pillar", + BlockKind::QuartzStairs => "Quartz Stairs", + BlockKind::ActivatorRail => "Activator Rail", + BlockKind::Dropper => "Dropper", + BlockKind::WhiteTerracotta => "White Terracotta", + BlockKind::OrangeTerracotta => "Orange Terracotta", + BlockKind::MagentaTerracotta => "Magenta Terracotta", + BlockKind::LightBlueTerracotta => "Light Blue Terracotta", + BlockKind::YellowTerracotta => "Yellow Terracotta", + BlockKind::LimeTerracotta => "Lime Terracotta", + BlockKind::PinkTerracotta => "Pink Terracotta", + BlockKind::GrayTerracotta => "Gray Terracotta", + BlockKind::LightGrayTerracotta => "Light Gray Terracotta", + BlockKind::CyanTerracotta => "Cyan Terracotta", + BlockKind::PurpleTerracotta => "Purple Terracotta", + BlockKind::BlueTerracotta => "Blue Terracotta", + BlockKind::BrownTerracotta => "Brown Terracotta", + BlockKind::GreenTerracotta => "Green Terracotta", + BlockKind::RedTerracotta => "Red Terracotta", + BlockKind::BlackTerracotta => "Black Terracotta", + BlockKind::WhiteStainedGlassPane => "White Stained Glass Pane", + BlockKind::OrangeStainedGlassPane => "Orange Stained Glass Pane", + BlockKind::MagentaStainedGlassPane => "Magenta Stained Glass Pane", + BlockKind::LightBlueStainedGlassPane => "Light Blue Stained Glass Pane", + BlockKind::YellowStainedGlassPane => "Yellow Stained Glass Pane", + BlockKind::LimeStainedGlassPane => "Lime Stained Glass Pane", + BlockKind::PinkStainedGlassPane => "Pink Stained Glass Pane", + BlockKind::GrayStainedGlassPane => "Gray Stained Glass Pane", + BlockKind::LightGrayStainedGlassPane => "Light Gray Stained Glass Pane", + BlockKind::CyanStainedGlassPane => "Cyan Stained Glass Pane", + BlockKind::PurpleStainedGlassPane => "Purple Stained Glass Pane", + BlockKind::BlueStainedGlassPane => "Blue Stained Glass Pane", + BlockKind::BrownStainedGlassPane => "Brown Stained Glass Pane", + BlockKind::GreenStainedGlassPane => "Green Stained Glass Pane", + BlockKind::RedStainedGlassPane => "Red Stained Glass Pane", + BlockKind::BlackStainedGlassPane => "Black Stained Glass Pane", + BlockKind::AcaciaStairs => "Acacia Stairs", + BlockKind::DarkOakStairs => "Dark Oak Stairs", + BlockKind::SlimeBlock => "Slime Block", + BlockKind::Barrier => "Barrier", + BlockKind::IronTrapdoor => "Iron Trapdoor", + BlockKind::Prismarine => "Prismarine", + BlockKind::PrismarineBricks => "Prismarine Bricks", + BlockKind::DarkPrismarine => "Dark Prismarine", + BlockKind::PrismarineStairs => "Prismarine Stairs", + BlockKind::PrismarineBrickStairs => "Prismarine Brick Stairs", + BlockKind::DarkPrismarineStairs => "Dark Prismarine Stairs", + BlockKind::PrismarineSlab => "Prismarine Slab", + BlockKind::PrismarineBrickSlab => "Prismarine Brick Slab", + BlockKind::DarkPrismarineSlab => "Dark Prismarine Slab", + BlockKind::SeaLantern => "Sea Lantern", + BlockKind::HayBlock => "Hay Bale", + BlockKind::WhiteCarpet => "White Carpet", + BlockKind::OrangeCarpet => "Orange Carpet", + BlockKind::MagentaCarpet => "Magenta Carpet", + BlockKind::LightBlueCarpet => "Light Blue Carpet", + BlockKind::YellowCarpet => "Yellow Carpet", + BlockKind::LimeCarpet => "Lime Carpet", + BlockKind::PinkCarpet => "Pink Carpet", + BlockKind::GrayCarpet => "Gray Carpet", + BlockKind::LightGrayCarpet => "Light Gray Carpet", + BlockKind::CyanCarpet => "Cyan Carpet", + BlockKind::PurpleCarpet => "Purple Carpet", + BlockKind::BlueCarpet => "Blue Carpet", + BlockKind::BrownCarpet => "Brown Carpet", + BlockKind::GreenCarpet => "Green Carpet", + BlockKind::RedCarpet => "Red Carpet", + BlockKind::BlackCarpet => "Black Carpet", + BlockKind::Terracotta => "Terracotta", + BlockKind::CoalBlock => "Block of Coal", + BlockKind::PackedIce => "Packed Ice", + BlockKind::Sunflower => "Sunflower", + BlockKind::Lilac => "Lilac", + BlockKind::RoseBush => "Rose Bush", + BlockKind::Peony => "Peony", + BlockKind::TallGrass => "Tall Grass", + BlockKind::LargeFern => "Large Fern", + BlockKind::WhiteBanner => "White Banner", + BlockKind::OrangeBanner => "Orange Banner", + BlockKind::MagentaBanner => "Magenta Banner", + BlockKind::LightBlueBanner => "Light Blue Banner", + BlockKind::YellowBanner => "Yellow Banner", + BlockKind::LimeBanner => "Lime Banner", + BlockKind::PinkBanner => "Pink Banner", + BlockKind::GrayBanner => "Gray Banner", + BlockKind::LightGrayBanner => "Light Gray Banner", + BlockKind::CyanBanner => "Cyan Banner", + BlockKind::PurpleBanner => "Purple Banner", + BlockKind::BlueBanner => "Blue Banner", + BlockKind::BrownBanner => "Brown Banner", + BlockKind::GreenBanner => "Green Banner", + BlockKind::RedBanner => "Red Banner", + BlockKind::BlackBanner => "Black Banner", + BlockKind::WhiteWallBanner => "White wall banner", + BlockKind::OrangeWallBanner => "Orange wall banner", + BlockKind::MagentaWallBanner => "Magenta wall banner", + BlockKind::LightBlueWallBanner => "Light blue wall banner", + BlockKind::YellowWallBanner => "Yellow wall banner", + BlockKind::LimeWallBanner => "Lime wall banner", + BlockKind::PinkWallBanner => "Pink wall banner", + BlockKind::GrayWallBanner => "Gray wall banner", + BlockKind::LightGrayWallBanner => "Light gray wall banner", + BlockKind::CyanWallBanner => "Cyan wall banner", + BlockKind::PurpleWallBanner => "Purple wall banner", + BlockKind::BlueWallBanner => "Blue wall banner", + BlockKind::BrownWallBanner => "Brown wall banner", + BlockKind::GreenWallBanner => "Green wall banner", + BlockKind::RedWallBanner => "Red wall banner", + BlockKind::BlackWallBanner => "Black wall banner", + BlockKind::RedSandstone => "Red Sandstone", + BlockKind::ChiseledRedSandstone => "Chiseled Red Sandstone", + BlockKind::CutRedSandstone => "Cut Red Sandstone", + BlockKind::RedSandstoneStairs => "Red Sandstone Stairs", + BlockKind::OakSlab => "Oak Slab", + BlockKind::SpruceSlab => "Spruce Slab", + BlockKind::BirchSlab => "Birch Slab", + BlockKind::JungleSlab => "Jungle Slab", + BlockKind::AcaciaSlab => "Acacia Slab", + BlockKind::DarkOakSlab => "Dark Oak Slab", + BlockKind::StoneSlab => "Stone Slab", + BlockKind::SmoothStoneSlab => "Smooth Stone Slab", + BlockKind::SandstoneSlab => "Sandstone Slab", + BlockKind::CutSandstoneSlab => "Cut Sandstone Slab", + BlockKind::PetrifiedOakSlab => "Petrified Oak Slab", + BlockKind::CobblestoneSlab => "Cobblestone Slab", + BlockKind::BrickSlab => "Brick Slab", + BlockKind::StoneBrickSlab => "Stone Brick Slab", + BlockKind::NetherBrickSlab => "Nether Brick Slab", + BlockKind::QuartzSlab => "Quartz Slab", + BlockKind::RedSandstoneSlab => "Red Sandstone Slab", + BlockKind::CutRedSandstoneSlab => "Cut Red Sandstone Slab", + BlockKind::PurpurSlab => "Purpur Slab", + BlockKind::SmoothStone => "Smooth Stone", + BlockKind::SmoothSandstone => "Smooth Sandstone", + BlockKind::SmoothQuartz => "Smooth Quartz Block", + BlockKind::SmoothRedSandstone => "Smooth Red Sandstone", + BlockKind::SpruceFenceGate => "Spruce Fence Gate", + BlockKind::BirchFenceGate => "Birch Fence Gate", + BlockKind::JungleFenceGate => "Jungle Fence Gate", + BlockKind::AcaciaFenceGate => "Acacia Fence Gate", + BlockKind::DarkOakFenceGate => "Dark Oak Fence Gate", + BlockKind::SpruceFence => "Spruce Fence", + BlockKind::BirchFence => "Birch Fence", + BlockKind::JungleFence => "Jungle Fence", + BlockKind::AcaciaFence => "Acacia Fence", + BlockKind::DarkOakFence => "Dark Oak Fence", + BlockKind::SpruceDoor => "Spruce Door", + BlockKind::BirchDoor => "Birch Door", + BlockKind::JungleDoor => "Jungle Door", + BlockKind::AcaciaDoor => "Acacia Door", + BlockKind::DarkOakDoor => "Dark Oak Door", + BlockKind::EndRod => "End Rod", + BlockKind::ChorusPlant => "Chorus Plant", + BlockKind::ChorusFlower => "Chorus Flower", + BlockKind::PurpurBlock => "Purpur Block", + BlockKind::PurpurPillar => "Purpur Pillar", + BlockKind::PurpurStairs => "Purpur Stairs", + BlockKind::EndStoneBricks => "End Stone Bricks", + BlockKind::Beetroots => "Beetroots", + BlockKind::GrassPath => "Grass Path", + BlockKind::EndGateway => "End Gateway", + BlockKind::RepeatingCommandBlock => "Repeating Command Block", + BlockKind::ChainCommandBlock => "Chain Command Block", + BlockKind::FrostedIce => "Frosted Ice", + BlockKind::MagmaBlock => "Magma Block", + BlockKind::NetherWartBlock => "Nether Wart Block", + BlockKind::RedNetherBricks => "Red Nether Bricks", + BlockKind::BoneBlock => "Bone Block", + BlockKind::StructureVoid => "Structure Void", + BlockKind::Observer => "Observer", + BlockKind::ShulkerBox => "Shulker Box", + BlockKind::WhiteShulkerBox => "White Shulker Box", + BlockKind::OrangeShulkerBox => "Orange Shulker Box", + BlockKind::MagentaShulkerBox => "Magenta Shulker Box", + BlockKind::LightBlueShulkerBox => "Light Blue Shulker Box", + BlockKind::YellowShulkerBox => "Yellow Shulker Box", + BlockKind::LimeShulkerBox => "Lime Shulker Box", + BlockKind::PinkShulkerBox => "Pink Shulker Box", + BlockKind::GrayShulkerBox => "Gray Shulker Box", + BlockKind::LightGrayShulkerBox => "Light Gray Shulker Box", + BlockKind::CyanShulkerBox => "Cyan Shulker Box", + BlockKind::PurpleShulkerBox => "Purple Shulker Box", + BlockKind::BlueShulkerBox => "Blue Shulker Box", + BlockKind::BrownShulkerBox => "Brown Shulker Box", + BlockKind::GreenShulkerBox => "Green Shulker Box", + BlockKind::RedShulkerBox => "Red Shulker Box", + BlockKind::BlackShulkerBox => "Black Shulker Box", + BlockKind::WhiteGlazedTerracotta => "White Glazed Terracotta", + BlockKind::OrangeGlazedTerracotta => "Orange Glazed Terracotta", + BlockKind::MagentaGlazedTerracotta => "Magenta Glazed Terracotta", + BlockKind::LightBlueGlazedTerracotta => "Light Blue Glazed Terracotta", + BlockKind::YellowGlazedTerracotta => "Yellow Glazed Terracotta", + BlockKind::LimeGlazedTerracotta => "Lime Glazed Terracotta", + BlockKind::PinkGlazedTerracotta => "Pink Glazed Terracotta", + BlockKind::GrayGlazedTerracotta => "Gray Glazed Terracotta", + BlockKind::LightGrayGlazedTerracotta => "Light Gray Glazed Terracotta", + BlockKind::CyanGlazedTerracotta => "Cyan Glazed Terracotta", + BlockKind::PurpleGlazedTerracotta => "Purple Glazed Terracotta", + BlockKind::BlueGlazedTerracotta => "Blue Glazed Terracotta", + BlockKind::BrownGlazedTerracotta => "Brown Glazed Terracotta", + BlockKind::GreenGlazedTerracotta => "Green Glazed Terracotta", + BlockKind::RedGlazedTerracotta => "Red Glazed Terracotta", + BlockKind::BlackGlazedTerracotta => "Black Glazed Terracotta", + BlockKind::WhiteConcrete => "White Concrete", + BlockKind::OrangeConcrete => "Orange Concrete", + BlockKind::MagentaConcrete => "Magenta Concrete", + BlockKind::LightBlueConcrete => "Light Blue Concrete", + BlockKind::YellowConcrete => "Yellow Concrete", + BlockKind::LimeConcrete => "Lime Concrete", + BlockKind::PinkConcrete => "Pink Concrete", + BlockKind::GrayConcrete => "Gray Concrete", + BlockKind::LightGrayConcrete => "Light Gray Concrete", + BlockKind::CyanConcrete => "Cyan Concrete", + BlockKind::PurpleConcrete => "Purple Concrete", + BlockKind::BlueConcrete => "Blue Concrete", + BlockKind::BrownConcrete => "Brown Concrete", + BlockKind::GreenConcrete => "Green Concrete", + BlockKind::RedConcrete => "Red Concrete", + BlockKind::BlackConcrete => "Black Concrete", + BlockKind::WhiteConcretePowder => "White Concrete Powder", + BlockKind::OrangeConcretePowder => "Orange Concrete Powder", + BlockKind::MagentaConcretePowder => "Magenta Concrete Powder", + BlockKind::LightBlueConcretePowder => "Light Blue Concrete Powder", + BlockKind::YellowConcretePowder => "Yellow Concrete Powder", + BlockKind::LimeConcretePowder => "Lime Concrete Powder", + BlockKind::PinkConcretePowder => "Pink Concrete Powder", + BlockKind::GrayConcretePowder => "Gray Concrete Powder", + BlockKind::LightGrayConcretePowder => "Light Gray Concrete Powder", + BlockKind::CyanConcretePowder => "Cyan Concrete Powder", + BlockKind::PurpleConcretePowder => "Purple Concrete Powder", + BlockKind::BlueConcretePowder => "Blue Concrete Powder", + BlockKind::BrownConcretePowder => "Brown Concrete Powder", + BlockKind::GreenConcretePowder => "Green Concrete Powder", + BlockKind::RedConcretePowder => "Red Concrete Powder", + BlockKind::BlackConcretePowder => "Black Concrete Powder", + BlockKind::Kelp => "Kelp", + BlockKind::KelpPlant => "Kelp Plant", + BlockKind::DriedKelpBlock => "Dried Kelp Block", + BlockKind::TurtleEgg => "Turtle Egg", + BlockKind::DeadTubeCoralBlock => "Dead Tube Coral Block", + BlockKind::DeadBrainCoralBlock => "Dead Brain Coral Block", + BlockKind::DeadBubbleCoralBlock => "Dead Bubble Coral Block", + BlockKind::DeadFireCoralBlock => "Dead Fire Coral Block", + BlockKind::DeadHornCoralBlock => "Dead Horn Coral Block", + BlockKind::TubeCoralBlock => "Tube Coral Block", + BlockKind::BrainCoralBlock => "Brain Coral Block", + BlockKind::BubbleCoralBlock => "Bubble Coral Block", + BlockKind::FireCoralBlock => "Fire Coral Block", + BlockKind::HornCoralBlock => "Horn Coral Block", + BlockKind::DeadTubeCoral => "Dead Tube Coral", + BlockKind::DeadBrainCoral => "Dead Brain Coral", + BlockKind::DeadBubbleCoral => "Dead Bubble Coral", + BlockKind::DeadFireCoral => "Dead Fire Coral", + BlockKind::DeadHornCoral => "Dead Horn Coral", + BlockKind::TubeCoral => "Tube Coral", + BlockKind::BrainCoral => "Brain Coral", + BlockKind::BubbleCoral => "Bubble Coral", + BlockKind::FireCoral => "Fire Coral", + BlockKind::HornCoral => "Horn Coral", + BlockKind::DeadTubeCoralFan => "Dead Tube Coral Fan", + BlockKind::DeadBrainCoralFan => "Dead Brain Coral Fan", + BlockKind::DeadBubbleCoralFan => "Dead Bubble Coral Fan", + BlockKind::DeadFireCoralFan => "Dead Fire Coral Fan", + BlockKind::DeadHornCoralFan => "Dead Horn Coral Fan", + BlockKind::TubeCoralFan => "Tube Coral Fan", + BlockKind::BrainCoralFan => "Brain Coral Fan", + BlockKind::BubbleCoralFan => "Bubble Coral Fan", + BlockKind::FireCoralFan => "Fire Coral Fan", + BlockKind::HornCoralFan => "Horn Coral Fan", + BlockKind::DeadTubeCoralWallFan => "Dead Tube Coral Wall Fan", + BlockKind::DeadBrainCoralWallFan => "Dead Brain Coral Wall Fan", + BlockKind::DeadBubbleCoralWallFan => "Dead Bubble Coral Wall Fan", + BlockKind::DeadFireCoralWallFan => "Dead Fire Coral Wall Fan", + BlockKind::DeadHornCoralWallFan => "Dead Horn Coral Wall Fan", + BlockKind::TubeCoralWallFan => "Tube Coral Wall Fan", + BlockKind::BrainCoralWallFan => "Brain Coral Wall Fan", + BlockKind::BubbleCoralWallFan => "Bubble Coral Wall Fan", + BlockKind::FireCoralWallFan => "Fire Coral Wall Fan", + BlockKind::HornCoralWallFan => "Horn Coral Wall Fan", + BlockKind::SeaPickle => "Sea Pickle", + BlockKind::BlueIce => "Blue Ice", + BlockKind::Conduit => "Conduit", + BlockKind::BambooSapling => "Bamboo Shoot", + BlockKind::Bamboo => "Bamboo", + BlockKind::PottedBamboo => "Potted Bamboo", + BlockKind::VoidAir => "Void Air", + BlockKind::CaveAir => "Cave Air", + BlockKind::BubbleColumn => "Bubble Column", + BlockKind::PolishedGraniteStairs => "Polished Granite Stairs", + BlockKind::SmoothRedSandstoneStairs => "Smooth Red Sandstone Stairs", + BlockKind::MossyStoneBrickStairs => "Mossy Stone Brick Stairs", + BlockKind::PolishedDioriteStairs => "Polished Diorite Stairs", + BlockKind::MossyCobblestoneStairs => "Mossy Cobblestone Stairs", + BlockKind::EndStoneBrickStairs => "End Stone Brick Stairs", + BlockKind::StoneStairs => "Stone Stairs", + BlockKind::SmoothSandstoneStairs => "Smooth Sandstone Stairs", + BlockKind::SmoothQuartzStairs => "Smooth Quartz Stairs", + BlockKind::GraniteStairs => "Granite Stairs", + BlockKind::AndesiteStairs => "Andesite Stairs", + BlockKind::RedNetherBrickStairs => "Red Nether Brick Stairs", + BlockKind::PolishedAndesiteStairs => "Polished Andesite Stairs", + BlockKind::DioriteStairs => "Diorite Stairs", + BlockKind::PolishedGraniteSlab => "Polished Granite Slab", + BlockKind::SmoothRedSandstoneSlab => "Smooth Red Sandstone Slab", + BlockKind::MossyStoneBrickSlab => "Mossy Stone Brick Slab", + BlockKind::PolishedDioriteSlab => "Polished Diorite Slab", + BlockKind::MossyCobblestoneSlab => "Mossy Cobblestone Slab", + BlockKind::EndStoneBrickSlab => "End Stone Brick Slab", + BlockKind::SmoothSandstoneSlab => "Smooth Sandstone Slab", + BlockKind::SmoothQuartzSlab => "Smooth Quartz Slab", + BlockKind::GraniteSlab => "Granite Slab", + BlockKind::AndesiteSlab => "Andesite Slab", + BlockKind::RedNetherBrickSlab => "Red Nether Brick Slab", + BlockKind::PolishedAndesiteSlab => "Polished Andesite Slab", + BlockKind::DioriteSlab => "Diorite Slab", + BlockKind::BrickWall => "Brick Wall", + BlockKind::PrismarineWall => "Prismarine Wall", + BlockKind::RedSandstoneWall => "Red Sandstone Wall", + BlockKind::MossyStoneBrickWall => "Mossy Stone Brick Wall", + BlockKind::GraniteWall => "Granite Wall", + BlockKind::StoneBrickWall => "Stone Brick Wall", + BlockKind::NetherBrickWall => "Nether Brick Wall", + BlockKind::AndesiteWall => "Andesite Wall", + BlockKind::RedNetherBrickWall => "Red Nether Brick Wall", + BlockKind::SandstoneWall => "Sandstone Wall", + BlockKind::EndStoneBrickWall => "End Stone Brick Wall", + BlockKind::DioriteWall => "Diorite Wall", + BlockKind::Scaffolding => "Scaffolding", + BlockKind::Loom => "Loom", + BlockKind::Barrel => "Barrel", + BlockKind::Smoker => "Smoker", + BlockKind::BlastFurnace => "Blast Furnace", + BlockKind::CartographyTable => "Cartography Table", + BlockKind::FletchingTable => "Fletching Table", + BlockKind::Grindstone => "Grindstone", + BlockKind::Lectern => "Lectern", + BlockKind::SmithingTable => "Smithing Table", + BlockKind::Stonecutter => "Stonecutter", + BlockKind::Bell => "Bell", + BlockKind::Lantern => "Lantern", + BlockKind::SoulLantern => "Soul Lantern", + BlockKind::Campfire => "Campfire", + BlockKind::SoulCampfire => "Soul Campfire", + BlockKind::SweetBerryBush => "Sweet Berry Bush", + BlockKind::WarpedStem => "Warped Stem", + BlockKind::StrippedWarpedStem => "Stripped Warped Stem", + BlockKind::WarpedHyphae => "Warped Hyphae", + BlockKind::StrippedWarpedHyphae => "Stripped Warped Hyphae", + BlockKind::WarpedNylium => "Warped Nylium", + BlockKind::WarpedFungus => "Warped Fungus", + BlockKind::WarpedWartBlock => "Warped Wart Block", + BlockKind::WarpedRoots => "Warped Roots", + BlockKind::NetherSprouts => "Nether Sprouts", + BlockKind::CrimsonStem => "Crimson Stem", + BlockKind::StrippedCrimsonStem => "Stripped Crimson Stem", + BlockKind::CrimsonHyphae => "Crimson Hyphae", + BlockKind::StrippedCrimsonHyphae => "Stripped Crimson Hyphae", + BlockKind::CrimsonNylium => "Crimson Nylium", + BlockKind::CrimsonFungus => "Crimson Fungus", + BlockKind::Shroomlight => "Shroomlight", + BlockKind::WeepingVines => "Weeping Vines", + BlockKind::WeepingVinesPlant => "Weeping Vines Plant", + BlockKind::TwistingVines => "Twisting Vines", + BlockKind::TwistingVinesPlant => "Twisting Vines Plant", + BlockKind::CrimsonRoots => "Crimson Roots", + BlockKind::CrimsonPlanks => "Crimson Planks", + BlockKind::WarpedPlanks => "Warped Planks", + BlockKind::CrimsonSlab => "Crimson Slab", + BlockKind::WarpedSlab => "Warped Slab", + BlockKind::CrimsonPressurePlate => "Crimson Pressure Plate", + BlockKind::WarpedPressurePlate => "Warped Pressure Plate", + BlockKind::CrimsonFence => "Crimson Fence", + BlockKind::WarpedFence => "Warped Fence", + BlockKind::CrimsonTrapdoor => "Crimson Trapdoor", + BlockKind::WarpedTrapdoor => "Warped Trapdoor", + BlockKind::CrimsonFenceGate => "Crimson Fence Gate", + BlockKind::WarpedFenceGate => "Warped Fence Gate", + BlockKind::CrimsonStairs => "Crimson Stairs", + BlockKind::WarpedStairs => "Warped Stairs", + BlockKind::CrimsonButton => "Crimson Button", + BlockKind::WarpedButton => "Warped Button", + BlockKind::CrimsonDoor => "Crimson Door", + BlockKind::WarpedDoor => "Warped Door", + BlockKind::CrimsonSign => "Crimson Sign", + BlockKind::WarpedSign => "Warped Sign", + BlockKind::CrimsonWallSign => "Crimson Wall Sign", + BlockKind::WarpedWallSign => "Warped Wall Sign", + BlockKind::StructureBlock => "Structure Block", + BlockKind::Jigsaw => "Jigsaw Block", + BlockKind::Composter => "Composter", + BlockKind::Target => "Target", + BlockKind::BeeNest => "Bee Nest", + BlockKind::Beehive => "Beehive", + BlockKind::HoneyBlock => "Honey Block", + BlockKind::HoneycombBlock => "Honeycomb Block", + BlockKind::NetheriteBlock => "Block of Netherite", + BlockKind::AncientDebris => "Ancient Debris", + BlockKind::CryingObsidian => "Crying Obsidian", + BlockKind::RespawnAnchor => "Respawn Anchor", + BlockKind::PottedCrimsonFungus => "Potted Crimson Fungus", + BlockKind::PottedWarpedFungus => "Potted Warped Fungus", + BlockKind::PottedCrimsonRoots => "Potted Crimson Roots", + BlockKind::PottedWarpedRoots => "Potted Warped Roots", + BlockKind::Lodestone => "Lodestone", + BlockKind::Blackstone => "Blackstone", + BlockKind::BlackstoneStairs => "Blackstone Stairs", + BlockKind::BlackstoneWall => "Blackstone Wall", + BlockKind::BlackstoneSlab => "Blackstone Slab", + BlockKind::PolishedBlackstone => "Polished Blackstone", + BlockKind::PolishedBlackstoneBricks => "Polished Blackstone Bricks", + BlockKind::CrackedPolishedBlackstoneBricks => "Cracked Polished Blackstone Bricks", + BlockKind::ChiseledPolishedBlackstone => "Chiseled Polished Blackstone", + BlockKind::PolishedBlackstoneBrickSlab => "Polished Blackstone Brick Slab", + BlockKind::PolishedBlackstoneBrickStairs => "Polished Blackstone Brick Stairs", + BlockKind::PolishedBlackstoneBrickWall => "Polished Blackstone Brick Wall", + BlockKind::GildedBlackstone => "Gilded Blackstone", + BlockKind::PolishedBlackstoneStairs => "Polished Blackstone Stairs", + BlockKind::PolishedBlackstoneSlab => "Polished Blackstone Slab", + BlockKind::PolishedBlackstonePressurePlate => "Polished Blackstone Pressure Plate", + BlockKind::PolishedBlackstoneButton => "Polished Blackstone Button", + BlockKind::PolishedBlackstoneWall => "Polished Blackstone Wall", + BlockKind::ChiseledNetherBricks => "Chiseled Nether Bricks", + BlockKind::CrackedNetherBricks => "Cracked Nether Bricks", + BlockKind::QuartzBricks => "Quartz Bricks", + } + } + + /// Gets a `BlockKind` by its `display_name`. + pub fn from_display_name(display_name: &str) -> Option<Self> { + match display_name { + "Air" => Some(BlockKind::Air), + "Stone" => Some(BlockKind::Stone), + "Granite" => Some(BlockKind::Granite), + "Polished Granite" => Some(BlockKind::PolishedGranite), + "Diorite" => Some(BlockKind::Diorite), + "Polished Diorite" => Some(BlockKind::PolishedDiorite), + "Andesite" => Some(BlockKind::Andesite), + "Polished Andesite" => Some(BlockKind::PolishedAndesite), + "Grass Block" => Some(BlockKind::GrassBlock), + "Dirt" => Some(BlockKind::Dirt), + "Coarse Dirt" => Some(BlockKind::CoarseDirt), + "Podzol" => Some(BlockKind::Podzol), + "Cobblestone" => Some(BlockKind::Cobblestone), + "Oak Planks" => Some(BlockKind::OakPlanks), + "Spruce Planks" => Some(BlockKind::SprucePlanks), + "Birch Planks" => Some(BlockKind::BirchPlanks), + "Jungle Planks" => Some(BlockKind::JunglePlanks), + "Acacia Planks" => Some(BlockKind::AcaciaPlanks), + "Dark Oak Planks" => Some(BlockKind::DarkOakPlanks), + "Oak Sapling" => Some(BlockKind::OakSapling), + "Spruce Sapling" => Some(BlockKind::SpruceSapling), + "Birch Sapling" => Some(BlockKind::BirchSapling), + "Jungle Sapling" => Some(BlockKind::JungleSapling), + "Acacia Sapling" => Some(BlockKind::AcaciaSapling), + "Dark Oak Sapling" => Some(BlockKind::DarkOakSapling), + "Bedrock" => Some(BlockKind::Bedrock), + "Water" => Some(BlockKind::Water), + "Lava" => Some(BlockKind::Lava), + "Sand" => Some(BlockKind::Sand), + "Red Sand" => Some(BlockKind::RedSand), + "Gravel" => Some(BlockKind::Gravel), + "Gold Ore" => Some(BlockKind::GoldOre), + "Iron Ore" => Some(BlockKind::IronOre), + "Coal Ore" => Some(BlockKind::CoalOre), + "Nether Gold Ore" => Some(BlockKind::NetherGoldOre), + "Oak Log" => Some(BlockKind::OakLog), + "Spruce Log" => Some(BlockKind::SpruceLog), + "Birch Log" => Some(BlockKind::BirchLog), + "Jungle Log" => Some(BlockKind::JungleLog), + "Acacia Log" => Some(BlockKind::AcaciaLog), + "Dark Oak Log" => Some(BlockKind::DarkOakLog), + "Stripped Spruce Log" => Some(BlockKind::StrippedSpruceLog), + "Stripped Birch Log" => Some(BlockKind::StrippedBirchLog), + "Stripped Jungle Log" => Some(BlockKind::StrippedJungleLog), + "Stripped Acacia Log" => Some(BlockKind::StrippedAcaciaLog), + "Stripped Dark Oak Log" => Some(BlockKind::StrippedDarkOakLog), + "Stripped Oak Log" => Some(BlockKind::StrippedOakLog), + "Oak Wood" => Some(BlockKind::OakWood), + "Spruce Wood" => Some(BlockKind::SpruceWood), + "Birch Wood" => Some(BlockKind::BirchWood), + "Jungle Wood" => Some(BlockKind::JungleWood), + "Acacia Wood" => Some(BlockKind::AcaciaWood), + "Dark Oak Wood" => Some(BlockKind::DarkOakWood), + "Stripped Oak Wood" => Some(BlockKind::StrippedOakWood), + "Stripped Spruce Wood" => Some(BlockKind::StrippedSpruceWood), + "Stripped Birch Wood" => Some(BlockKind::StrippedBirchWood), + "Stripped Jungle Wood" => Some(BlockKind::StrippedJungleWood), + "Stripped Acacia Wood" => Some(BlockKind::StrippedAcaciaWood), + "Stripped Dark Oak Wood" => Some(BlockKind::StrippedDarkOakWood), + "Oak Leaves" => Some(BlockKind::OakLeaves), + "Spruce Leaves" => Some(BlockKind::SpruceLeaves), + "Birch Leaves" => Some(BlockKind::BirchLeaves), + "Jungle Leaves" => Some(BlockKind::JungleLeaves), + "Acacia Leaves" => Some(BlockKind::AcaciaLeaves), + "Dark Oak Leaves" => Some(BlockKind::DarkOakLeaves), + "Sponge" => Some(BlockKind::Sponge), + "Wet Sponge" => Some(BlockKind::WetSponge), + "Glass" => Some(BlockKind::Glass), + "Lapis Lazuli Ore" => Some(BlockKind::LapisOre), + "Lapis Lazuli Block" => Some(BlockKind::LapisBlock), + "Dispenser" => Some(BlockKind::Dispenser), + "Sandstone" => Some(BlockKind::Sandstone), + "Chiseled Sandstone" => Some(BlockKind::ChiseledSandstone), + "Cut Sandstone" => Some(BlockKind::CutSandstone), + "Note Block" => Some(BlockKind::NoteBlock), + "White Bed" => Some(BlockKind::WhiteBed), + "Orange Bed" => Some(BlockKind::OrangeBed), + "Magenta Bed" => Some(BlockKind::MagentaBed), + "Light Blue Bed" => Some(BlockKind::LightBlueBed), + "Yellow Bed" => Some(BlockKind::YellowBed), + "Lime Bed" => Some(BlockKind::LimeBed), + "Pink Bed" => Some(BlockKind::PinkBed), + "Gray Bed" => Some(BlockKind::GrayBed), + "Light Gray Bed" => Some(BlockKind::LightGrayBed), + "Cyan Bed" => Some(BlockKind::CyanBed), + "Purple Bed" => Some(BlockKind::PurpleBed), + "Blue Bed" => Some(BlockKind::BlueBed), + "Brown Bed" => Some(BlockKind::BrownBed), + "Green Bed" => Some(BlockKind::GreenBed), + "Red Bed" => Some(BlockKind::RedBed), + "Black Bed" => Some(BlockKind::BlackBed), + "Powered Rail" => Some(BlockKind::PoweredRail), + "Detector Rail" => Some(BlockKind::DetectorRail), + "Sticky Piston" => Some(BlockKind::StickyPiston), + "Cobweb" => Some(BlockKind::Cobweb), + "Grass" => Some(BlockKind::Grass), + "Fern" => Some(BlockKind::Fern), + "Dead Bush" => Some(BlockKind::DeadBush), + "Seagrass" => Some(BlockKind::Seagrass), + "Tall Seagrass" => Some(BlockKind::TallSeagrass), + "Piston" => Some(BlockKind::Piston), + "Piston Head" => Some(BlockKind::PistonHead), + "White Wool" => Some(BlockKind::WhiteWool), + "Orange Wool" => Some(BlockKind::OrangeWool), + "Magenta Wool" => Some(BlockKind::MagentaWool), + "Light Blue Wool" => Some(BlockKind::LightBlueWool), + "Yellow Wool" => Some(BlockKind::YellowWool), + "Lime Wool" => Some(BlockKind::LimeWool), + "Pink Wool" => Some(BlockKind::PinkWool), + "Gray Wool" => Some(BlockKind::GrayWool), + "Light Gray Wool" => Some(BlockKind::LightGrayWool), + "Cyan Wool" => Some(BlockKind::CyanWool), + "Purple Wool" => Some(BlockKind::PurpleWool), + "Blue Wool" => Some(BlockKind::BlueWool), + "Brown Wool" => Some(BlockKind::BrownWool), + "Green Wool" => Some(BlockKind::GreenWool), + "Red Wool" => Some(BlockKind::RedWool), + "Black Wool" => Some(BlockKind::BlackWool), + "Moving Piston" => Some(BlockKind::MovingPiston), + "Dandelion" => Some(BlockKind::Dandelion), + "Poppy" => Some(BlockKind::Poppy), + "Blue Orchid" => Some(BlockKind::BlueOrchid), + "Allium" => Some(BlockKind::Allium), + "Azure Bluet" => Some(BlockKind::AzureBluet), + "Red Tulip" => Some(BlockKind::RedTulip), + "Orange Tulip" => Some(BlockKind::OrangeTulip), + "White Tulip" => Some(BlockKind::WhiteTulip), + "Pink Tulip" => Some(BlockKind::PinkTulip), + "Oxeye Daisy" => Some(BlockKind::OxeyeDaisy), + "Cornflower" => Some(BlockKind::Cornflower), + "Wither Rose" => Some(BlockKind::WitherRose), + "Lily of the Valley" => Some(BlockKind::LilyOfTheValley), + "Brown Mushroom" => Some(BlockKind::BrownMushroom), + "Red Mushroom" => Some(BlockKind::RedMushroom), + "Block of Gold" => Some(BlockKind::GoldBlock), + "Block of Iron" => Some(BlockKind::IronBlock), + "Bricks" => Some(BlockKind::Bricks), + "TNT" => Some(BlockKind::Tnt), + "Bookshelf" => Some(BlockKind::Bookshelf), + "Mossy Cobblestone" => Some(BlockKind::MossyCobblestone), + "Obsidian" => Some(BlockKind::Obsidian), + "Torch" => Some(BlockKind::Torch), + "Wall Torch" => Some(BlockKind::WallTorch), + "Fire" => Some(BlockKind::Fire), + "Soul Fire" => Some(BlockKind::SoulFire), + "Spawner" => Some(BlockKind::Spawner), + "Oak Stairs" => Some(BlockKind::OakStairs), + "Chest" => Some(BlockKind::Chest), + "Redstone Wire" => Some(BlockKind::RedstoneWire), + "Diamond Ore" => Some(BlockKind::DiamondOre), + "Block of Diamond" => Some(BlockKind::DiamondBlock), + "Crafting Table" => Some(BlockKind::CraftingTable), + "Wheat Crops" => Some(BlockKind::Wheat), + "Farmland" => Some(BlockKind::Farmland), + "Furnace" => Some(BlockKind::Furnace), + "Oak Sign" => Some(BlockKind::OakSign), + "Spruce Sign" => Some(BlockKind::SpruceSign), + "Birch Sign" => Some(BlockKind::BirchSign), + "Acacia Sign" => Some(BlockKind::AcaciaSign), + "Jungle Sign" => Some(BlockKind::JungleSign), + "Dark Oak Sign" => Some(BlockKind::DarkOakSign), + "Oak Door" => Some(BlockKind::OakDoor), + "Ladder" => Some(BlockKind::Ladder), + "Rail" => Some(BlockKind::Rail), + "Cobblestone Stairs" => Some(BlockKind::CobblestoneStairs), + "Oak Wall Sign" => Some(BlockKind::OakWallSign), + "Spruce Wall Sign" => Some(BlockKind::SpruceWallSign), + "Birch Wall Sign" => Some(BlockKind::BirchWallSign), + "Acacia Wall Sign" => Some(BlockKind::AcaciaWallSign), + "Jungle Wall Sign" => Some(BlockKind::JungleWallSign), + "Dark Oak Wall Sign" => Some(BlockKind::DarkOakWallSign), + "Lever" => Some(BlockKind::Lever), + "Stone Pressure Plate" => Some(BlockKind::StonePressurePlate), + "Iron Door" => Some(BlockKind::IronDoor), + "Oak Pressure Plate" => Some(BlockKind::OakPressurePlate), + "Spruce Pressure Plate" => Some(BlockKind::SprucePressurePlate), + "Birch Pressure Plate" => Some(BlockKind::BirchPressurePlate), + "Jungle Pressure Plate" => Some(BlockKind::JunglePressurePlate), + "Acacia Pressure Plate" => Some(BlockKind::AcaciaPressurePlate), + "Dark Oak Pressure Plate" => Some(BlockKind::DarkOakPressurePlate), + "Redstone Ore" => Some(BlockKind::RedstoneOre), + "Redstone Torch" => Some(BlockKind::RedstoneTorch), + "Redstone Wall Torch" => Some(BlockKind::RedstoneWallTorch), + "Stone Button" => Some(BlockKind::StoneButton), + "Snow" => Some(BlockKind::Snow), + "Ice" => Some(BlockKind::Ice), + "Snow Block" => Some(BlockKind::SnowBlock), + "Cactus" => Some(BlockKind::Cactus), + "Clay" => Some(BlockKind::Clay), + "Sugar Cane" => Some(BlockKind::SugarCane), + "Jukebox" => Some(BlockKind::Jukebox), + "Oak Fence" => Some(BlockKind::OakFence), + "Pumpkin" => Some(BlockKind::Pumpkin), + "Netherrack" => Some(BlockKind::Netherrack), + "Soul Sand" => Some(BlockKind::SoulSand), + "Soul Soil" => Some(BlockKind::SoulSoil), + "Basalt" => Some(BlockKind::Basalt), + "Polished Basalt" => Some(BlockKind::PolishedBasalt), + "Soul Torch" => Some(BlockKind::SoulTorch), + "Soul Wall Torch" => Some(BlockKind::SoulWallTorch), + "Glowstone" => Some(BlockKind::Glowstone), + "Nether Portal" => Some(BlockKind::NetherPortal), + "Carved Pumpkin" => Some(BlockKind::CarvedPumpkin), + "Jack o'Lantern" => Some(BlockKind::JackOLantern), + "Cake" => Some(BlockKind::Cake), + "Redstone Repeater" => Some(BlockKind::Repeater), + "White Stained Glass" => Some(BlockKind::WhiteStainedGlass), + "Orange Stained Glass" => Some(BlockKind::OrangeStainedGlass), + "Magenta Stained Glass" => Some(BlockKind::MagentaStainedGlass), + "Light Blue Stained Glass" => Some(BlockKind::LightBlueStainedGlass), + "Yellow Stained Glass" => Some(BlockKind::YellowStainedGlass), + "Lime Stained Glass" => Some(BlockKind::LimeStainedGlass), + "Pink Stained Glass" => Some(BlockKind::PinkStainedGlass), + "Gray Stained Glass" => Some(BlockKind::GrayStainedGlass), + "Light Gray Stained Glass" => Some(BlockKind::LightGrayStainedGlass), + "Cyan Stained Glass" => Some(BlockKind::CyanStainedGlass), + "Purple Stained Glass" => Some(BlockKind::PurpleStainedGlass), + "Blue Stained Glass" => Some(BlockKind::BlueStainedGlass), + "Brown Stained Glass" => Some(BlockKind::BrownStainedGlass), + "Green Stained Glass" => Some(BlockKind::GreenStainedGlass), + "Red Stained Glass" => Some(BlockKind::RedStainedGlass), + "Black Stained Glass" => Some(BlockKind::BlackStainedGlass), + "Oak Trapdoor" => Some(BlockKind::OakTrapdoor), + "Spruce Trapdoor" => Some(BlockKind::SpruceTrapdoor), + "Birch Trapdoor" => Some(BlockKind::BirchTrapdoor), + "Jungle Trapdoor" => Some(BlockKind::JungleTrapdoor), + "Acacia Trapdoor" => Some(BlockKind::AcaciaTrapdoor), + "Dark Oak Trapdoor" => Some(BlockKind::DarkOakTrapdoor), + "Stone Bricks" => Some(BlockKind::StoneBricks), + "Mossy Stone Bricks" => Some(BlockKind::MossyStoneBricks), + "Cracked Stone Bricks" => Some(BlockKind::CrackedStoneBricks), + "Chiseled Stone Bricks" => Some(BlockKind::ChiseledStoneBricks), + "Infested Stone" => Some(BlockKind::InfestedStone), + "Infested Cobblestone" => Some(BlockKind::InfestedCobblestone), + "Infested Stone Bricks" => Some(BlockKind::InfestedStoneBricks), + "Infested Mossy Stone Bricks" => Some(BlockKind::InfestedMossyStoneBricks), + "Infested Cracked Stone Bricks" => Some(BlockKind::InfestedCrackedStoneBricks), + "Infested Chiseled Stone Bricks" => Some(BlockKind::InfestedChiseledStoneBricks), + "Brown Mushroom Block" => Some(BlockKind::BrownMushroomBlock), + "Red Mushroom Block" => Some(BlockKind::RedMushroomBlock), + "Mushroom Stem" => Some(BlockKind::MushroomStem), + "Iron Bars" => Some(BlockKind::IronBars), + "Chain" => Some(BlockKind::Chain), + "Glass Pane" => Some(BlockKind::GlassPane), + "Melon" => Some(BlockKind::Melon), + "Attached Pumpkin Stem" => Some(BlockKind::AttachedPumpkinStem), + "Attached Melon Stem" => Some(BlockKind::AttachedMelonStem), + "Pumpkin Stem" => Some(BlockKind::PumpkinStem), + "Melon Stem" => Some(BlockKind::MelonStem), + "Vines" => Some(BlockKind::Vine), + "Oak Fence Gate" => Some(BlockKind::OakFenceGate), + "Brick Stairs" => Some(BlockKind::BrickStairs), + "Stone Brick Stairs" => Some(BlockKind::StoneBrickStairs), + "Mycelium" => Some(BlockKind::Mycelium), + "Lily Pad" => Some(BlockKind::LilyPad), + "Nether Bricks" => Some(BlockKind::NetherBricks), + "Nether Brick Fence" => Some(BlockKind::NetherBrickFence), + "Nether Brick Stairs" => Some(BlockKind::NetherBrickStairs), + "Nether Wart" => Some(BlockKind::NetherWart), + "Enchanting Table" => Some(BlockKind::EnchantingTable), + "Brewing Stand" => Some(BlockKind::BrewingStand), + "Cauldron" => Some(BlockKind::Cauldron), + "End Portal" => Some(BlockKind::EndPortal), + "End Portal Frame" => Some(BlockKind::EndPortalFrame), + "End Stone" => Some(BlockKind::EndStone), + "Dragon Egg" => Some(BlockKind::DragonEgg), + "Redstone Lamp" => Some(BlockKind::RedstoneLamp), + "Cocoa" => Some(BlockKind::Cocoa), + "Sandstone Stairs" => Some(BlockKind::SandstoneStairs), + "Emerald Ore" => Some(BlockKind::EmeraldOre), + "Ender Chest" => Some(BlockKind::EnderChest), + "Tripwire Hook" => Some(BlockKind::TripwireHook), + "Tripwire" => Some(BlockKind::Tripwire), + "Block of Emerald" => Some(BlockKind::EmeraldBlock), + "Spruce Stairs" => Some(BlockKind::SpruceStairs), + "Birch Stairs" => Some(BlockKind::BirchStairs), + "Jungle Stairs" => Some(BlockKind::JungleStairs), + "Command Block" => Some(BlockKind::CommandBlock), + "Beacon" => Some(BlockKind::Beacon), + "Cobblestone Wall" => Some(BlockKind::CobblestoneWall), + "Mossy Cobblestone Wall" => Some(BlockKind::MossyCobblestoneWall), + "Flower Pot" => Some(BlockKind::FlowerPot), + "Potted Oak Sapling" => Some(BlockKind::PottedOakSapling), + "Potted Spruce Sapling" => Some(BlockKind::PottedSpruceSapling), + "Potted Birch Sapling" => Some(BlockKind::PottedBirchSapling), + "Potted Jungle Sapling" => Some(BlockKind::PottedJungleSapling), + "Potted Acacia Sapling" => Some(BlockKind::PottedAcaciaSapling), + "Potted Dark Oak Sapling" => Some(BlockKind::PottedDarkOakSapling), + "Potted Fern" => Some(BlockKind::PottedFern), + "Potted Dandelion" => Some(BlockKind::PottedDandelion), + "Potted Poppy" => Some(BlockKind::PottedPoppy), + "Potted Blue Orchid" => Some(BlockKind::PottedBlueOrchid), + "Potted Allium" => Some(BlockKind::PottedAllium), + "Potted Azure Bluet" => Some(BlockKind::PottedAzureBluet), + "Potted Red Tulip" => Some(BlockKind::PottedRedTulip), + "Potted Orange Tulip" => Some(BlockKind::PottedOrangeTulip), + "Potted White Tulip" => Some(BlockKind::PottedWhiteTulip), + "Potted Pink Tulip" => Some(BlockKind::PottedPinkTulip), + "Potted Oxeye Daisy" => Some(BlockKind::PottedOxeyeDaisy), + "Potted Cornflower" => Some(BlockKind::PottedCornflower), + "Potted Lily of the Valley" => Some(BlockKind::PottedLilyOfTheValley), + "Potted Wither Rose" => Some(BlockKind::PottedWitherRose), + "Potted Red Mushroom" => Some(BlockKind::PottedRedMushroom), + "Potted Brown Mushroom" => Some(BlockKind::PottedBrownMushroom), + "Potted Dead Bush" => Some(BlockKind::PottedDeadBush), + "Potted Cactus" => Some(BlockKind::PottedCactus), + "Carrots" => Some(BlockKind::Carrots), + "Potatoes" => Some(BlockKind::Potatoes), + "Oak Button" => Some(BlockKind::OakButton), + "Spruce Button" => Some(BlockKind::SpruceButton), + "Birch Button" => Some(BlockKind::BirchButton), + "Jungle Button" => Some(BlockKind::JungleButton), + "Acacia Button" => Some(BlockKind::AcaciaButton), + "Dark Oak Button" => Some(BlockKind::DarkOakButton), + "Skeleton Skull" => Some(BlockKind::SkeletonSkull), + "Skeleton Wall Skull" => Some(BlockKind::SkeletonWallSkull), + "Wither Skeleton Skull" => Some(BlockKind::WitherSkeletonSkull), + "Wither Skeleton Wall Skull" => Some(BlockKind::WitherSkeletonWallSkull), + "Zombie Head" => Some(BlockKind::ZombieHead), + "Zombie Wall Head" => Some(BlockKind::ZombieWallHead), + "Player Head" => Some(BlockKind::PlayerHead), + "Player Wall Head" => Some(BlockKind::PlayerWallHead), + "Creeper Head" => Some(BlockKind::CreeperHead), + "Creeper Wall Head" => Some(BlockKind::CreeperWallHead), + "Dragon Head" => Some(BlockKind::DragonHead), + "Dragon Wall Head" => Some(BlockKind::DragonWallHead), + "Anvil" => Some(BlockKind::Anvil), + "Chipped Anvil" => Some(BlockKind::ChippedAnvil), + "Damaged Anvil" => Some(BlockKind::DamagedAnvil), + "Trapped Chest" => Some(BlockKind::TrappedChest), + "Light Weighted Pressure Plate" => Some(BlockKind::LightWeightedPressurePlate), + "Heavy Weighted Pressure Plate" => Some(BlockKind::HeavyWeightedPressurePlate), + "Redstone Comparator" => Some(BlockKind::Comparator), + "Daylight Detector" => Some(BlockKind::DaylightDetector), + "Block of Redstone" => Some(BlockKind::RedstoneBlock), + "Nether Quartz Ore" => Some(BlockKind::NetherQuartzOre), + "Hopper" => Some(BlockKind::Hopper), + "Block of Quartz" => Some(BlockKind::QuartzBlock), + "Chiseled Quartz Block" => Some(BlockKind::ChiseledQuartzBlock), + "Quartz Pillar" => Some(BlockKind::QuartzPillar), + "Quartz Stairs" => Some(BlockKind::QuartzStairs), + "Activator Rail" => Some(BlockKind::ActivatorRail), + "Dropper" => Some(BlockKind::Dropper), + "White Terracotta" => Some(BlockKind::WhiteTerracotta), + "Orange Terracotta" => Some(BlockKind::OrangeTerracotta), + "Magenta Terracotta" => Some(BlockKind::MagentaTerracotta), + "Light Blue Terracotta" => Some(BlockKind::LightBlueTerracotta), + "Yellow Terracotta" => Some(BlockKind::YellowTerracotta), + "Lime Terracotta" => Some(BlockKind::LimeTerracotta), + "Pink Terracotta" => Some(BlockKind::PinkTerracotta), + "Gray Terracotta" => Some(BlockKind::GrayTerracotta), + "Light Gray Terracotta" => Some(BlockKind::LightGrayTerracotta), + "Cyan Terracotta" => Some(BlockKind::CyanTerracotta), + "Purple Terracotta" => Some(BlockKind::PurpleTerracotta), + "Blue Terracotta" => Some(BlockKind::BlueTerracotta), + "Brown Terracotta" => Some(BlockKind::BrownTerracotta), + "Green Terracotta" => Some(BlockKind::GreenTerracotta), + "Red Terracotta" => Some(BlockKind::RedTerracotta), + "Black Terracotta" => Some(BlockKind::BlackTerracotta), + "White Stained Glass Pane" => Some(BlockKind::WhiteStainedGlassPane), + "Orange Stained Glass Pane" => Some(BlockKind::OrangeStainedGlassPane), + "Magenta Stained Glass Pane" => Some(BlockKind::MagentaStainedGlassPane), + "Light Blue Stained Glass Pane" => Some(BlockKind::LightBlueStainedGlassPane), + "Yellow Stained Glass Pane" => Some(BlockKind::YellowStainedGlassPane), + "Lime Stained Glass Pane" => Some(BlockKind::LimeStainedGlassPane), + "Pink Stained Glass Pane" => Some(BlockKind::PinkStainedGlassPane), + "Gray Stained Glass Pane" => Some(BlockKind::GrayStainedGlassPane), + "Light Gray Stained Glass Pane" => Some(BlockKind::LightGrayStainedGlassPane), + "Cyan Stained Glass Pane" => Some(BlockKind::CyanStainedGlassPane), + "Purple Stained Glass Pane" => Some(BlockKind::PurpleStainedGlassPane), + "Blue Stained Glass Pane" => Some(BlockKind::BlueStainedGlassPane), + "Brown Stained Glass Pane" => Some(BlockKind::BrownStainedGlassPane), + "Green Stained Glass Pane" => Some(BlockKind::GreenStainedGlassPane), + "Red Stained Glass Pane" => Some(BlockKind::RedStainedGlassPane), + "Black Stained Glass Pane" => Some(BlockKind::BlackStainedGlassPane), + "Acacia Stairs" => Some(BlockKind::AcaciaStairs), + "Dark Oak Stairs" => Some(BlockKind::DarkOakStairs), + "Slime Block" => Some(BlockKind::SlimeBlock), + "Barrier" => Some(BlockKind::Barrier), + "Iron Trapdoor" => Some(BlockKind::IronTrapdoor), + "Prismarine" => Some(BlockKind::Prismarine), + "Prismarine Bricks" => Some(BlockKind::PrismarineBricks), + "Dark Prismarine" => Some(BlockKind::DarkPrismarine), + "Prismarine Stairs" => Some(BlockKind::PrismarineStairs), + "Prismarine Brick Stairs" => Some(BlockKind::PrismarineBrickStairs), + "Dark Prismarine Stairs" => Some(BlockKind::DarkPrismarineStairs), + "Prismarine Slab" => Some(BlockKind::PrismarineSlab), + "Prismarine Brick Slab" => Some(BlockKind::PrismarineBrickSlab), + "Dark Prismarine Slab" => Some(BlockKind::DarkPrismarineSlab), + "Sea Lantern" => Some(BlockKind::SeaLantern), + "Hay Bale" => Some(BlockKind::HayBlock), + "White Carpet" => Some(BlockKind::WhiteCarpet), + "Orange Carpet" => Some(BlockKind::OrangeCarpet), + "Magenta Carpet" => Some(BlockKind::MagentaCarpet), + "Light Blue Carpet" => Some(BlockKind::LightBlueCarpet), + "Yellow Carpet" => Some(BlockKind::YellowCarpet), + "Lime Carpet" => Some(BlockKind::LimeCarpet), + "Pink Carpet" => Some(BlockKind::PinkCarpet), + "Gray Carpet" => Some(BlockKind::GrayCarpet), + "Light Gray Carpet" => Some(BlockKind::LightGrayCarpet), + "Cyan Carpet" => Some(BlockKind::CyanCarpet), + "Purple Carpet" => Some(BlockKind::PurpleCarpet), + "Blue Carpet" => Some(BlockKind::BlueCarpet), + "Brown Carpet" => Some(BlockKind::BrownCarpet), + "Green Carpet" => Some(BlockKind::GreenCarpet), + "Red Carpet" => Some(BlockKind::RedCarpet), + "Black Carpet" => Some(BlockKind::BlackCarpet), + "Terracotta" => Some(BlockKind::Terracotta), + "Block of Coal" => Some(BlockKind::CoalBlock), + "Packed Ice" => Some(BlockKind::PackedIce), + "Sunflower" => Some(BlockKind::Sunflower), + "Lilac" => Some(BlockKind::Lilac), + "Rose Bush" => Some(BlockKind::RoseBush), + "Peony" => Some(BlockKind::Peony), + "Tall Grass" => Some(BlockKind::TallGrass), + "Large Fern" => Some(BlockKind::LargeFern), + "White Banner" => Some(BlockKind::WhiteBanner), + "Orange Banner" => Some(BlockKind::OrangeBanner), + "Magenta Banner" => Some(BlockKind::MagentaBanner), + "Light Blue Banner" => Some(BlockKind::LightBlueBanner), + "Yellow Banner" => Some(BlockKind::YellowBanner), + "Lime Banner" => Some(BlockKind::LimeBanner), + "Pink Banner" => Some(BlockKind::PinkBanner), + "Gray Banner" => Some(BlockKind::GrayBanner), + "Light Gray Banner" => Some(BlockKind::LightGrayBanner), + "Cyan Banner" => Some(BlockKind::CyanBanner), + "Purple Banner" => Some(BlockKind::PurpleBanner), + "Blue Banner" => Some(BlockKind::BlueBanner), + "Brown Banner" => Some(BlockKind::BrownBanner), + "Green Banner" => Some(BlockKind::GreenBanner), + "Red Banner" => Some(BlockKind::RedBanner), + "Black Banner" => Some(BlockKind::BlackBanner), + "White wall banner" => Some(BlockKind::WhiteWallBanner), + "Orange wall banner" => Some(BlockKind::OrangeWallBanner), + "Magenta wall banner" => Some(BlockKind::MagentaWallBanner), + "Light blue wall banner" => Some(BlockKind::LightBlueWallBanner), + "Yellow wall banner" => Some(BlockKind::YellowWallBanner), + "Lime wall banner" => Some(BlockKind::LimeWallBanner), + "Pink wall banner" => Some(BlockKind::PinkWallBanner), + "Gray wall banner" => Some(BlockKind::GrayWallBanner), + "Light gray wall banner" => Some(BlockKind::LightGrayWallBanner), + "Cyan wall banner" => Some(BlockKind::CyanWallBanner), + "Purple wall banner" => Some(BlockKind::PurpleWallBanner), + "Blue wall banner" => Some(BlockKind::BlueWallBanner), + "Brown wall banner" => Some(BlockKind::BrownWallBanner), + "Green wall banner" => Some(BlockKind::GreenWallBanner), + "Red wall banner" => Some(BlockKind::RedWallBanner), + "Black wall banner" => Some(BlockKind::BlackWallBanner), + "Red Sandstone" => Some(BlockKind::RedSandstone), + "Chiseled Red Sandstone" => Some(BlockKind::ChiseledRedSandstone), + "Cut Red Sandstone" => Some(BlockKind::CutRedSandstone), + "Red Sandstone Stairs" => Some(BlockKind::RedSandstoneStairs), + "Oak Slab" => Some(BlockKind::OakSlab), + "Spruce Slab" => Some(BlockKind::SpruceSlab), + "Birch Slab" => Some(BlockKind::BirchSlab), + "Jungle Slab" => Some(BlockKind::JungleSlab), + "Acacia Slab" => Some(BlockKind::AcaciaSlab), + "Dark Oak Slab" => Some(BlockKind::DarkOakSlab), + "Stone Slab" => Some(BlockKind::StoneSlab), + "Smooth Stone Slab" => Some(BlockKind::SmoothStoneSlab), + "Sandstone Slab" => Some(BlockKind::SandstoneSlab), + "Cut Sandstone Slab" => Some(BlockKind::CutSandstoneSlab), + "Petrified Oak Slab" => Some(BlockKind::PetrifiedOakSlab), + "Cobblestone Slab" => Some(BlockKind::CobblestoneSlab), + "Brick Slab" => Some(BlockKind::BrickSlab), + "Stone Brick Slab" => Some(BlockKind::StoneBrickSlab), + "Nether Brick Slab" => Some(BlockKind::NetherBrickSlab), + "Quartz Slab" => Some(BlockKind::QuartzSlab), + "Red Sandstone Slab" => Some(BlockKind::RedSandstoneSlab), + "Cut Red Sandstone Slab" => Some(BlockKind::CutRedSandstoneSlab), + "Purpur Slab" => Some(BlockKind::PurpurSlab), + "Smooth Stone" => Some(BlockKind::SmoothStone), + "Smooth Sandstone" => Some(BlockKind::SmoothSandstone), + "Smooth Quartz Block" => Some(BlockKind::SmoothQuartz), + "Smooth Red Sandstone" => Some(BlockKind::SmoothRedSandstone), + "Spruce Fence Gate" => Some(BlockKind::SpruceFenceGate), + "Birch Fence Gate" => Some(BlockKind::BirchFenceGate), + "Jungle Fence Gate" => Some(BlockKind::JungleFenceGate), + "Acacia Fence Gate" => Some(BlockKind::AcaciaFenceGate), + "Dark Oak Fence Gate" => Some(BlockKind::DarkOakFenceGate), + "Spruce Fence" => Some(BlockKind::SpruceFence), + "Birch Fence" => Some(BlockKind::BirchFence), + "Jungle Fence" => Some(BlockKind::JungleFence), + "Acacia Fence" => Some(BlockKind::AcaciaFence), + "Dark Oak Fence" => Some(BlockKind::DarkOakFence), + "Spruce Door" => Some(BlockKind::SpruceDoor), + "Birch Door" => Some(BlockKind::BirchDoor), + "Jungle Door" => Some(BlockKind::JungleDoor), + "Acacia Door" => Some(BlockKind::AcaciaDoor), + "Dark Oak Door" => Some(BlockKind::DarkOakDoor), + "End Rod" => Some(BlockKind::EndRod), + "Chorus Plant" => Some(BlockKind::ChorusPlant), + "Chorus Flower" => Some(BlockKind::ChorusFlower), + "Purpur Block" => Some(BlockKind::PurpurBlock), + "Purpur Pillar" => Some(BlockKind::PurpurPillar), + "Purpur Stairs" => Some(BlockKind::PurpurStairs), + "End Stone Bricks" => Some(BlockKind::EndStoneBricks), + "Beetroots" => Some(BlockKind::Beetroots), + "Grass Path" => Some(BlockKind::GrassPath), + "End Gateway" => Some(BlockKind::EndGateway), + "Repeating Command Block" => Some(BlockKind::RepeatingCommandBlock), + "Chain Command Block" => Some(BlockKind::ChainCommandBlock), + "Frosted Ice" => Some(BlockKind::FrostedIce), + "Magma Block" => Some(BlockKind::MagmaBlock), + "Nether Wart Block" => Some(BlockKind::NetherWartBlock), + "Red Nether Bricks" => Some(BlockKind::RedNetherBricks), + "Bone Block" => Some(BlockKind::BoneBlock), + "Structure Void" => Some(BlockKind::StructureVoid), + "Observer" => Some(BlockKind::Observer), + "Shulker Box" => Some(BlockKind::ShulkerBox), + "White Shulker Box" => Some(BlockKind::WhiteShulkerBox), + "Orange Shulker Box" => Some(BlockKind::OrangeShulkerBox), + "Magenta Shulker Box" => Some(BlockKind::MagentaShulkerBox), + "Light Blue Shulker Box" => Some(BlockKind::LightBlueShulkerBox), + "Yellow Shulker Box" => Some(BlockKind::YellowShulkerBox), + "Lime Shulker Box" => Some(BlockKind::LimeShulkerBox), + "Pink Shulker Box" => Some(BlockKind::PinkShulkerBox), + "Gray Shulker Box" => Some(BlockKind::GrayShulkerBox), + "Light Gray Shulker Box" => Some(BlockKind::LightGrayShulkerBox), + "Cyan Shulker Box" => Some(BlockKind::CyanShulkerBox), + "Purple Shulker Box" => Some(BlockKind::PurpleShulkerBox), + "Blue Shulker Box" => Some(BlockKind::BlueShulkerBox), + "Brown Shulker Box" => Some(BlockKind::BrownShulkerBox), + "Green Shulker Box" => Some(BlockKind::GreenShulkerBox), + "Red Shulker Box" => Some(BlockKind::RedShulkerBox), + "Black Shulker Box" => Some(BlockKind::BlackShulkerBox), + "White Glazed Terracotta" => Some(BlockKind::WhiteGlazedTerracotta), + "Orange Glazed Terracotta" => Some(BlockKind::OrangeGlazedTerracotta), + "Magenta Glazed Terracotta" => Some(BlockKind::MagentaGlazedTerracotta), + "Light Blue Glazed Terracotta" => Some(BlockKind::LightBlueGlazedTerracotta), + "Yellow Glazed Terracotta" => Some(BlockKind::YellowGlazedTerracotta), + "Lime Glazed Terracotta" => Some(BlockKind::LimeGlazedTerracotta), + "Pink Glazed Terracotta" => Some(BlockKind::PinkGlazedTerracotta), + "Gray Glazed Terracotta" => Some(BlockKind::GrayGlazedTerracotta), + "Light Gray Glazed Terracotta" => Some(BlockKind::LightGrayGlazedTerracotta), + "Cyan Glazed Terracotta" => Some(BlockKind::CyanGlazedTerracotta), + "Purple Glazed Terracotta" => Some(BlockKind::PurpleGlazedTerracotta), + "Blue Glazed Terracotta" => Some(BlockKind::BlueGlazedTerracotta), + "Brown Glazed Terracotta" => Some(BlockKind::BrownGlazedTerracotta), + "Green Glazed Terracotta" => Some(BlockKind::GreenGlazedTerracotta), + "Red Glazed Terracotta" => Some(BlockKind::RedGlazedTerracotta), + "Black Glazed Terracotta" => Some(BlockKind::BlackGlazedTerracotta), + "White Concrete" => Some(BlockKind::WhiteConcrete), + "Orange Concrete" => Some(BlockKind::OrangeConcrete), + "Magenta Concrete" => Some(BlockKind::MagentaConcrete), + "Light Blue Concrete" => Some(BlockKind::LightBlueConcrete), + "Yellow Concrete" => Some(BlockKind::YellowConcrete), + "Lime Concrete" => Some(BlockKind::LimeConcrete), + "Pink Concrete" => Some(BlockKind::PinkConcrete), + "Gray Concrete" => Some(BlockKind::GrayConcrete), + "Light Gray Concrete" => Some(BlockKind::LightGrayConcrete), + "Cyan Concrete" => Some(BlockKind::CyanConcrete), + "Purple Concrete" => Some(BlockKind::PurpleConcrete), + "Blue Concrete" => Some(BlockKind::BlueConcrete), + "Brown Concrete" => Some(BlockKind::BrownConcrete), + "Green Concrete" => Some(BlockKind::GreenConcrete), + "Red Concrete" => Some(BlockKind::RedConcrete), + "Black Concrete" => Some(BlockKind::BlackConcrete), + "White Concrete Powder" => Some(BlockKind::WhiteConcretePowder), + "Orange Concrete Powder" => Some(BlockKind::OrangeConcretePowder), + "Magenta Concrete Powder" => Some(BlockKind::MagentaConcretePowder), + "Light Blue Concrete Powder" => Some(BlockKind::LightBlueConcretePowder), + "Yellow Concrete Powder" => Some(BlockKind::YellowConcretePowder), + "Lime Concrete Powder" => Some(BlockKind::LimeConcretePowder), + "Pink Concrete Powder" => Some(BlockKind::PinkConcretePowder), + "Gray Concrete Powder" => Some(BlockKind::GrayConcretePowder), + "Light Gray Concrete Powder" => Some(BlockKind::LightGrayConcretePowder), + "Cyan Concrete Powder" => Some(BlockKind::CyanConcretePowder), + "Purple Concrete Powder" => Some(BlockKind::PurpleConcretePowder), + "Blue Concrete Powder" => Some(BlockKind::BlueConcretePowder), + "Brown Concrete Powder" => Some(BlockKind::BrownConcretePowder), + "Green Concrete Powder" => Some(BlockKind::GreenConcretePowder), + "Red Concrete Powder" => Some(BlockKind::RedConcretePowder), + "Black Concrete Powder" => Some(BlockKind::BlackConcretePowder), + "Kelp" => Some(BlockKind::Kelp), + "Kelp Plant" => Some(BlockKind::KelpPlant), + "Dried Kelp Block" => Some(BlockKind::DriedKelpBlock), + "Turtle Egg" => Some(BlockKind::TurtleEgg), + "Dead Tube Coral Block" => Some(BlockKind::DeadTubeCoralBlock), + "Dead Brain Coral Block" => Some(BlockKind::DeadBrainCoralBlock), + "Dead Bubble Coral Block" => Some(BlockKind::DeadBubbleCoralBlock), + "Dead Fire Coral Block" => Some(BlockKind::DeadFireCoralBlock), + "Dead Horn Coral Block" => Some(BlockKind::DeadHornCoralBlock), + "Tube Coral Block" => Some(BlockKind::TubeCoralBlock), + "Brain Coral Block" => Some(BlockKind::BrainCoralBlock), + "Bubble Coral Block" => Some(BlockKind::BubbleCoralBlock), + "Fire Coral Block" => Some(BlockKind::FireCoralBlock), + "Horn Coral Block" => Some(BlockKind::HornCoralBlock), + "Dead Tube Coral" => Some(BlockKind::DeadTubeCoral), + "Dead Brain Coral" => Some(BlockKind::DeadBrainCoral), + "Dead Bubble Coral" => Some(BlockKind::DeadBubbleCoral), + "Dead Fire Coral" => Some(BlockKind::DeadFireCoral), + "Dead Horn Coral" => Some(BlockKind::DeadHornCoral), + "Tube Coral" => Some(BlockKind::TubeCoral), + "Brain Coral" => Some(BlockKind::BrainCoral), + "Bubble Coral" => Some(BlockKind::BubbleCoral), + "Fire Coral" => Some(BlockKind::FireCoral), + "Horn Coral" => Some(BlockKind::HornCoral), + "Dead Tube Coral Fan" => Some(BlockKind::DeadTubeCoralFan), + "Dead Brain Coral Fan" => Some(BlockKind::DeadBrainCoralFan), + "Dead Bubble Coral Fan" => Some(BlockKind::DeadBubbleCoralFan), + "Dead Fire Coral Fan" => Some(BlockKind::DeadFireCoralFan), + "Dead Horn Coral Fan" => Some(BlockKind::DeadHornCoralFan), + "Tube Coral Fan" => Some(BlockKind::TubeCoralFan), + "Brain Coral Fan" => Some(BlockKind::BrainCoralFan), + "Bubble Coral Fan" => Some(BlockKind::BubbleCoralFan), + "Fire Coral Fan" => Some(BlockKind::FireCoralFan), + "Horn Coral Fan" => Some(BlockKind::HornCoralFan), + "Dead Tube Coral Wall Fan" => Some(BlockKind::DeadTubeCoralWallFan), + "Dead Brain Coral Wall Fan" => Some(BlockKind::DeadBrainCoralWallFan), + "Dead Bubble Coral Wall Fan" => Some(BlockKind::DeadBubbleCoralWallFan), + "Dead Fire Coral Wall Fan" => Some(BlockKind::DeadFireCoralWallFan), + "Dead Horn Coral Wall Fan" => Some(BlockKind::DeadHornCoralWallFan), + "Tube Coral Wall Fan" => Some(BlockKind::TubeCoralWallFan), + "Brain Coral Wall Fan" => Some(BlockKind::BrainCoralWallFan), + "Bubble Coral Wall Fan" => Some(BlockKind::BubbleCoralWallFan), + "Fire Coral Wall Fan" => Some(BlockKind::FireCoralWallFan), + "Horn Coral Wall Fan" => Some(BlockKind::HornCoralWallFan), + "Sea Pickle" => Some(BlockKind::SeaPickle), + "Blue Ice" => Some(BlockKind::BlueIce), + "Conduit" => Some(BlockKind::Conduit), + "Bamboo Shoot" => Some(BlockKind::BambooSapling), + "Bamboo" => Some(BlockKind::Bamboo), + "Potted Bamboo" => Some(BlockKind::PottedBamboo), + "Void Air" => Some(BlockKind::VoidAir), + "Cave Air" => Some(BlockKind::CaveAir), + "Bubble Column" => Some(BlockKind::BubbleColumn), + "Polished Granite Stairs" => Some(BlockKind::PolishedGraniteStairs), + "Smooth Red Sandstone Stairs" => Some(BlockKind::SmoothRedSandstoneStairs), + "Mossy Stone Brick Stairs" => Some(BlockKind::MossyStoneBrickStairs), + "Polished Diorite Stairs" => Some(BlockKind::PolishedDioriteStairs), + "Mossy Cobblestone Stairs" => Some(BlockKind::MossyCobblestoneStairs), + "End Stone Brick Stairs" => Some(BlockKind::EndStoneBrickStairs), + "Stone Stairs" => Some(BlockKind::StoneStairs), + "Smooth Sandstone Stairs" => Some(BlockKind::SmoothSandstoneStairs), + "Smooth Quartz Stairs" => Some(BlockKind::SmoothQuartzStairs), + "Granite Stairs" => Some(BlockKind::GraniteStairs), + "Andesite Stairs" => Some(BlockKind::AndesiteStairs), + "Red Nether Brick Stairs" => Some(BlockKind::RedNetherBrickStairs), + "Polished Andesite Stairs" => Some(BlockKind::PolishedAndesiteStairs), + "Diorite Stairs" => Some(BlockKind::DioriteStairs), + "Polished Granite Slab" => Some(BlockKind::PolishedGraniteSlab), + "Smooth Red Sandstone Slab" => Some(BlockKind::SmoothRedSandstoneSlab), + "Mossy Stone Brick Slab" => Some(BlockKind::MossyStoneBrickSlab), + "Polished Diorite Slab" => Some(BlockKind::PolishedDioriteSlab), + "Mossy Cobblestone Slab" => Some(BlockKind::MossyCobblestoneSlab), + "End Stone Brick Slab" => Some(BlockKind::EndStoneBrickSlab), + "Smooth Sandstone Slab" => Some(BlockKind::SmoothSandstoneSlab), + "Smooth Quartz Slab" => Some(BlockKind::SmoothQuartzSlab), + "Granite Slab" => Some(BlockKind::GraniteSlab), + "Andesite Slab" => Some(BlockKind::AndesiteSlab), + "Red Nether Brick Slab" => Some(BlockKind::RedNetherBrickSlab), + "Polished Andesite Slab" => Some(BlockKind::PolishedAndesiteSlab), + "Diorite Slab" => Some(BlockKind::DioriteSlab), + "Brick Wall" => Some(BlockKind::BrickWall), + "Prismarine Wall" => Some(BlockKind::PrismarineWall), + "Red Sandstone Wall" => Some(BlockKind::RedSandstoneWall), + "Mossy Stone Brick Wall" => Some(BlockKind::MossyStoneBrickWall), + "Granite Wall" => Some(BlockKind::GraniteWall), + "Stone Brick Wall" => Some(BlockKind::StoneBrickWall), + "Nether Brick Wall" => Some(BlockKind::NetherBrickWall), + "Andesite Wall" => Some(BlockKind::AndesiteWall), + "Red Nether Brick Wall" => Some(BlockKind::RedNetherBrickWall), + "Sandstone Wall" => Some(BlockKind::SandstoneWall), + "End Stone Brick Wall" => Some(BlockKind::EndStoneBrickWall), + "Diorite Wall" => Some(BlockKind::DioriteWall), + "Scaffolding" => Some(BlockKind::Scaffolding), + "Loom" => Some(BlockKind::Loom), + "Barrel" => Some(BlockKind::Barrel), + "Smoker" => Some(BlockKind::Smoker), + "Blast Furnace" => Some(BlockKind::BlastFurnace), + "Cartography Table" => Some(BlockKind::CartographyTable), + "Fletching Table" => Some(BlockKind::FletchingTable), + "Grindstone" => Some(BlockKind::Grindstone), + "Lectern" => Some(BlockKind::Lectern), + "Smithing Table" => Some(BlockKind::SmithingTable), + "Stonecutter" => Some(BlockKind::Stonecutter), + "Bell" => Some(BlockKind::Bell), + "Lantern" => Some(BlockKind::Lantern), + "Soul Lantern" => Some(BlockKind::SoulLantern), + "Campfire" => Some(BlockKind::Campfire), + "Soul Campfire" => Some(BlockKind::SoulCampfire), + "Sweet Berry Bush" => Some(BlockKind::SweetBerryBush), + "Warped Stem" => Some(BlockKind::WarpedStem), + "Stripped Warped Stem" => Some(BlockKind::StrippedWarpedStem), + "Warped Hyphae" => Some(BlockKind::WarpedHyphae), + "Stripped Warped Hyphae" => Some(BlockKind::StrippedWarpedHyphae), + "Warped Nylium" => Some(BlockKind::WarpedNylium), + "Warped Fungus" => Some(BlockKind::WarpedFungus), + "Warped Wart Block" => Some(BlockKind::WarpedWartBlock), + "Warped Roots" => Some(BlockKind::WarpedRoots), + "Nether Sprouts" => Some(BlockKind::NetherSprouts), + "Crimson Stem" => Some(BlockKind::CrimsonStem), + "Stripped Crimson Stem" => Some(BlockKind::StrippedCrimsonStem), + "Crimson Hyphae" => Some(BlockKind::CrimsonHyphae), + "Stripped Crimson Hyphae" => Some(BlockKind::StrippedCrimsonHyphae), + "Crimson Nylium" => Some(BlockKind::CrimsonNylium), + "Crimson Fungus" => Some(BlockKind::CrimsonFungus), + "Shroomlight" => Some(BlockKind::Shroomlight), + "Weeping Vines" => Some(BlockKind::WeepingVines), + "Weeping Vines Plant" => Some(BlockKind::WeepingVinesPlant), + "Twisting Vines" => Some(BlockKind::TwistingVines), + "Twisting Vines Plant" => Some(BlockKind::TwistingVinesPlant), + "Crimson Roots" => Some(BlockKind::CrimsonRoots), + "Crimson Planks" => Some(BlockKind::CrimsonPlanks), + "Warped Planks" => Some(BlockKind::WarpedPlanks), + "Crimson Slab" => Some(BlockKind::CrimsonSlab), + "Warped Slab" => Some(BlockKind::WarpedSlab), + "Crimson Pressure Plate" => Some(BlockKind::CrimsonPressurePlate), + "Warped Pressure Plate" => Some(BlockKind::WarpedPressurePlate), + "Crimson Fence" => Some(BlockKind::CrimsonFence), + "Warped Fence" => Some(BlockKind::WarpedFence), + "Crimson Trapdoor" => Some(BlockKind::CrimsonTrapdoor), + "Warped Trapdoor" => Some(BlockKind::WarpedTrapdoor), + "Crimson Fence Gate" => Some(BlockKind::CrimsonFenceGate), + "Warped Fence Gate" => Some(BlockKind::WarpedFenceGate), + "Crimson Stairs" => Some(BlockKind::CrimsonStairs), + "Warped Stairs" => Some(BlockKind::WarpedStairs), + "Crimson Button" => Some(BlockKind::CrimsonButton), + "Warped Button" => Some(BlockKind::WarpedButton), + "Crimson Door" => Some(BlockKind::CrimsonDoor), + "Warped Door" => Some(BlockKind::WarpedDoor), + "Crimson Sign" => Some(BlockKind::CrimsonSign), + "Warped Sign" => Some(BlockKind::WarpedSign), + "Crimson Wall Sign" => Some(BlockKind::CrimsonWallSign), + "Warped Wall Sign" => Some(BlockKind::WarpedWallSign), + "Structure Block" => Some(BlockKind::StructureBlock), + "Jigsaw Block" => Some(BlockKind::Jigsaw), + "Composter" => Some(BlockKind::Composter), + "Target" => Some(BlockKind::Target), + "Bee Nest" => Some(BlockKind::BeeNest), + "Beehive" => Some(BlockKind::Beehive), + "Honey Block" => Some(BlockKind::HoneyBlock), + "Honeycomb Block" => Some(BlockKind::HoneycombBlock), + "Block of Netherite" => Some(BlockKind::NetheriteBlock), + "Ancient Debris" => Some(BlockKind::AncientDebris), + "Crying Obsidian" => Some(BlockKind::CryingObsidian), + "Respawn Anchor" => Some(BlockKind::RespawnAnchor), + "Potted Crimson Fungus" => Some(BlockKind::PottedCrimsonFungus), + "Potted Warped Fungus" => Some(BlockKind::PottedWarpedFungus), + "Potted Crimson Roots" => Some(BlockKind::PottedCrimsonRoots), + "Potted Warped Roots" => Some(BlockKind::PottedWarpedRoots), + "Lodestone" => Some(BlockKind::Lodestone), + "Blackstone" => Some(BlockKind::Blackstone), + "Blackstone Stairs" => Some(BlockKind::BlackstoneStairs), + "Blackstone Wall" => Some(BlockKind::BlackstoneWall), + "Blackstone Slab" => Some(BlockKind::BlackstoneSlab), + "Polished Blackstone" => Some(BlockKind::PolishedBlackstone), + "Polished Blackstone Bricks" => Some(BlockKind::PolishedBlackstoneBricks), + "Cracked Polished Blackstone Bricks" => { + Some(BlockKind::CrackedPolishedBlackstoneBricks) + } + "Chiseled Polished Blackstone" => Some(BlockKind::ChiseledPolishedBlackstone), + "Polished Blackstone Brick Slab" => Some(BlockKind::PolishedBlackstoneBrickSlab), + "Polished Blackstone Brick Stairs" => Some(BlockKind::PolishedBlackstoneBrickStairs), + "Polished Blackstone Brick Wall" => Some(BlockKind::PolishedBlackstoneBrickWall), + "Gilded Blackstone" => Some(BlockKind::GildedBlackstone), + "Polished Blackstone Stairs" => Some(BlockKind::PolishedBlackstoneStairs), + "Polished Blackstone Slab" => Some(BlockKind::PolishedBlackstoneSlab), + "Polished Blackstone Pressure Plate" => { + Some(BlockKind::PolishedBlackstonePressurePlate) + } + "Polished Blackstone Button" => Some(BlockKind::PolishedBlackstoneButton), + "Polished Blackstone Wall" => Some(BlockKind::PolishedBlackstoneWall), + "Chiseled Nether Bricks" => Some(BlockKind::ChiseledNetherBricks), + "Cracked Nether Bricks" => Some(BlockKind::CrackedNetherBricks), + "Quartz Bricks" => Some(BlockKind::QuartzBricks), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `hardness` property of this `BlockKind`. + pub fn hardness(&self) -> f32 { + match self { + BlockKind::Air => 0 as f32, + BlockKind::Stone => 1.5 as f32, + BlockKind::Granite => 1.5 as f32, + BlockKind::PolishedGranite => 1.5 as f32, + BlockKind::Diorite => 1.5 as f32, + BlockKind::PolishedDiorite => 1.5 as f32, + BlockKind::Andesite => 1.5 as f32, + BlockKind::PolishedAndesite => 1.5 as f32, + BlockKind::GrassBlock => 0.6 as f32, + BlockKind::Dirt => 0.5 as f32, + BlockKind::CoarseDirt => 0.5 as f32, + BlockKind::Podzol => 0.5 as f32, + BlockKind::Cobblestone => 2 as f32, + BlockKind::OakPlanks => 2 as f32, + BlockKind::SprucePlanks => 2 as f32, + BlockKind::BirchPlanks => 2 as f32, + BlockKind::JunglePlanks => 2 as f32, + BlockKind::AcaciaPlanks => 2 as f32, + BlockKind::DarkOakPlanks => 2 as f32, + BlockKind::OakSapling => 0 as f32, + BlockKind::SpruceSapling => 0 as f32, + BlockKind::BirchSapling => 0 as f32, + BlockKind::JungleSapling => 0 as f32, + BlockKind::AcaciaSapling => 0 as f32, + BlockKind::DarkOakSapling => 0 as f32, + BlockKind::Bedrock => 0 as f32, + BlockKind::Water => 100 as f32, + BlockKind::Lava => 100 as f32, + BlockKind::Sand => 0.5 as f32, + BlockKind::RedSand => 0.5 as f32, + BlockKind::Gravel => 0.6 as f32, + BlockKind::GoldOre => 3 as f32, + BlockKind::IronOre => 3 as f32, + BlockKind::CoalOre => 3 as f32, + BlockKind::NetherGoldOre => 3 as f32, + BlockKind::OakLog => 2 as f32, + BlockKind::SpruceLog => 2 as f32, + BlockKind::BirchLog => 2 as f32, + BlockKind::JungleLog => 2 as f32, + BlockKind::AcaciaLog => 2 as f32, + BlockKind::DarkOakLog => 2 as f32, + BlockKind::StrippedSpruceLog => 2 as f32, + BlockKind::StrippedBirchLog => 2 as f32, + BlockKind::StrippedJungleLog => 2 as f32, + BlockKind::StrippedAcaciaLog => 2 as f32, + BlockKind::StrippedDarkOakLog => 2 as f32, + BlockKind::StrippedOakLog => 2 as f32, + BlockKind::OakWood => 2 as f32, + BlockKind::SpruceWood => 2 as f32, + BlockKind::BirchWood => 2 as f32, + BlockKind::JungleWood => 2 as f32, + BlockKind::AcaciaWood => 2 as f32, + BlockKind::DarkOakWood => 2 as f32, + BlockKind::StrippedOakWood => 2 as f32, + BlockKind::StrippedSpruceWood => 2 as f32, + BlockKind::StrippedBirchWood => 2 as f32, + BlockKind::StrippedJungleWood => 2 as f32, + BlockKind::StrippedAcaciaWood => 2 as f32, + BlockKind::StrippedDarkOakWood => 2 as f32, + BlockKind::OakLeaves => 0.2 as f32, + BlockKind::SpruceLeaves => 0.2 as f32, + BlockKind::BirchLeaves => 0.2 as f32, + BlockKind::JungleLeaves => 0.2 as f32, + BlockKind::AcaciaLeaves => 0.2 as f32, + BlockKind::DarkOakLeaves => 0.2 as f32, + BlockKind::Sponge => 0.6 as f32, + BlockKind::WetSponge => 0.6 as f32, + BlockKind::Glass => 0.3 as f32, + BlockKind::LapisOre => 3 as f32, + BlockKind::LapisBlock => 3 as f32, + BlockKind::Dispenser => 3.5 as f32, + BlockKind::Sandstone => 0.8 as f32, + BlockKind::ChiseledSandstone => 0.8 as f32, + BlockKind::CutSandstone => 0.8 as f32, + BlockKind::NoteBlock => 0.8 as f32, + BlockKind::WhiteBed => 0.2 as f32, + BlockKind::OrangeBed => 0.2 as f32, + BlockKind::MagentaBed => 0.2 as f32, + BlockKind::LightBlueBed => 0.2 as f32, + BlockKind::YellowBed => 0.2 as f32, + BlockKind::LimeBed => 0.2 as f32, + BlockKind::PinkBed => 0.2 as f32, + BlockKind::GrayBed => 0.2 as f32, + BlockKind::LightGrayBed => 0.2 as f32, + BlockKind::CyanBed => 0.2 as f32, + BlockKind::PurpleBed => 0.2 as f32, + BlockKind::BlueBed => 0.2 as f32, + BlockKind::BrownBed => 0.2 as f32, + BlockKind::GreenBed => 0.2 as f32, + BlockKind::RedBed => 0.2 as f32, + BlockKind::BlackBed => 0.2 as f32, + BlockKind::PoweredRail => 0.7 as f32, + BlockKind::DetectorRail => 0.7 as f32, + BlockKind::StickyPiston => 1.5 as f32, + BlockKind::Cobweb => 4 as f32, + BlockKind::Grass => 0 as f32, + BlockKind::Fern => 0 as f32, + BlockKind::DeadBush => 0 as f32, + BlockKind::Seagrass => 0 as f32, + BlockKind::TallSeagrass => 0 as f32, + BlockKind::Piston => 1.5 as f32, + BlockKind::PistonHead => 1.5 as f32, + BlockKind::WhiteWool => 0.8 as f32, + BlockKind::OrangeWool => 0.8 as f32, + BlockKind::MagentaWool => 0.8 as f32, + BlockKind::LightBlueWool => 0.8 as f32, + BlockKind::YellowWool => 0.8 as f32, + BlockKind::LimeWool => 0.8 as f32, + BlockKind::PinkWool => 0.8 as f32, + BlockKind::GrayWool => 0.8 as f32, + BlockKind::LightGrayWool => 0.8 as f32, + BlockKind::CyanWool => 0.8 as f32, + BlockKind::PurpleWool => 0.8 as f32, + BlockKind::BlueWool => 0.8 as f32, + BlockKind::BrownWool => 0.8 as f32, + BlockKind::GreenWool => 0.8 as f32, + BlockKind::RedWool => 0.8 as f32, + BlockKind::BlackWool => 0.8 as f32, + BlockKind::MovingPiston => 0 as f32, + BlockKind::Dandelion => 0 as f32, + BlockKind::Poppy => 0 as f32, + BlockKind::BlueOrchid => 0 as f32, + BlockKind::Allium => 0 as f32, + BlockKind::AzureBluet => 0 as f32, + BlockKind::RedTulip => 0 as f32, + BlockKind::OrangeTulip => 0 as f32, + BlockKind::WhiteTulip => 0 as f32, + BlockKind::PinkTulip => 0 as f32, + BlockKind::OxeyeDaisy => 0 as f32, + BlockKind::Cornflower => 0 as f32, + BlockKind::WitherRose => 0 as f32, + BlockKind::LilyOfTheValley => 0 as f32, + BlockKind::BrownMushroom => 0 as f32, + BlockKind::RedMushroom => 0 as f32, + BlockKind::GoldBlock => 3 as f32, + BlockKind::IronBlock => 5 as f32, + BlockKind::Bricks => 2 as f32, + BlockKind::Tnt => 0 as f32, + BlockKind::Bookshelf => 1.5 as f32, + BlockKind::MossyCobblestone => 2 as f32, + BlockKind::Obsidian => 50 as f32, + BlockKind::Torch => 0 as f32, + BlockKind::WallTorch => 0 as f32, + BlockKind::Fire => 0 as f32, + BlockKind::SoulFire => 0 as f32, + BlockKind::Spawner => 5 as f32, + BlockKind::OakStairs => 0 as f32, + BlockKind::Chest => 2.5 as f32, + BlockKind::RedstoneWire => 0 as f32, + BlockKind::DiamondOre => 3 as f32, + BlockKind::DiamondBlock => 5 as f32, + BlockKind::CraftingTable => 2.5 as f32, + BlockKind::Wheat => 0 as f32, + BlockKind::Farmland => 0.6 as f32, + BlockKind::Furnace => 3.5 as f32, + BlockKind::OakSign => 1 as f32, + BlockKind::SpruceSign => 1 as f32, + BlockKind::BirchSign => 1 as f32, + BlockKind::AcaciaSign => 1 as f32, + BlockKind::JungleSign => 1 as f32, + BlockKind::DarkOakSign => 1 as f32, + BlockKind::OakDoor => 3 as f32, + BlockKind::Ladder => 0.4 as f32, + BlockKind::Rail => 0.7 as f32, + BlockKind::CobblestoneStairs => 0 as f32, + BlockKind::OakWallSign => 1 as f32, + BlockKind::SpruceWallSign => 1 as f32, + BlockKind::BirchWallSign => 1 as f32, + BlockKind::AcaciaWallSign => 1 as f32, + BlockKind::JungleWallSign => 1 as f32, + BlockKind::DarkOakWallSign => 1 as f32, + BlockKind::Lever => 0.5 as f32, + BlockKind::StonePressurePlate => 0.5 as f32, + BlockKind::IronDoor => 5 as f32, + BlockKind::OakPressurePlate => 0.5 as f32, + BlockKind::SprucePressurePlate => 0.5 as f32, + BlockKind::BirchPressurePlate => 0.5 as f32, + BlockKind::JunglePressurePlate => 0.5 as f32, + BlockKind::AcaciaPressurePlate => 0.5 as f32, + BlockKind::DarkOakPressurePlate => 0.5 as f32, + BlockKind::RedstoneOre => 3 as f32, + BlockKind::RedstoneTorch => 0 as f32, + BlockKind::RedstoneWallTorch => 0 as f32, + BlockKind::StoneButton => 0.5 as f32, + BlockKind::Snow => 0.1 as f32, + BlockKind::Ice => 0.5 as f32, + BlockKind::SnowBlock => 0.2 as f32, + BlockKind::Cactus => 0.4 as f32, + BlockKind::Clay => 0.6 as f32, + BlockKind::SugarCane => 0 as f32, + BlockKind::Jukebox => 2 as f32, + BlockKind::OakFence => 2 as f32, + BlockKind::Pumpkin => 1 as f32, + BlockKind::Netherrack => 0.4 as f32, + BlockKind::SoulSand => 0.5 as f32, + BlockKind::SoulSoil => 0.5 as f32, + BlockKind::Basalt => 1.25 as f32, + BlockKind::PolishedBasalt => 1.25 as f32, + BlockKind::SoulTorch => 0 as f32, + BlockKind::SoulWallTorch => 0 as f32, + BlockKind::Glowstone => 0.3 as f32, + BlockKind::NetherPortal => 0 as f32, + BlockKind::CarvedPumpkin => 1 as f32, + BlockKind::JackOLantern => 1 as f32, + BlockKind::Cake => 0.5 as f32, + BlockKind::Repeater => 0 as f32, + BlockKind::WhiteStainedGlass => 0.3 as f32, + BlockKind::OrangeStainedGlass => 0.3 as f32, + BlockKind::MagentaStainedGlass => 0.3 as f32, + BlockKind::LightBlueStainedGlass => 0.3 as f32, + BlockKind::YellowStainedGlass => 0.3 as f32, + BlockKind::LimeStainedGlass => 0.3 as f32, + BlockKind::PinkStainedGlass => 0.3 as f32, + BlockKind::GrayStainedGlass => 0.3 as f32, + BlockKind::LightGrayStainedGlass => 0.3 as f32, + BlockKind::CyanStainedGlass => 0.3 as f32, + BlockKind::PurpleStainedGlass => 0.3 as f32, + BlockKind::BlueStainedGlass => 0.3 as f32, + BlockKind::BrownStainedGlass => 0.3 as f32, + BlockKind::GreenStainedGlass => 0.3 as f32, + BlockKind::RedStainedGlass => 0.3 as f32, + BlockKind::BlackStainedGlass => 0.3 as f32, + BlockKind::OakTrapdoor => 3 as f32, + BlockKind::SpruceTrapdoor => 3 as f32, + BlockKind::BirchTrapdoor => 3 as f32, + BlockKind::JungleTrapdoor => 3 as f32, + BlockKind::AcaciaTrapdoor => 3 as f32, + BlockKind::DarkOakTrapdoor => 3 as f32, + BlockKind::StoneBricks => 1.5 as f32, + BlockKind::MossyStoneBricks => 1.5 as f32, + BlockKind::CrackedStoneBricks => 1.5 as f32, + BlockKind::ChiseledStoneBricks => 1.5 as f32, + BlockKind::InfestedStone => 0 as f32, + BlockKind::InfestedCobblestone => 0 as f32, + BlockKind::InfestedStoneBricks => 0 as f32, + BlockKind::InfestedMossyStoneBricks => 0 as f32, + BlockKind::InfestedCrackedStoneBricks => 0 as f32, + BlockKind::InfestedChiseledStoneBricks => 0 as f32, + BlockKind::BrownMushroomBlock => 0.2 as f32, + BlockKind::RedMushroomBlock => 0.2 as f32, + BlockKind::MushroomStem => 0.2 as f32, + BlockKind::IronBars => 5 as f32, + BlockKind::Chain => 5 as f32, + BlockKind::GlassPane => 0.3 as f32, + BlockKind::Melon => 1 as f32, + BlockKind::AttachedPumpkinStem => 0 as f32, + BlockKind::AttachedMelonStem => 0 as f32, + BlockKind::PumpkinStem => 0 as f32, + BlockKind::MelonStem => 0 as f32, + BlockKind::Vine => 0.2 as f32, + BlockKind::OakFenceGate => 2 as f32, + BlockKind::BrickStairs => 0 as f32, + BlockKind::StoneBrickStairs => 0 as f32, + BlockKind::Mycelium => 0.6 as f32, + BlockKind::LilyPad => 0 as f32, + BlockKind::NetherBricks => 2 as f32, + BlockKind::NetherBrickFence => 2 as f32, + BlockKind::NetherBrickStairs => 0 as f32, + BlockKind::NetherWart => 0 as f32, + BlockKind::EnchantingTable => 5 as f32, + BlockKind::BrewingStand => 0.5 as f32, + BlockKind::Cauldron => 2 as f32, + BlockKind::EndPortal => 0 as f32, + BlockKind::EndPortalFrame => 0 as f32, + BlockKind::EndStone => 3 as f32, + BlockKind::DragonEgg => 3 as f32, + BlockKind::RedstoneLamp => 0.3 as f32, + BlockKind::Cocoa => 0.2 as f32, + BlockKind::SandstoneStairs => 0 as f32, + BlockKind::EmeraldOre => 3 as f32, + BlockKind::EnderChest => 22.5 as f32, + BlockKind::TripwireHook => 0 as f32, + BlockKind::Tripwire => 0 as f32, + BlockKind::EmeraldBlock => 5 as f32, + BlockKind::SpruceStairs => 0 as f32, + BlockKind::BirchStairs => 0 as f32, + BlockKind::JungleStairs => 0 as f32, + BlockKind::CommandBlock => 0 as f32, + BlockKind::Beacon => 3 as f32, + BlockKind::CobblestoneWall => 0 as f32, + BlockKind::MossyCobblestoneWall => 0 as f32, + BlockKind::FlowerPot => 0 as f32, + BlockKind::PottedOakSapling => 0 as f32, + BlockKind::PottedSpruceSapling => 0 as f32, + BlockKind::PottedBirchSapling => 0 as f32, + BlockKind::PottedJungleSapling => 0 as f32, + BlockKind::PottedAcaciaSapling => 0 as f32, + BlockKind::PottedDarkOakSapling => 0 as f32, + BlockKind::PottedFern => 0 as f32, + BlockKind::PottedDandelion => 0 as f32, + BlockKind::PottedPoppy => 0 as f32, + BlockKind::PottedBlueOrchid => 0 as f32, + BlockKind::PottedAllium => 0 as f32, + BlockKind::PottedAzureBluet => 0 as f32, + BlockKind::PottedRedTulip => 0 as f32, + BlockKind::PottedOrangeTulip => 0 as f32, + BlockKind::PottedWhiteTulip => 0 as f32, + BlockKind::PottedPinkTulip => 0 as f32, + BlockKind::PottedOxeyeDaisy => 0 as f32, + BlockKind::PottedCornflower => 0 as f32, + BlockKind::PottedLilyOfTheValley => 0 as f32, + BlockKind::PottedWitherRose => 0 as f32, + BlockKind::PottedRedMushroom => 0 as f32, + BlockKind::PottedBrownMushroom => 0 as f32, + BlockKind::PottedDeadBush => 0 as f32, + BlockKind::PottedCactus => 0 as f32, + BlockKind::Carrots => 0 as f32, + BlockKind::Potatoes => 0 as f32, + BlockKind::OakButton => 0.5 as f32, + BlockKind::SpruceButton => 0.5 as f32, + BlockKind::BirchButton => 0.5 as f32, + BlockKind::JungleButton => 0.5 as f32, + BlockKind::AcaciaButton => 0.5 as f32, + BlockKind::DarkOakButton => 0.5 as f32, + BlockKind::SkeletonSkull => 1 as f32, + BlockKind::SkeletonWallSkull => 1 as f32, + BlockKind::WitherSkeletonSkull => 1 as f32, + BlockKind::WitherSkeletonWallSkull => 1 as f32, + BlockKind::ZombieHead => 1 as f32, + BlockKind::ZombieWallHead => 1 as f32, + BlockKind::PlayerHead => 1 as f32, + BlockKind::PlayerWallHead => 1 as f32, + BlockKind::CreeperHead => 1 as f32, + BlockKind::CreeperWallHead => 1 as f32, + BlockKind::DragonHead => 1 as f32, + BlockKind::DragonWallHead => 1 as f32, + BlockKind::Anvil => 5 as f32, + BlockKind::ChippedAnvil => 5 as f32, + BlockKind::DamagedAnvil => 5 as f32, + BlockKind::TrappedChest => 2.5 as f32, + BlockKind::LightWeightedPressurePlate => 0.5 as f32, + BlockKind::HeavyWeightedPressurePlate => 0.5 as f32, + BlockKind::Comparator => 0 as f32, + BlockKind::DaylightDetector => 0.2 as f32, + BlockKind::RedstoneBlock => 5 as f32, + BlockKind::NetherQuartzOre => 3 as f32, + BlockKind::Hopper => 3 as f32, + BlockKind::QuartzBlock => 0.8 as f32, + BlockKind::ChiseledQuartzBlock => 0.8 as f32, + BlockKind::QuartzPillar => 0.8 as f32, + BlockKind::QuartzStairs => 0 as f32, + BlockKind::ActivatorRail => 0.7 as f32, + BlockKind::Dropper => 3.5 as f32, + BlockKind::WhiteTerracotta => 1.25 as f32, + BlockKind::OrangeTerracotta => 1.25 as f32, + BlockKind::MagentaTerracotta => 1.25 as f32, + BlockKind::LightBlueTerracotta => 1.25 as f32, + BlockKind::YellowTerracotta => 1.25 as f32, + BlockKind::LimeTerracotta => 1.25 as f32, + BlockKind::PinkTerracotta => 1.25 as f32, + BlockKind::GrayTerracotta => 1.25 as f32, + BlockKind::LightGrayTerracotta => 1.25 as f32, + BlockKind::CyanTerracotta => 1.25 as f32, + BlockKind::PurpleTerracotta => 1.25 as f32, + BlockKind::BlueTerracotta => 1.25 as f32, + BlockKind::BrownTerracotta => 1.25 as f32, + BlockKind::GreenTerracotta => 1.25 as f32, + BlockKind::RedTerracotta => 1.25 as f32, + BlockKind::BlackTerracotta => 1.25 as f32, + BlockKind::WhiteStainedGlassPane => 0.3 as f32, + BlockKind::OrangeStainedGlassPane => 0.3 as f32, + BlockKind::MagentaStainedGlassPane => 0.3 as f32, + BlockKind::LightBlueStainedGlassPane => 0.3 as f32, + BlockKind::YellowStainedGlassPane => 0.3 as f32, + BlockKind::LimeStainedGlassPane => 0.3 as f32, + BlockKind::PinkStainedGlassPane => 0.3 as f32, + BlockKind::GrayStainedGlassPane => 0.3 as f32, + BlockKind::LightGrayStainedGlassPane => 0.3 as f32, + BlockKind::CyanStainedGlassPane => 0.3 as f32, + BlockKind::PurpleStainedGlassPane => 0.3 as f32, + BlockKind::BlueStainedGlassPane => 0.3 as f32, + BlockKind::BrownStainedGlassPane => 0.3 as f32, + BlockKind::GreenStainedGlassPane => 0.3 as f32, + BlockKind::RedStainedGlassPane => 0.3 as f32, + BlockKind::BlackStainedGlassPane => 0.3 as f32, + BlockKind::AcaciaStairs => 0 as f32, + BlockKind::DarkOakStairs => 0 as f32, + BlockKind::SlimeBlock => 0 as f32, + BlockKind::Barrier => 0 as f32, + BlockKind::IronTrapdoor => 5 as f32, + BlockKind::Prismarine => 1.5 as f32, + BlockKind::PrismarineBricks => 1.5 as f32, + BlockKind::DarkPrismarine => 1.5 as f32, + BlockKind::PrismarineStairs => 0 as f32, + BlockKind::PrismarineBrickStairs => 0 as f32, + BlockKind::DarkPrismarineStairs => 0 as f32, + BlockKind::PrismarineSlab => 1.5 as f32, + BlockKind::PrismarineBrickSlab => 1.5 as f32, + BlockKind::DarkPrismarineSlab => 1.5 as f32, + BlockKind::SeaLantern => 0.3 as f32, + BlockKind::HayBlock => 0.5 as f32, + BlockKind::WhiteCarpet => 0.1 as f32, + BlockKind::OrangeCarpet => 0.1 as f32, + BlockKind::MagentaCarpet => 0.1 as f32, + BlockKind::LightBlueCarpet => 0.1 as f32, + BlockKind::YellowCarpet => 0.1 as f32, + BlockKind::LimeCarpet => 0.1 as f32, + BlockKind::PinkCarpet => 0.1 as f32, + BlockKind::GrayCarpet => 0.1 as f32, + BlockKind::LightGrayCarpet => 0.1 as f32, + BlockKind::CyanCarpet => 0.1 as f32, + BlockKind::PurpleCarpet => 0.1 as f32, + BlockKind::BlueCarpet => 0.1 as f32, + BlockKind::BrownCarpet => 0.1 as f32, + BlockKind::GreenCarpet => 0.1 as f32, + BlockKind::RedCarpet => 0.1 as f32, + BlockKind::BlackCarpet => 0.1 as f32, + BlockKind::Terracotta => 1.25 as f32, + BlockKind::CoalBlock => 5 as f32, + BlockKind::PackedIce => 0.5 as f32, + BlockKind::Sunflower => 0 as f32, + BlockKind::Lilac => 0 as f32, + BlockKind::RoseBush => 0 as f32, + BlockKind::Peony => 0 as f32, + BlockKind::TallGrass => 0 as f32, + BlockKind::LargeFern => 0 as f32, + BlockKind::WhiteBanner => 1 as f32, + BlockKind::OrangeBanner => 1 as f32, + BlockKind::MagentaBanner => 1 as f32, + BlockKind::LightBlueBanner => 1 as f32, + BlockKind::YellowBanner => 1 as f32, + BlockKind::LimeBanner => 1 as f32, + BlockKind::PinkBanner => 1 as f32, + BlockKind::GrayBanner => 1 as f32, + BlockKind::LightGrayBanner => 1 as f32, + BlockKind::CyanBanner => 1 as f32, + BlockKind::PurpleBanner => 1 as f32, + BlockKind::BlueBanner => 1 as f32, + BlockKind::BrownBanner => 1 as f32, + BlockKind::GreenBanner => 1 as f32, + BlockKind::RedBanner => 1 as f32, + BlockKind::BlackBanner => 1 as f32, + BlockKind::WhiteWallBanner => 1 as f32, + BlockKind::OrangeWallBanner => 1 as f32, + BlockKind::MagentaWallBanner => 1 as f32, + BlockKind::LightBlueWallBanner => 1 as f32, + BlockKind::YellowWallBanner => 1 as f32, + BlockKind::LimeWallBanner => 1 as f32, + BlockKind::PinkWallBanner => 1 as f32, + BlockKind::GrayWallBanner => 1 as f32, + BlockKind::LightGrayWallBanner => 1 as f32, + BlockKind::CyanWallBanner => 1 as f32, + BlockKind::PurpleWallBanner => 1 as f32, + BlockKind::BlueWallBanner => 1 as f32, + BlockKind::BrownWallBanner => 1 as f32, + BlockKind::GreenWallBanner => 1 as f32, + BlockKind::RedWallBanner => 1 as f32, + BlockKind::BlackWallBanner => 1 as f32, + BlockKind::RedSandstone => 0.8 as f32, + BlockKind::ChiseledRedSandstone => 0.8 as f32, + BlockKind::CutRedSandstone => 0.8 as f32, + BlockKind::RedSandstoneStairs => 0 as f32, + BlockKind::OakSlab => 2 as f32, + BlockKind::SpruceSlab => 2 as f32, + BlockKind::BirchSlab => 2 as f32, + BlockKind::JungleSlab => 2 as f32, + BlockKind::AcaciaSlab => 2 as f32, + BlockKind::DarkOakSlab => 2 as f32, + BlockKind::StoneSlab => 2 as f32, + BlockKind::SmoothStoneSlab => 2 as f32, + BlockKind::SandstoneSlab => 2 as f32, + BlockKind::CutSandstoneSlab => 2 as f32, + BlockKind::PetrifiedOakSlab => 2 as f32, + BlockKind::CobblestoneSlab => 2 as f32, + BlockKind::BrickSlab => 2 as f32, + BlockKind::StoneBrickSlab => 2 as f32, + BlockKind::NetherBrickSlab => 2 as f32, + BlockKind::QuartzSlab => 2 as f32, + BlockKind::RedSandstoneSlab => 2 as f32, + BlockKind::CutRedSandstoneSlab => 2 as f32, + BlockKind::PurpurSlab => 2 as f32, + BlockKind::SmoothStone => 2 as f32, + BlockKind::SmoothSandstone => 2 as f32, + BlockKind::SmoothQuartz => 2 as f32, + BlockKind::SmoothRedSandstone => 2 as f32, + BlockKind::SpruceFenceGate => 2 as f32, + BlockKind::BirchFenceGate => 2 as f32, + BlockKind::JungleFenceGate => 2 as f32, + BlockKind::AcaciaFenceGate => 2 as f32, + BlockKind::DarkOakFenceGate => 2 as f32, + BlockKind::SpruceFence => 2 as f32, + BlockKind::BirchFence => 2 as f32, + BlockKind::JungleFence => 2 as f32, + BlockKind::AcaciaFence => 2 as f32, + BlockKind::DarkOakFence => 2 as f32, + BlockKind::SpruceDoor => 3 as f32, + BlockKind::BirchDoor => 3 as f32, + BlockKind::JungleDoor => 3 as f32, + BlockKind::AcaciaDoor => 3 as f32, + BlockKind::DarkOakDoor => 3 as f32, + BlockKind::EndRod => 0 as f32, + BlockKind::ChorusPlant => 0.4 as f32, + BlockKind::ChorusFlower => 0.4 as f32, + BlockKind::PurpurBlock => 1.5 as f32, + BlockKind::PurpurPillar => 1.5 as f32, + BlockKind::PurpurStairs => 0 as f32, + BlockKind::EndStoneBricks => 3 as f32, + BlockKind::Beetroots => 0 as f32, + BlockKind::GrassPath => 0.65 as f32, + BlockKind::EndGateway => 0 as f32, + BlockKind::RepeatingCommandBlock => 0 as f32, + BlockKind::ChainCommandBlock => 0 as f32, + BlockKind::FrostedIce => 0.5 as f32, + BlockKind::MagmaBlock => 0.5 as f32, + BlockKind::NetherWartBlock => 1 as f32, + BlockKind::RedNetherBricks => 2 as f32, + BlockKind::BoneBlock => 2 as f32, + BlockKind::StructureVoid => 0 as f32, + BlockKind::Observer => 3 as f32, + BlockKind::ShulkerBox => 2 as f32, + BlockKind::WhiteShulkerBox => 2 as f32, + BlockKind::OrangeShulkerBox => 2 as f32, + BlockKind::MagentaShulkerBox => 2 as f32, + BlockKind::LightBlueShulkerBox => 2 as f32, + BlockKind::YellowShulkerBox => 2 as f32, + BlockKind::LimeShulkerBox => 2 as f32, + BlockKind::PinkShulkerBox => 2 as f32, + BlockKind::GrayShulkerBox => 2 as f32, + BlockKind::LightGrayShulkerBox => 2 as f32, + BlockKind::CyanShulkerBox => 2 as f32, + BlockKind::PurpleShulkerBox => 2 as f32, + BlockKind::BlueShulkerBox => 2 as f32, + BlockKind::BrownShulkerBox => 2 as f32, + BlockKind::GreenShulkerBox => 2 as f32, + BlockKind::RedShulkerBox => 2 as f32, + BlockKind::BlackShulkerBox => 2 as f32, + BlockKind::WhiteGlazedTerracotta => 1.4 as f32, + BlockKind::OrangeGlazedTerracotta => 1.4 as f32, + BlockKind::MagentaGlazedTerracotta => 1.4 as f32, + BlockKind::LightBlueGlazedTerracotta => 1.4 as f32, + BlockKind::YellowGlazedTerracotta => 1.4 as f32, + BlockKind::LimeGlazedTerracotta => 1.4 as f32, + BlockKind::PinkGlazedTerracotta => 1.4 as f32, + BlockKind::GrayGlazedTerracotta => 1.4 as f32, + BlockKind::LightGrayGlazedTerracotta => 1.4 as f32, + BlockKind::CyanGlazedTerracotta => 1.4 as f32, + BlockKind::PurpleGlazedTerracotta => 1.4 as f32, + BlockKind::BlueGlazedTerracotta => 1.4 as f32, + BlockKind::BrownGlazedTerracotta => 1.4 as f32, + BlockKind::GreenGlazedTerracotta => 1.4 as f32, + BlockKind::RedGlazedTerracotta => 1.4 as f32, + BlockKind::BlackGlazedTerracotta => 1.4 as f32, + BlockKind::WhiteConcrete => 1.8 as f32, + BlockKind::OrangeConcrete => 1.8 as f32, + BlockKind::MagentaConcrete => 1.8 as f32, + BlockKind::LightBlueConcrete => 1.8 as f32, + BlockKind::YellowConcrete => 1.8 as f32, + BlockKind::LimeConcrete => 1.8 as f32, + BlockKind::PinkConcrete => 1.8 as f32, + BlockKind::GrayConcrete => 1.8 as f32, + BlockKind::LightGrayConcrete => 1.8 as f32, + BlockKind::CyanConcrete => 1.8 as f32, + BlockKind::PurpleConcrete => 1.8 as f32, + BlockKind::BlueConcrete => 1.8 as f32, + BlockKind::BrownConcrete => 1.8 as f32, + BlockKind::GreenConcrete => 1.8 as f32, + BlockKind::RedConcrete => 1.8 as f32, + BlockKind::BlackConcrete => 1.8 as f32, + BlockKind::WhiteConcretePowder => 0.5 as f32, + BlockKind::OrangeConcretePowder => 0.5 as f32, + BlockKind::MagentaConcretePowder => 0.5 as f32, + BlockKind::LightBlueConcretePowder => 0.5 as f32, + BlockKind::YellowConcretePowder => 0.5 as f32, + BlockKind::LimeConcretePowder => 0.5 as f32, + BlockKind::PinkConcretePowder => 0.5 as f32, + BlockKind::GrayConcretePowder => 0.5 as f32, + BlockKind::LightGrayConcretePowder => 0.5 as f32, + BlockKind::CyanConcretePowder => 0.5 as f32, + BlockKind::PurpleConcretePowder => 0.5 as f32, + BlockKind::BlueConcretePowder => 0.5 as f32, + BlockKind::BrownConcretePowder => 0.5 as f32, + BlockKind::GreenConcretePowder => 0.5 as f32, + BlockKind::RedConcretePowder => 0.5 as f32, + BlockKind::BlackConcretePowder => 0.5 as f32, + BlockKind::Kelp => 0 as f32, + BlockKind::KelpPlant => 0 as f32, + BlockKind::DriedKelpBlock => 0.5 as f32, + BlockKind::TurtleEgg => 0.5 as f32, + BlockKind::DeadTubeCoralBlock => 1.5 as f32, + BlockKind::DeadBrainCoralBlock => 1.5 as f32, + BlockKind::DeadBubbleCoralBlock => 1.5 as f32, + BlockKind::DeadFireCoralBlock => 1.5 as f32, + BlockKind::DeadHornCoralBlock => 1.5 as f32, + BlockKind::TubeCoralBlock => 1.5 as f32, + BlockKind::BrainCoralBlock => 1.5 as f32, + BlockKind::BubbleCoralBlock => 1.5 as f32, + BlockKind::FireCoralBlock => 1.5 as f32, + BlockKind::HornCoralBlock => 1.5 as f32, + BlockKind::DeadTubeCoral => 0 as f32, + BlockKind::DeadBrainCoral => 0 as f32, + BlockKind::DeadBubbleCoral => 0 as f32, + BlockKind::DeadFireCoral => 0 as f32, + BlockKind::DeadHornCoral => 0 as f32, + BlockKind::TubeCoral => 0 as f32, + BlockKind::BrainCoral => 0 as f32, + BlockKind::BubbleCoral => 0 as f32, + BlockKind::FireCoral => 0 as f32, + BlockKind::HornCoral => 0 as f32, + BlockKind::DeadTubeCoralFan => 0 as f32, + BlockKind::DeadBrainCoralFan => 0 as f32, + BlockKind::DeadBubbleCoralFan => 0 as f32, + BlockKind::DeadFireCoralFan => 0 as f32, + BlockKind::DeadHornCoralFan => 0 as f32, + BlockKind::TubeCoralFan => 0 as f32, + BlockKind::BrainCoralFan => 0 as f32, + BlockKind::BubbleCoralFan => 0 as f32, + BlockKind::FireCoralFan => 0 as f32, + BlockKind::HornCoralFan => 0 as f32, + BlockKind::DeadTubeCoralWallFan => 0 as f32, + BlockKind::DeadBrainCoralWallFan => 0 as f32, + BlockKind::DeadBubbleCoralWallFan => 0 as f32, + BlockKind::DeadFireCoralWallFan => 0 as f32, + BlockKind::DeadHornCoralWallFan => 0 as f32, + BlockKind::TubeCoralWallFan => 0 as f32, + BlockKind::BrainCoralWallFan => 0 as f32, + BlockKind::BubbleCoralWallFan => 0 as f32, + BlockKind::FireCoralWallFan => 0 as f32, + BlockKind::HornCoralWallFan => 0 as f32, + BlockKind::SeaPickle => 0 as f32, + BlockKind::BlueIce => 2.8 as f32, + BlockKind::Conduit => 3 as f32, + BlockKind::BambooSapling => 1 as f32, + BlockKind::Bamboo => 1 as f32, + BlockKind::PottedBamboo => 0 as f32, + BlockKind::VoidAir => 0 as f32, + BlockKind::CaveAir => 0 as f32, + BlockKind::BubbleColumn => 0 as f32, + BlockKind::PolishedGraniteStairs => 0 as f32, + BlockKind::SmoothRedSandstoneStairs => 0 as f32, + BlockKind::MossyStoneBrickStairs => 0 as f32, + BlockKind::PolishedDioriteStairs => 0 as f32, + BlockKind::MossyCobblestoneStairs => 0 as f32, + BlockKind::EndStoneBrickStairs => 0 as f32, + BlockKind::StoneStairs => 0 as f32, + BlockKind::SmoothSandstoneStairs => 0 as f32, + BlockKind::SmoothQuartzStairs => 0 as f32, + BlockKind::GraniteStairs => 0 as f32, + BlockKind::AndesiteStairs => 0 as f32, + BlockKind::RedNetherBrickStairs => 0 as f32, + BlockKind::PolishedAndesiteStairs => 0 as f32, + BlockKind::DioriteStairs => 0 as f32, + BlockKind::PolishedGraniteSlab => 0 as f32, + BlockKind::SmoothRedSandstoneSlab => 0 as f32, + BlockKind::MossyStoneBrickSlab => 0 as f32, + BlockKind::PolishedDioriteSlab => 0 as f32, + BlockKind::MossyCobblestoneSlab => 0 as f32, + BlockKind::EndStoneBrickSlab => 0 as f32, + BlockKind::SmoothSandstoneSlab => 0 as f32, + BlockKind::SmoothQuartzSlab => 0 as f32, + BlockKind::GraniteSlab => 0 as f32, + BlockKind::AndesiteSlab => 0 as f32, + BlockKind::RedNetherBrickSlab => 0 as f32, + BlockKind::PolishedAndesiteSlab => 0 as f32, + BlockKind::DioriteSlab => 0 as f32, + BlockKind::BrickWall => 0 as f32, + BlockKind::PrismarineWall => 0 as f32, + BlockKind::RedSandstoneWall => 0 as f32, + BlockKind::MossyStoneBrickWall => 0 as f32, + BlockKind::GraniteWall => 0 as f32, + BlockKind::StoneBrickWall => 0 as f32, + BlockKind::NetherBrickWall => 0 as f32, + BlockKind::AndesiteWall => 0 as f32, + BlockKind::RedNetherBrickWall => 0 as f32, + BlockKind::SandstoneWall => 0 as f32, + BlockKind::EndStoneBrickWall => 0 as f32, + BlockKind::DioriteWall => 0 as f32, + BlockKind::Scaffolding => 0 as f32, + BlockKind::Loom => 2.5 as f32, + BlockKind::Barrel => 2.5 as f32, + BlockKind::Smoker => 3.5 as f32, + BlockKind::BlastFurnace => 3.5 as f32, + BlockKind::CartographyTable => 2.5 as f32, + BlockKind::FletchingTable => 2.5 as f32, + BlockKind::Grindstone => 2 as f32, + BlockKind::Lectern => 2.5 as f32, + BlockKind::SmithingTable => 2.5 as f32, + BlockKind::Stonecutter => 3.5 as f32, + BlockKind::Bell => 5 as f32, + BlockKind::Lantern => 3.5 as f32, + BlockKind::SoulLantern => 3.5 as f32, + BlockKind::Campfire => 2 as f32, + BlockKind::SoulCampfire => 2 as f32, + BlockKind::SweetBerryBush => 0 as f32, + BlockKind::WarpedStem => 2 as f32, + BlockKind::StrippedWarpedStem => 2 as f32, + BlockKind::WarpedHyphae => 2 as f32, + BlockKind::StrippedWarpedHyphae => 2 as f32, + BlockKind::WarpedNylium => 0.4 as f32, + BlockKind::WarpedFungus => 0 as f32, + BlockKind::WarpedWartBlock => 1 as f32, + BlockKind::WarpedRoots => 0 as f32, + BlockKind::NetherSprouts => 0 as f32, + BlockKind::CrimsonStem => 2 as f32, + BlockKind::StrippedCrimsonStem => 2 as f32, + BlockKind::CrimsonHyphae => 2 as f32, + BlockKind::StrippedCrimsonHyphae => 2 as f32, + BlockKind::CrimsonNylium => 0.4 as f32, + BlockKind::CrimsonFungus => 0 as f32, + BlockKind::Shroomlight => 1 as f32, + BlockKind::WeepingVines => 0 as f32, + BlockKind::WeepingVinesPlant => 0 as f32, + BlockKind::TwistingVines => 0 as f32, + BlockKind::TwistingVinesPlant => 0 as f32, + BlockKind::CrimsonRoots => 0 as f32, + BlockKind::CrimsonPlanks => 2 as f32, + BlockKind::WarpedPlanks => 2 as f32, + BlockKind::CrimsonSlab => 2 as f32, + BlockKind::WarpedSlab => 2 as f32, + BlockKind::CrimsonPressurePlate => 0.5 as f32, + BlockKind::WarpedPressurePlate => 0.5 as f32, + BlockKind::CrimsonFence => 2 as f32, + BlockKind::WarpedFence => 2 as f32, + BlockKind::CrimsonTrapdoor => 3 as f32, + BlockKind::WarpedTrapdoor => 3 as f32, + BlockKind::CrimsonFenceGate => 2 as f32, + BlockKind::WarpedFenceGate => 2 as f32, + BlockKind::CrimsonStairs => 0 as f32, + BlockKind::WarpedStairs => 0 as f32, + BlockKind::CrimsonButton => 0.5 as f32, + BlockKind::WarpedButton => 0.5 as f32, + BlockKind::CrimsonDoor => 3 as f32, + BlockKind::WarpedDoor => 3 as f32, + BlockKind::CrimsonSign => 1 as f32, + BlockKind::WarpedSign => 1 as f32, + BlockKind::CrimsonWallSign => 1 as f32, + BlockKind::WarpedWallSign => 1 as f32, + BlockKind::StructureBlock => 0 as f32, + BlockKind::Jigsaw => 0 as f32, + BlockKind::Composter => 0.6 as f32, + BlockKind::Target => 0.5 as f32, + BlockKind::BeeNest => 0.3 as f32, + BlockKind::Beehive => 0.6 as f32, + BlockKind::HoneyBlock => 0 as f32, + BlockKind::HoneycombBlock => 0.6 as f32, + BlockKind::NetheriteBlock => 50 as f32, + BlockKind::AncientDebris => 30 as f32, + BlockKind::CryingObsidian => 50 as f32, + BlockKind::RespawnAnchor => 50 as f32, + BlockKind::PottedCrimsonFungus => 0 as f32, + BlockKind::PottedWarpedFungus => 0 as f32, + BlockKind::PottedCrimsonRoots => 0 as f32, + BlockKind::PottedWarpedRoots => 0 as f32, + BlockKind::Lodestone => 3.5 as f32, + BlockKind::Blackstone => 1.5 as f32, + BlockKind::BlackstoneStairs => 0 as f32, + BlockKind::BlackstoneWall => 0 as f32, + BlockKind::BlackstoneSlab => 2 as f32, + BlockKind::PolishedBlackstone => 2 as f32, + BlockKind::PolishedBlackstoneBricks => 1.5 as f32, + BlockKind::CrackedPolishedBlackstoneBricks => 0 as f32, + BlockKind::ChiseledPolishedBlackstone => 1.5 as f32, + BlockKind::PolishedBlackstoneBrickSlab => 2 as f32, + BlockKind::PolishedBlackstoneBrickStairs => 0 as f32, + BlockKind::PolishedBlackstoneBrickWall => 0 as f32, + BlockKind::GildedBlackstone => 0 as f32, + BlockKind::PolishedBlackstoneStairs => 0 as f32, + BlockKind::PolishedBlackstoneSlab => 0 as f32, + BlockKind::PolishedBlackstonePressurePlate => 0.5 as f32, + BlockKind::PolishedBlackstoneButton => 0.5 as f32, + BlockKind::PolishedBlackstoneWall => 0 as f32, + BlockKind::ChiseledNetherBricks => 2 as f32, + BlockKind::CrackedNetherBricks => 2 as f32, + BlockKind::QuartzBricks => 0 as f32, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `diggable` property of this `BlockKind`. + pub fn diggable(&self) -> bool { + match self { + BlockKind::Air => true, + BlockKind::Stone => true, + BlockKind::Granite => true, + BlockKind::PolishedGranite => true, + BlockKind::Diorite => true, + BlockKind::PolishedDiorite => true, + BlockKind::Andesite => true, + BlockKind::PolishedAndesite => true, + BlockKind::GrassBlock => true, + BlockKind::Dirt => true, + BlockKind::CoarseDirt => true, + BlockKind::Podzol => true, + BlockKind::Cobblestone => true, + BlockKind::OakPlanks => true, + BlockKind::SprucePlanks => true, + BlockKind::BirchPlanks => true, + BlockKind::JunglePlanks => true, + BlockKind::AcaciaPlanks => true, + BlockKind::DarkOakPlanks => true, + BlockKind::OakSapling => true, + BlockKind::SpruceSapling => true, + BlockKind::BirchSapling => true, + BlockKind::JungleSapling => true, + BlockKind::AcaciaSapling => true, + BlockKind::DarkOakSapling => true, + BlockKind::Bedrock => false, + BlockKind::Water => false, + BlockKind::Lava => false, + BlockKind::Sand => true, + BlockKind::RedSand => true, + BlockKind::Gravel => true, + BlockKind::GoldOre => true, + BlockKind::IronOre => true, + BlockKind::CoalOre => true, + BlockKind::NetherGoldOre => true, + BlockKind::OakLog => true, + BlockKind::SpruceLog => true, + BlockKind::BirchLog => true, + BlockKind::JungleLog => true, + BlockKind::AcaciaLog => true, + BlockKind::DarkOakLog => true, + BlockKind::StrippedSpruceLog => true, + BlockKind::StrippedBirchLog => true, + BlockKind::StrippedJungleLog => true, + BlockKind::StrippedAcaciaLog => true, + BlockKind::StrippedDarkOakLog => true, + BlockKind::StrippedOakLog => true, + BlockKind::OakWood => true, + BlockKind::SpruceWood => true, + BlockKind::BirchWood => true, + BlockKind::JungleWood => true, + BlockKind::AcaciaWood => true, + BlockKind::DarkOakWood => true, + BlockKind::StrippedOakWood => true, + BlockKind::StrippedSpruceWood => true, + BlockKind::StrippedBirchWood => true, + BlockKind::StrippedJungleWood => true, + BlockKind::StrippedAcaciaWood => true, + BlockKind::StrippedDarkOakWood => true, + BlockKind::OakLeaves => true, + BlockKind::SpruceLeaves => true, + BlockKind::BirchLeaves => true, + BlockKind::JungleLeaves => true, + BlockKind::AcaciaLeaves => true, + BlockKind::DarkOakLeaves => true, + BlockKind::Sponge => true, + BlockKind::WetSponge => true, + BlockKind::Glass => true, + BlockKind::LapisOre => true, + BlockKind::LapisBlock => true, + BlockKind::Dispenser => true, + BlockKind::Sandstone => true, + BlockKind::ChiseledSandstone => true, + BlockKind::CutSandstone => true, + BlockKind::NoteBlock => true, + BlockKind::WhiteBed => true, + BlockKind::OrangeBed => true, + BlockKind::MagentaBed => true, + BlockKind::LightBlueBed => true, + BlockKind::YellowBed => true, + BlockKind::LimeBed => true, + BlockKind::PinkBed => true, + BlockKind::GrayBed => true, + BlockKind::LightGrayBed => true, + BlockKind::CyanBed => true, + BlockKind::PurpleBed => true, + BlockKind::BlueBed => true, + BlockKind::BrownBed => true, + BlockKind::GreenBed => true, + BlockKind::RedBed => true, + BlockKind::BlackBed => true, + BlockKind::PoweredRail => true, + BlockKind::DetectorRail => true, + BlockKind::StickyPiston => true, + BlockKind::Cobweb => true, + BlockKind::Grass => true, + BlockKind::Fern => true, + BlockKind::DeadBush => true, + BlockKind::Seagrass => true, + BlockKind::TallSeagrass => true, + BlockKind::Piston => true, + BlockKind::PistonHead => true, + BlockKind::WhiteWool => true, + BlockKind::OrangeWool => true, + BlockKind::MagentaWool => true, + BlockKind::LightBlueWool => true, + BlockKind::YellowWool => true, + BlockKind::LimeWool => true, + BlockKind::PinkWool => true, + BlockKind::GrayWool => true, + BlockKind::LightGrayWool => true, + BlockKind::CyanWool => true, + BlockKind::PurpleWool => true, + BlockKind::BlueWool => true, + BlockKind::BrownWool => true, + BlockKind::GreenWool => true, + BlockKind::RedWool => true, + BlockKind::BlackWool => true, + BlockKind::MovingPiston => false, + BlockKind::Dandelion => true, + BlockKind::Poppy => true, + BlockKind::BlueOrchid => true, + BlockKind::Allium => true, + BlockKind::AzureBluet => true, + BlockKind::RedTulip => true, + BlockKind::OrangeTulip => true, + BlockKind::WhiteTulip => true, + BlockKind::PinkTulip => true, + BlockKind::OxeyeDaisy => true, + BlockKind::Cornflower => true, + BlockKind::WitherRose => true, + BlockKind::LilyOfTheValley => true, + BlockKind::BrownMushroom => true, + BlockKind::RedMushroom => true, + BlockKind::GoldBlock => true, + BlockKind::IronBlock => true, + BlockKind::Bricks => true, + BlockKind::Tnt => true, + BlockKind::Bookshelf => true, + BlockKind::MossyCobblestone => true, + BlockKind::Obsidian => true, + BlockKind::Torch => true, + BlockKind::WallTorch => true, + BlockKind::Fire => true, + BlockKind::SoulFire => true, + BlockKind::Spawner => true, + BlockKind::OakStairs => true, + BlockKind::Chest => true, + BlockKind::RedstoneWire => true, + BlockKind::DiamondOre => true, + BlockKind::DiamondBlock => true, + BlockKind::CraftingTable => true, + BlockKind::Wheat => true, + BlockKind::Farmland => true, + BlockKind::Furnace => true, + BlockKind::OakSign => true, + BlockKind::SpruceSign => true, + BlockKind::BirchSign => true, + BlockKind::AcaciaSign => true, + BlockKind::JungleSign => true, + BlockKind::DarkOakSign => true, + BlockKind::OakDoor => true, + BlockKind::Ladder => true, + BlockKind::Rail => true, + BlockKind::CobblestoneStairs => true, + BlockKind::OakWallSign => true, + BlockKind::SpruceWallSign => true, + BlockKind::BirchWallSign => true, + BlockKind::AcaciaWallSign => true, + BlockKind::JungleWallSign => true, + BlockKind::DarkOakWallSign => true, + BlockKind::Lever => true, + BlockKind::StonePressurePlate => true, + BlockKind::IronDoor => true, + BlockKind::OakPressurePlate => true, + BlockKind::SprucePressurePlate => true, + BlockKind::BirchPressurePlate => true, + BlockKind::JunglePressurePlate => true, + BlockKind::AcaciaPressurePlate => true, + BlockKind::DarkOakPressurePlate => true, + BlockKind::RedstoneOre => true, + BlockKind::RedstoneTorch => true, + BlockKind::RedstoneWallTorch => true, + BlockKind::StoneButton => true, + BlockKind::Snow => true, + BlockKind::Ice => true, + BlockKind::SnowBlock => true, + BlockKind::Cactus => true, + BlockKind::Clay => true, + BlockKind::SugarCane => true, + BlockKind::Jukebox => true, + BlockKind::OakFence => true, + BlockKind::Pumpkin => true, + BlockKind::Netherrack => true, + BlockKind::SoulSand => true, + BlockKind::SoulSoil => true, + BlockKind::Basalt => true, + BlockKind::PolishedBasalt => true, + BlockKind::SoulTorch => true, + BlockKind::SoulWallTorch => true, + BlockKind::Glowstone => true, + BlockKind::NetherPortal => false, + BlockKind::CarvedPumpkin => true, + BlockKind::JackOLantern => true, + BlockKind::Cake => true, + BlockKind::Repeater => true, + BlockKind::WhiteStainedGlass => true, + BlockKind::OrangeStainedGlass => true, + BlockKind::MagentaStainedGlass => true, + BlockKind::LightBlueStainedGlass => true, + BlockKind::YellowStainedGlass => true, + BlockKind::LimeStainedGlass => true, + BlockKind::PinkStainedGlass => true, + BlockKind::GrayStainedGlass => true, + BlockKind::LightGrayStainedGlass => true, + BlockKind::CyanStainedGlass => true, + BlockKind::PurpleStainedGlass => true, + BlockKind::BlueStainedGlass => true, + BlockKind::BrownStainedGlass => true, + BlockKind::GreenStainedGlass => true, + BlockKind::RedStainedGlass => true, + BlockKind::BlackStainedGlass => true, + BlockKind::OakTrapdoor => true, + BlockKind::SpruceTrapdoor => true, + BlockKind::BirchTrapdoor => true, + BlockKind::JungleTrapdoor => true, + BlockKind::AcaciaTrapdoor => true, + BlockKind::DarkOakTrapdoor => true, + BlockKind::StoneBricks => true, + BlockKind::MossyStoneBricks => true, + BlockKind::CrackedStoneBricks => true, + BlockKind::ChiseledStoneBricks => true, + BlockKind::InfestedStone => true, + BlockKind::InfestedCobblestone => true, + BlockKind::InfestedStoneBricks => true, + BlockKind::InfestedMossyStoneBricks => true, + BlockKind::InfestedCrackedStoneBricks => true, + BlockKind::InfestedChiseledStoneBricks => true, + BlockKind::BrownMushroomBlock => true, + BlockKind::RedMushroomBlock => true, + BlockKind::MushroomStem => true, + BlockKind::IronBars => true, + BlockKind::Chain => true, + BlockKind::GlassPane => true, + BlockKind::Melon => true, + BlockKind::AttachedPumpkinStem => true, + BlockKind::AttachedMelonStem => true, + BlockKind::PumpkinStem => true, + BlockKind::MelonStem => true, + BlockKind::Vine => true, + BlockKind::OakFenceGate => true, + BlockKind::BrickStairs => true, + BlockKind::StoneBrickStairs => true, + BlockKind::Mycelium => true, + BlockKind::LilyPad => true, + BlockKind::NetherBricks => true, + BlockKind::NetherBrickFence => true, + BlockKind::NetherBrickStairs => true, + BlockKind::NetherWart => true, + BlockKind::EnchantingTable => true, + BlockKind::BrewingStand => true, + BlockKind::Cauldron => true, + BlockKind::EndPortal => false, + BlockKind::EndPortalFrame => false, + BlockKind::EndStone => true, + BlockKind::DragonEgg => true, + BlockKind::RedstoneLamp => true, + BlockKind::Cocoa => true, + BlockKind::SandstoneStairs => true, + BlockKind::EmeraldOre => true, + BlockKind::EnderChest => true, + BlockKind::TripwireHook => true, + BlockKind::Tripwire => true, + BlockKind::EmeraldBlock => true, + BlockKind::SpruceStairs => true, + BlockKind::BirchStairs => true, + BlockKind::JungleStairs => true, + BlockKind::CommandBlock => false, + BlockKind::Beacon => true, + BlockKind::CobblestoneWall => true, + BlockKind::MossyCobblestoneWall => true, + BlockKind::FlowerPot => true, + BlockKind::PottedOakSapling => true, + BlockKind::PottedSpruceSapling => true, + BlockKind::PottedBirchSapling => true, + BlockKind::PottedJungleSapling => true, + BlockKind::PottedAcaciaSapling => true, + BlockKind::PottedDarkOakSapling => true, + BlockKind::PottedFern => true, + BlockKind::PottedDandelion => true, + BlockKind::PottedPoppy => true, + BlockKind::PottedBlueOrchid => true, + BlockKind::PottedAllium => true, + BlockKind::PottedAzureBluet => true, + BlockKind::PottedRedTulip => true, + BlockKind::PottedOrangeTulip => true, + BlockKind::PottedWhiteTulip => true, + BlockKind::PottedPinkTulip => true, + BlockKind::PottedOxeyeDaisy => true, + BlockKind::PottedCornflower => true, + BlockKind::PottedLilyOfTheValley => true, + BlockKind::PottedWitherRose => true, + BlockKind::PottedRedMushroom => true, + BlockKind::PottedBrownMushroom => true, + BlockKind::PottedDeadBush => true, + BlockKind::PottedCactus => true, + BlockKind::Carrots => true, + BlockKind::Potatoes => true, + BlockKind::OakButton => true, + BlockKind::SpruceButton => true, + BlockKind::BirchButton => true, + BlockKind::JungleButton => true, + BlockKind::AcaciaButton => true, + BlockKind::DarkOakButton => true, + BlockKind::SkeletonSkull => true, + BlockKind::SkeletonWallSkull => true, + BlockKind::WitherSkeletonSkull => true, + BlockKind::WitherSkeletonWallSkull => true, + BlockKind::ZombieHead => true, + BlockKind::ZombieWallHead => true, + BlockKind::PlayerHead => true, + BlockKind::PlayerWallHead => true, + BlockKind::CreeperHead => true, + BlockKind::CreeperWallHead => true, + BlockKind::DragonHead => true, + BlockKind::DragonWallHead => true, + BlockKind::Anvil => true, + BlockKind::ChippedAnvil => true, + BlockKind::DamagedAnvil => true, + BlockKind::TrappedChest => true, + BlockKind::LightWeightedPressurePlate => true, + BlockKind::HeavyWeightedPressurePlate => true, + BlockKind::Comparator => true, + BlockKind::DaylightDetector => true, + BlockKind::RedstoneBlock => true, + BlockKind::NetherQuartzOre => true, + BlockKind::Hopper => true, + BlockKind::QuartzBlock => true, + BlockKind::ChiseledQuartzBlock => true, + BlockKind::QuartzPillar => true, + BlockKind::QuartzStairs => true, + BlockKind::ActivatorRail => true, + BlockKind::Dropper => true, + BlockKind::WhiteTerracotta => true, + BlockKind::OrangeTerracotta => true, + BlockKind::MagentaTerracotta => true, + BlockKind::LightBlueTerracotta => true, + BlockKind::YellowTerracotta => true, + BlockKind::LimeTerracotta => true, + BlockKind::PinkTerracotta => true, + BlockKind::GrayTerracotta => true, + BlockKind::LightGrayTerracotta => true, + BlockKind::CyanTerracotta => true, + BlockKind::PurpleTerracotta => true, + BlockKind::BlueTerracotta => true, + BlockKind::BrownTerracotta => true, + BlockKind::GreenTerracotta => true, + BlockKind::RedTerracotta => true, + BlockKind::BlackTerracotta => true, + BlockKind::WhiteStainedGlassPane => true, + BlockKind::OrangeStainedGlassPane => true, + BlockKind::MagentaStainedGlassPane => true, + BlockKind::LightBlueStainedGlassPane => true, + BlockKind::YellowStainedGlassPane => true, + BlockKind::LimeStainedGlassPane => true, + BlockKind::PinkStainedGlassPane => true, + BlockKind::GrayStainedGlassPane => true, + BlockKind::LightGrayStainedGlassPane => true, + BlockKind::CyanStainedGlassPane => true, + BlockKind::PurpleStainedGlassPane => true, + BlockKind::BlueStainedGlassPane => true, + BlockKind::BrownStainedGlassPane => true, + BlockKind::GreenStainedGlassPane => true, + BlockKind::RedStainedGlassPane => true, + BlockKind::BlackStainedGlassPane => true, + BlockKind::AcaciaStairs => true, + BlockKind::DarkOakStairs => true, + BlockKind::SlimeBlock => true, + BlockKind::Barrier => false, + BlockKind::IronTrapdoor => true, + BlockKind::Prismarine => true, + BlockKind::PrismarineBricks => true, + BlockKind::DarkPrismarine => true, + BlockKind::PrismarineStairs => true, + BlockKind::PrismarineBrickStairs => true, + BlockKind::DarkPrismarineStairs => true, + BlockKind::PrismarineSlab => true, + BlockKind::PrismarineBrickSlab => true, + BlockKind::DarkPrismarineSlab => true, + BlockKind::SeaLantern => true, + BlockKind::HayBlock => true, + BlockKind::WhiteCarpet => true, + BlockKind::OrangeCarpet => true, + BlockKind::MagentaCarpet => true, + BlockKind::LightBlueCarpet => true, + BlockKind::YellowCarpet => true, + BlockKind::LimeCarpet => true, + BlockKind::PinkCarpet => true, + BlockKind::GrayCarpet => true, + BlockKind::LightGrayCarpet => true, + BlockKind::CyanCarpet => true, + BlockKind::PurpleCarpet => true, + BlockKind::BlueCarpet => true, + BlockKind::BrownCarpet => true, + BlockKind::GreenCarpet => true, + BlockKind::RedCarpet => true, + BlockKind::BlackCarpet => true, + BlockKind::Terracotta => true, + BlockKind::CoalBlock => true, + BlockKind::PackedIce => true, + BlockKind::Sunflower => true, + BlockKind::Lilac => true, + BlockKind::RoseBush => true, + BlockKind::Peony => true, + BlockKind::TallGrass => true, + BlockKind::LargeFern => true, + BlockKind::WhiteBanner => true, + BlockKind::OrangeBanner => true, + BlockKind::MagentaBanner => true, + BlockKind::LightBlueBanner => true, + BlockKind::YellowBanner => true, + BlockKind::LimeBanner => true, + BlockKind::PinkBanner => true, + BlockKind::GrayBanner => true, + BlockKind::LightGrayBanner => true, + BlockKind::CyanBanner => true, + BlockKind::PurpleBanner => true, + BlockKind::BlueBanner => true, + BlockKind::BrownBanner => true, + BlockKind::GreenBanner => true, + BlockKind::RedBanner => true, + BlockKind::BlackBanner => true, + BlockKind::WhiteWallBanner => true, + BlockKind::OrangeWallBanner => true, + BlockKind::MagentaWallBanner => true, + BlockKind::LightBlueWallBanner => true, + BlockKind::YellowWallBanner => true, + BlockKind::LimeWallBanner => true, + BlockKind::PinkWallBanner => true, + BlockKind::GrayWallBanner => true, + BlockKind::LightGrayWallBanner => true, + BlockKind::CyanWallBanner => true, + BlockKind::PurpleWallBanner => true, + BlockKind::BlueWallBanner => true, + BlockKind::BrownWallBanner => true, + BlockKind::GreenWallBanner => true, + BlockKind::RedWallBanner => true, + BlockKind::BlackWallBanner => true, + BlockKind::RedSandstone => true, + BlockKind::ChiseledRedSandstone => true, + BlockKind::CutRedSandstone => true, + BlockKind::RedSandstoneStairs => true, + BlockKind::OakSlab => true, + BlockKind::SpruceSlab => true, + BlockKind::BirchSlab => true, + BlockKind::JungleSlab => true, + BlockKind::AcaciaSlab => true, + BlockKind::DarkOakSlab => true, + BlockKind::StoneSlab => true, + BlockKind::SmoothStoneSlab => true, + BlockKind::SandstoneSlab => true, + BlockKind::CutSandstoneSlab => true, + BlockKind::PetrifiedOakSlab => true, + BlockKind::CobblestoneSlab => true, + BlockKind::BrickSlab => true, + BlockKind::StoneBrickSlab => true, + BlockKind::NetherBrickSlab => true, + BlockKind::QuartzSlab => true, + BlockKind::RedSandstoneSlab => true, + BlockKind::CutRedSandstoneSlab => true, + BlockKind::PurpurSlab => true, + BlockKind::SmoothStone => true, + BlockKind::SmoothSandstone => true, + BlockKind::SmoothQuartz => true, + BlockKind::SmoothRedSandstone => true, + BlockKind::SpruceFenceGate => true, + BlockKind::BirchFenceGate => true, + BlockKind::JungleFenceGate => true, + BlockKind::AcaciaFenceGate => true, + BlockKind::DarkOakFenceGate => true, + BlockKind::SpruceFence => true, + BlockKind::BirchFence => true, + BlockKind::JungleFence => true, + BlockKind::AcaciaFence => true, + BlockKind::DarkOakFence => true, + BlockKind::SpruceDoor => true, + BlockKind::BirchDoor => true, + BlockKind::JungleDoor => true, + BlockKind::AcaciaDoor => true, + BlockKind::DarkOakDoor => true, + BlockKind::EndRod => true, + BlockKind::ChorusPlant => true, + BlockKind::ChorusFlower => true, + BlockKind::PurpurBlock => true, + BlockKind::PurpurPillar => true, + BlockKind::PurpurStairs => true, + BlockKind::EndStoneBricks => true, + BlockKind::Beetroots => true, + BlockKind::GrassPath => true, + BlockKind::EndGateway => false, + BlockKind::RepeatingCommandBlock => false, + BlockKind::ChainCommandBlock => false, + BlockKind::FrostedIce => true, + BlockKind::MagmaBlock => true, + BlockKind::NetherWartBlock => true, + BlockKind::RedNetherBricks => true, + BlockKind::BoneBlock => true, + BlockKind::StructureVoid => true, + BlockKind::Observer => true, + BlockKind::ShulkerBox => true, + BlockKind::WhiteShulkerBox => true, + BlockKind::OrangeShulkerBox => true, + BlockKind::MagentaShulkerBox => true, + BlockKind::LightBlueShulkerBox => true, + BlockKind::YellowShulkerBox => true, + BlockKind::LimeShulkerBox => true, + BlockKind::PinkShulkerBox => true, + BlockKind::GrayShulkerBox => true, + BlockKind::LightGrayShulkerBox => true, + BlockKind::CyanShulkerBox => true, + BlockKind::PurpleShulkerBox => true, + BlockKind::BlueShulkerBox => true, + BlockKind::BrownShulkerBox => true, + BlockKind::GreenShulkerBox => true, + BlockKind::RedShulkerBox => true, + BlockKind::BlackShulkerBox => true, + BlockKind::WhiteGlazedTerracotta => true, + BlockKind::OrangeGlazedTerracotta => true, + BlockKind::MagentaGlazedTerracotta => true, + BlockKind::LightBlueGlazedTerracotta => true, + BlockKind::YellowGlazedTerracotta => true, + BlockKind::LimeGlazedTerracotta => true, + BlockKind::PinkGlazedTerracotta => true, + BlockKind::GrayGlazedTerracotta => true, + BlockKind::LightGrayGlazedTerracotta => true, + BlockKind::CyanGlazedTerracotta => true, + BlockKind::PurpleGlazedTerracotta => true, + BlockKind::BlueGlazedTerracotta => true, + BlockKind::BrownGlazedTerracotta => true, + BlockKind::GreenGlazedTerracotta => true, + BlockKind::RedGlazedTerracotta => true, + BlockKind::BlackGlazedTerracotta => true, + BlockKind::WhiteConcrete => true, + BlockKind::OrangeConcrete => true, + BlockKind::MagentaConcrete => true, + BlockKind::LightBlueConcrete => true, + BlockKind::YellowConcrete => true, + BlockKind::LimeConcrete => true, + BlockKind::PinkConcrete => true, + BlockKind::GrayConcrete => true, + BlockKind::LightGrayConcrete => true, + BlockKind::CyanConcrete => true, + BlockKind::PurpleConcrete => true, + BlockKind::BlueConcrete => true, + BlockKind::BrownConcrete => true, + BlockKind::GreenConcrete => true, + BlockKind::RedConcrete => true, + BlockKind::BlackConcrete => true, + BlockKind::WhiteConcretePowder => true, + BlockKind::OrangeConcretePowder => true, + BlockKind::MagentaConcretePowder => true, + BlockKind::LightBlueConcretePowder => true, + BlockKind::YellowConcretePowder => true, + BlockKind::LimeConcretePowder => true, + BlockKind::PinkConcretePowder => true, + BlockKind::GrayConcretePowder => true, + BlockKind::LightGrayConcretePowder => true, + BlockKind::CyanConcretePowder => true, + BlockKind::PurpleConcretePowder => true, + BlockKind::BlueConcretePowder => true, + BlockKind::BrownConcretePowder => true, + BlockKind::GreenConcretePowder => true, + BlockKind::RedConcretePowder => true, + BlockKind::BlackConcretePowder => true, + BlockKind::Kelp => true, + BlockKind::KelpPlant => true, + BlockKind::DriedKelpBlock => true, + BlockKind::TurtleEgg => true, + BlockKind::DeadTubeCoralBlock => true, + BlockKind::DeadBrainCoralBlock => true, + BlockKind::DeadBubbleCoralBlock => true, + BlockKind::DeadFireCoralBlock => true, + BlockKind::DeadHornCoralBlock => true, + BlockKind::TubeCoralBlock => true, + BlockKind::BrainCoralBlock => true, + BlockKind::BubbleCoralBlock => true, + BlockKind::FireCoralBlock => true, + BlockKind::HornCoralBlock => true, + BlockKind::DeadTubeCoral => true, + BlockKind::DeadBrainCoral => true, + BlockKind::DeadBubbleCoral => true, + BlockKind::DeadFireCoral => true, + BlockKind::DeadHornCoral => true, + BlockKind::TubeCoral => true, + BlockKind::BrainCoral => true, + BlockKind::BubbleCoral => true, + BlockKind::FireCoral => true, + BlockKind::HornCoral => true, + BlockKind::DeadTubeCoralFan => true, + BlockKind::DeadBrainCoralFan => true, + BlockKind::DeadBubbleCoralFan => true, + BlockKind::DeadFireCoralFan => true, + BlockKind::DeadHornCoralFan => true, + BlockKind::TubeCoralFan => true, + BlockKind::BrainCoralFan => true, + BlockKind::BubbleCoralFan => true, + BlockKind::FireCoralFan => true, + BlockKind::HornCoralFan => true, + BlockKind::DeadTubeCoralWallFan => true, + BlockKind::DeadBrainCoralWallFan => true, + BlockKind::DeadBubbleCoralWallFan => true, + BlockKind::DeadFireCoralWallFan => true, + BlockKind::DeadHornCoralWallFan => true, + BlockKind::TubeCoralWallFan => true, + BlockKind::BrainCoralWallFan => true, + BlockKind::BubbleCoralWallFan => true, + BlockKind::FireCoralWallFan => true, + BlockKind::HornCoralWallFan => true, + BlockKind::SeaPickle => true, + BlockKind::BlueIce => true, + BlockKind::Conduit => true, + BlockKind::BambooSapling => true, + BlockKind::Bamboo => true, + BlockKind::PottedBamboo => true, + BlockKind::VoidAir => true, + BlockKind::CaveAir => true, + BlockKind::BubbleColumn => true, + BlockKind::PolishedGraniteStairs => true, + BlockKind::SmoothRedSandstoneStairs => true, + BlockKind::MossyStoneBrickStairs => true, + BlockKind::PolishedDioriteStairs => true, + BlockKind::MossyCobblestoneStairs => true, + BlockKind::EndStoneBrickStairs => true, + BlockKind::StoneStairs => true, + BlockKind::SmoothSandstoneStairs => true, + BlockKind::SmoothQuartzStairs => true, + BlockKind::GraniteStairs => true, + BlockKind::AndesiteStairs => true, + BlockKind::RedNetherBrickStairs => true, + BlockKind::PolishedAndesiteStairs => true, + BlockKind::DioriteStairs => true, + BlockKind::PolishedGraniteSlab => true, + BlockKind::SmoothRedSandstoneSlab => true, + BlockKind::MossyStoneBrickSlab => true, + BlockKind::PolishedDioriteSlab => true, + BlockKind::MossyCobblestoneSlab => true, + BlockKind::EndStoneBrickSlab => true, + BlockKind::SmoothSandstoneSlab => true, + BlockKind::SmoothQuartzSlab => true, + BlockKind::GraniteSlab => true, + BlockKind::AndesiteSlab => true, + BlockKind::RedNetherBrickSlab => true, + BlockKind::PolishedAndesiteSlab => true, + BlockKind::DioriteSlab => true, + BlockKind::BrickWall => true, + BlockKind::PrismarineWall => true, + BlockKind::RedSandstoneWall => true, + BlockKind::MossyStoneBrickWall => true, + BlockKind::GraniteWall => true, + BlockKind::StoneBrickWall => true, + BlockKind::NetherBrickWall => true, + BlockKind::AndesiteWall => true, + BlockKind::RedNetherBrickWall => true, + BlockKind::SandstoneWall => true, + BlockKind::EndStoneBrickWall => true, + BlockKind::DioriteWall => true, + BlockKind::Scaffolding => true, + BlockKind::Loom => true, + BlockKind::Barrel => true, + BlockKind::Smoker => true, + BlockKind::BlastFurnace => true, + BlockKind::CartographyTable => true, + BlockKind::FletchingTable => true, + BlockKind::Grindstone => true, + BlockKind::Lectern => true, + BlockKind::SmithingTable => true, + BlockKind::Stonecutter => true, + BlockKind::Bell => true, + BlockKind::Lantern => true, + BlockKind::SoulLantern => true, + BlockKind::Campfire => true, + BlockKind::SoulCampfire => true, + BlockKind::SweetBerryBush => true, + BlockKind::WarpedStem => true, + BlockKind::StrippedWarpedStem => true, + BlockKind::WarpedHyphae => true, + BlockKind::StrippedWarpedHyphae => true, + BlockKind::WarpedNylium => true, + BlockKind::WarpedFungus => true, + BlockKind::WarpedWartBlock => true, + BlockKind::WarpedRoots => true, + BlockKind::NetherSprouts => true, + BlockKind::CrimsonStem => true, + BlockKind::StrippedCrimsonStem => true, + BlockKind::CrimsonHyphae => true, + BlockKind::StrippedCrimsonHyphae => true, + BlockKind::CrimsonNylium => true, + BlockKind::CrimsonFungus => true, + BlockKind::Shroomlight => true, + BlockKind::WeepingVines => true, + BlockKind::WeepingVinesPlant => true, + BlockKind::TwistingVines => true, + BlockKind::TwistingVinesPlant => true, + BlockKind::CrimsonRoots => true, + BlockKind::CrimsonPlanks => true, + BlockKind::WarpedPlanks => true, + BlockKind::CrimsonSlab => true, + BlockKind::WarpedSlab => true, + BlockKind::CrimsonPressurePlate => true, + BlockKind::WarpedPressurePlate => true, + BlockKind::CrimsonFence => true, + BlockKind::WarpedFence => true, + BlockKind::CrimsonTrapdoor => true, + BlockKind::WarpedTrapdoor => true, + BlockKind::CrimsonFenceGate => true, + BlockKind::WarpedFenceGate => true, + BlockKind::CrimsonStairs => true, + BlockKind::WarpedStairs => true, + BlockKind::CrimsonButton => true, + BlockKind::WarpedButton => true, + BlockKind::CrimsonDoor => true, + BlockKind::WarpedDoor => true, + BlockKind::CrimsonSign => true, + BlockKind::WarpedSign => true, + BlockKind::CrimsonWallSign => true, + BlockKind::WarpedWallSign => true, + BlockKind::StructureBlock => false, + BlockKind::Jigsaw => false, + BlockKind::Composter => true, + BlockKind::Target => true, + BlockKind::BeeNest => true, + BlockKind::Beehive => true, + BlockKind::HoneyBlock => true, + BlockKind::HoneycombBlock => true, + BlockKind::NetheriteBlock => true, + BlockKind::AncientDebris => true, + BlockKind::CryingObsidian => true, + BlockKind::RespawnAnchor => true, + BlockKind::PottedCrimsonFungus => true, + BlockKind::PottedWarpedFungus => true, + BlockKind::PottedCrimsonRoots => true, + BlockKind::PottedWarpedRoots => true, + BlockKind::Lodestone => true, + BlockKind::Blackstone => true, + BlockKind::BlackstoneStairs => true, + BlockKind::BlackstoneWall => true, + BlockKind::BlackstoneSlab => true, + BlockKind::PolishedBlackstone => true, + BlockKind::PolishedBlackstoneBricks => true, + BlockKind::CrackedPolishedBlackstoneBricks => true, + BlockKind::ChiseledPolishedBlackstone => true, + BlockKind::PolishedBlackstoneBrickSlab => true, + BlockKind::PolishedBlackstoneBrickStairs => true, + BlockKind::PolishedBlackstoneBrickWall => true, + BlockKind::GildedBlackstone => true, + BlockKind::PolishedBlackstoneStairs => true, + BlockKind::PolishedBlackstoneSlab => true, + BlockKind::PolishedBlackstonePressurePlate => true, + BlockKind::PolishedBlackstoneButton => true, + BlockKind::PolishedBlackstoneWall => true, + BlockKind::ChiseledNetherBricks => true, + BlockKind::CrackedNetherBricks => true, + BlockKind::QuartzBricks => true, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `transparent` property of this `BlockKind`. + pub fn transparent(&self) -> bool { + match self { + BlockKind::Air => true, + BlockKind::Stone => false, + BlockKind::Granite => false, + BlockKind::PolishedGranite => false, + BlockKind::Diorite => false, + BlockKind::PolishedDiorite => false, + BlockKind::Andesite => false, + BlockKind::PolishedAndesite => false, + BlockKind::GrassBlock => false, + BlockKind::Dirt => false, + BlockKind::CoarseDirt => false, + BlockKind::Podzol => false, + BlockKind::Cobblestone => false, + BlockKind::OakPlanks => false, + BlockKind::SprucePlanks => false, + BlockKind::BirchPlanks => false, + BlockKind::JunglePlanks => false, + BlockKind::AcaciaPlanks => false, + BlockKind::DarkOakPlanks => false, + BlockKind::OakSapling => true, + BlockKind::SpruceSapling => true, + BlockKind::BirchSapling => true, + BlockKind::JungleSapling => true, + BlockKind::AcaciaSapling => true, + BlockKind::DarkOakSapling => true, + BlockKind::Bedrock => false, + BlockKind::Water => true, + BlockKind::Lava => true, + BlockKind::Sand => false, + BlockKind::RedSand => false, + BlockKind::Gravel => false, + BlockKind::GoldOre => false, + BlockKind::IronOre => false, + BlockKind::CoalOre => false, + BlockKind::NetherGoldOre => false, + BlockKind::OakLog => false, + BlockKind::SpruceLog => false, + BlockKind::BirchLog => false, + BlockKind::JungleLog => false, + BlockKind::AcaciaLog => false, + BlockKind::DarkOakLog => false, + BlockKind::StrippedSpruceLog => false, + BlockKind::StrippedBirchLog => false, + BlockKind::StrippedJungleLog => false, + BlockKind::StrippedAcaciaLog => false, + BlockKind::StrippedDarkOakLog => false, + BlockKind::StrippedOakLog => false, + BlockKind::OakWood => false, + BlockKind::SpruceWood => false, + BlockKind::BirchWood => false, + BlockKind::JungleWood => false, + BlockKind::AcaciaWood => false, + BlockKind::DarkOakWood => false, + BlockKind::StrippedOakWood => false, + BlockKind::StrippedSpruceWood => false, + BlockKind::StrippedBirchWood => false, + BlockKind::StrippedJungleWood => false, + BlockKind::StrippedAcaciaWood => false, + BlockKind::StrippedDarkOakWood => false, + BlockKind::OakLeaves => true, + BlockKind::SpruceLeaves => true, + BlockKind::BirchLeaves => true, + BlockKind::JungleLeaves => true, + BlockKind::AcaciaLeaves => true, + BlockKind::DarkOakLeaves => true, + BlockKind::Sponge => false, + BlockKind::WetSponge => false, + BlockKind::Glass => true, + BlockKind::LapisOre => false, + BlockKind::LapisBlock => false, + BlockKind::Dispenser => false, + BlockKind::Sandstone => false, + BlockKind::ChiseledSandstone => false, + BlockKind::CutSandstone => false, + BlockKind::NoteBlock => false, + BlockKind::WhiteBed => true, + BlockKind::OrangeBed => true, + BlockKind::MagentaBed => true, + BlockKind::LightBlueBed => true, + BlockKind::YellowBed => true, + BlockKind::LimeBed => true, + BlockKind::PinkBed => true, + BlockKind::GrayBed => true, + BlockKind::LightGrayBed => true, + BlockKind::CyanBed => true, + BlockKind::PurpleBed => true, + BlockKind::BlueBed => true, + BlockKind::BrownBed => true, + BlockKind::GreenBed => true, + BlockKind::RedBed => true, + BlockKind::BlackBed => true, + BlockKind::PoweredRail => true, + BlockKind::DetectorRail => true, + BlockKind::StickyPiston => true, + BlockKind::Cobweb => true, + BlockKind::Grass => false, + BlockKind::Fern => true, + BlockKind::DeadBush => true, + BlockKind::Seagrass => true, + BlockKind::TallSeagrass => true, + BlockKind::Piston => true, + BlockKind::PistonHead => true, + BlockKind::WhiteWool => false, + BlockKind::OrangeWool => false, + BlockKind::MagentaWool => false, + BlockKind::LightBlueWool => false, + BlockKind::YellowWool => false, + BlockKind::LimeWool => false, + BlockKind::PinkWool => false, + BlockKind::GrayWool => false, + BlockKind::LightGrayWool => false, + BlockKind::CyanWool => false, + BlockKind::PurpleWool => false, + BlockKind::BlueWool => false, + BlockKind::BrownWool => false, + BlockKind::GreenWool => false, + BlockKind::RedWool => false, + BlockKind::BlackWool => false, + BlockKind::MovingPiston => true, + BlockKind::Dandelion => false, + BlockKind::Poppy => false, + BlockKind::BlueOrchid => true, + BlockKind::Allium => false, + BlockKind::AzureBluet => false, + BlockKind::RedTulip => true, + BlockKind::OrangeTulip => true, + BlockKind::WhiteTulip => true, + BlockKind::PinkTulip => true, + BlockKind::OxeyeDaisy => false, + BlockKind::Cornflower => true, + BlockKind::WitherRose => true, + BlockKind::LilyOfTheValley => true, + BlockKind::BrownMushroom => false, + BlockKind::RedMushroom => false, + BlockKind::GoldBlock => false, + BlockKind::IronBlock => false, + BlockKind::Bricks => false, + BlockKind::Tnt => true, + BlockKind::Bookshelf => false, + BlockKind::MossyCobblestone => false, + BlockKind::Obsidian => false, + BlockKind::Torch => true, + BlockKind::WallTorch => true, + BlockKind::Fire => true, + BlockKind::SoulFire => true, + BlockKind::Spawner => true, + BlockKind::OakStairs => true, + BlockKind::Chest => true, + BlockKind::RedstoneWire => true, + BlockKind::DiamondOre => false, + BlockKind::DiamondBlock => false, + BlockKind::CraftingTable => false, + BlockKind::Wheat => true, + BlockKind::Farmland => true, + BlockKind::Furnace => true, + BlockKind::OakSign => true, + BlockKind::SpruceSign => true, + BlockKind::BirchSign => true, + BlockKind::AcaciaSign => true, + BlockKind::JungleSign => true, + BlockKind::DarkOakSign => true, + BlockKind::OakDoor => true, + BlockKind::Ladder => true, + BlockKind::Rail => true, + BlockKind::CobblestoneStairs => true, + BlockKind::OakWallSign => true, + BlockKind::SpruceWallSign => true, + BlockKind::BirchWallSign => true, + BlockKind::AcaciaWallSign => true, + BlockKind::JungleWallSign => true, + BlockKind::DarkOakWallSign => true, + BlockKind::Lever => true, + BlockKind::StonePressurePlate => true, + BlockKind::IronDoor => true, + BlockKind::OakPressurePlate => true, + BlockKind::SprucePressurePlate => true, + BlockKind::BirchPressurePlate => true, + BlockKind::JunglePressurePlate => true, + BlockKind::AcaciaPressurePlate => true, + BlockKind::DarkOakPressurePlate => true, + BlockKind::RedstoneOre => true, + BlockKind::RedstoneTorch => true, + BlockKind::RedstoneWallTorch => true, + BlockKind::StoneButton => true, + BlockKind::Snow => false, + BlockKind::Ice => true, + BlockKind::SnowBlock => false, + BlockKind::Cactus => true, + BlockKind::Clay => false, + BlockKind::SugarCane => true, + BlockKind::Jukebox => false, + BlockKind::OakFence => true, + BlockKind::Pumpkin => true, + BlockKind::Netherrack => false, + BlockKind::SoulSand => false, + BlockKind::SoulSoil => false, + BlockKind::Basalt => false, + BlockKind::PolishedBasalt => false, + BlockKind::SoulTorch => true, + BlockKind::SoulWallTorch => true, + BlockKind::Glowstone => true, + BlockKind::NetherPortal => true, + BlockKind::CarvedPumpkin => true, + BlockKind::JackOLantern => true, + BlockKind::Cake => true, + BlockKind::Repeater => true, + BlockKind::WhiteStainedGlass => true, + BlockKind::OrangeStainedGlass => true, + BlockKind::MagentaStainedGlass => true, + BlockKind::LightBlueStainedGlass => true, + BlockKind::YellowStainedGlass => true, + BlockKind::LimeStainedGlass => true, + BlockKind::PinkStainedGlass => true, + BlockKind::GrayStainedGlass => true, + BlockKind::LightGrayStainedGlass => true, + BlockKind::CyanStainedGlass => true, + BlockKind::PurpleStainedGlass => true, + BlockKind::BlueStainedGlass => true, + BlockKind::BrownStainedGlass => true, + BlockKind::GreenStainedGlass => true, + BlockKind::RedStainedGlass => true, + BlockKind::BlackStainedGlass => true, + BlockKind::OakTrapdoor => true, + BlockKind::SpruceTrapdoor => true, + BlockKind::BirchTrapdoor => true, + BlockKind::JungleTrapdoor => true, + BlockKind::AcaciaTrapdoor => true, + BlockKind::DarkOakTrapdoor => true, + BlockKind::StoneBricks => false, + BlockKind::MossyStoneBricks => false, + BlockKind::CrackedStoneBricks => false, + BlockKind::ChiseledStoneBricks => false, + BlockKind::InfestedStone => false, + BlockKind::InfestedCobblestone => false, + BlockKind::InfestedStoneBricks => false, + BlockKind::InfestedMossyStoneBricks => false, + BlockKind::InfestedCrackedStoneBricks => false, + BlockKind::InfestedChiseledStoneBricks => false, + BlockKind::BrownMushroomBlock => false, + BlockKind::RedMushroomBlock => false, + BlockKind::MushroomStem => false, + BlockKind::IronBars => true, + BlockKind::Chain => true, + BlockKind::GlassPane => true, + BlockKind::Melon => true, + BlockKind::AttachedPumpkinStem => true, + BlockKind::AttachedMelonStem => true, + BlockKind::PumpkinStem => true, + BlockKind::MelonStem => true, + BlockKind::Vine => true, + BlockKind::OakFenceGate => true, + BlockKind::BrickStairs => true, + BlockKind::StoneBrickStairs => true, + BlockKind::Mycelium => false, + BlockKind::LilyPad => true, + BlockKind::NetherBricks => false, + BlockKind::NetherBrickFence => true, + BlockKind::NetherBrickStairs => true, + BlockKind::NetherWart => true, + BlockKind::EnchantingTable => true, + BlockKind::BrewingStand => true, + BlockKind::Cauldron => true, + BlockKind::EndPortal => true, + BlockKind::EndPortalFrame => true, + BlockKind::EndStone => false, + BlockKind::DragonEgg => true, + BlockKind::RedstoneLamp => true, + BlockKind::Cocoa => true, + BlockKind::SandstoneStairs => true, + BlockKind::EmeraldOre => false, + BlockKind::EnderChest => true, + BlockKind::TripwireHook => true, + BlockKind::Tripwire => true, + BlockKind::EmeraldBlock => false, + BlockKind::SpruceStairs => true, + BlockKind::BirchStairs => true, + BlockKind::JungleStairs => true, + BlockKind::CommandBlock => false, + BlockKind::Beacon => true, + BlockKind::CobblestoneWall => true, + BlockKind::MossyCobblestoneWall => true, + BlockKind::FlowerPot => true, + BlockKind::PottedOakSapling => true, + BlockKind::PottedSpruceSapling => true, + BlockKind::PottedBirchSapling => true, + BlockKind::PottedJungleSapling => true, + BlockKind::PottedAcaciaSapling => true, + BlockKind::PottedDarkOakSapling => true, + BlockKind::PottedFern => true, + BlockKind::PottedDandelion => true, + BlockKind::PottedPoppy => true, + BlockKind::PottedBlueOrchid => true, + BlockKind::PottedAllium => true, + BlockKind::PottedAzureBluet => true, + BlockKind::PottedRedTulip => true, + BlockKind::PottedOrangeTulip => true, + BlockKind::PottedWhiteTulip => true, + BlockKind::PottedPinkTulip => true, + BlockKind::PottedOxeyeDaisy => true, + BlockKind::PottedCornflower => true, + BlockKind::PottedLilyOfTheValley => true, + BlockKind::PottedWitherRose => true, + BlockKind::PottedRedMushroom => true, + BlockKind::PottedBrownMushroom => true, + BlockKind::PottedDeadBush => true, + BlockKind::PottedCactus => true, + BlockKind::Carrots => false, + BlockKind::Potatoes => false, + BlockKind::OakButton => true, + BlockKind::SpruceButton => true, + BlockKind::BirchButton => true, + BlockKind::JungleButton => true, + BlockKind::AcaciaButton => true, + BlockKind::DarkOakButton => true, + BlockKind::SkeletonSkull => true, + BlockKind::SkeletonWallSkull => true, + BlockKind::WitherSkeletonSkull => true, + BlockKind::WitherSkeletonWallSkull => true, + BlockKind::ZombieHead => true, + BlockKind::ZombieWallHead => true, + BlockKind::PlayerHead => true, + BlockKind::PlayerWallHead => true, + BlockKind::CreeperHead => true, + BlockKind::CreeperWallHead => true, + BlockKind::DragonHead => true, + BlockKind::DragonWallHead => true, + BlockKind::Anvil => true, + BlockKind::ChippedAnvil => true, + BlockKind::DamagedAnvil => true, + BlockKind::TrappedChest => true, + BlockKind::LightWeightedPressurePlate => true, + BlockKind::HeavyWeightedPressurePlate => true, + BlockKind::Comparator => true, + BlockKind::DaylightDetector => true, + BlockKind::RedstoneBlock => true, + BlockKind::NetherQuartzOre => false, + BlockKind::Hopper => true, + BlockKind::QuartzBlock => false, + BlockKind::ChiseledQuartzBlock => false, + BlockKind::QuartzPillar => false, + BlockKind::QuartzStairs => true, + BlockKind::ActivatorRail => true, + BlockKind::Dropper => false, + BlockKind::WhiteTerracotta => false, + BlockKind::OrangeTerracotta => false, + BlockKind::MagentaTerracotta => false, + BlockKind::LightBlueTerracotta => false, + BlockKind::YellowTerracotta => false, + BlockKind::LimeTerracotta => false, + BlockKind::PinkTerracotta => false, + BlockKind::GrayTerracotta => false, + BlockKind::LightGrayTerracotta => false, + BlockKind::CyanTerracotta => false, + BlockKind::PurpleTerracotta => false, + BlockKind::BlueTerracotta => false, + BlockKind::BrownTerracotta => false, + BlockKind::GreenTerracotta => false, + BlockKind::RedTerracotta => false, + BlockKind::BlackTerracotta => false, + BlockKind::WhiteStainedGlassPane => true, + BlockKind::OrangeStainedGlassPane => true, + BlockKind::MagentaStainedGlassPane => true, + BlockKind::LightBlueStainedGlassPane => true, + BlockKind::YellowStainedGlassPane => true, + BlockKind::LimeStainedGlassPane => true, + BlockKind::PinkStainedGlassPane => true, + BlockKind::GrayStainedGlassPane => true, + BlockKind::LightGrayStainedGlassPane => true, + BlockKind::CyanStainedGlassPane => true, + BlockKind::PurpleStainedGlassPane => true, + BlockKind::BlueStainedGlassPane => true, + BlockKind::BrownStainedGlassPane => true, + BlockKind::GreenStainedGlassPane => true, + BlockKind::RedStainedGlassPane => true, + BlockKind::BlackStainedGlassPane => true, + BlockKind::AcaciaStairs => true, + BlockKind::DarkOakStairs => true, + BlockKind::SlimeBlock => true, + BlockKind::Barrier => true, + BlockKind::IronTrapdoor => true, + BlockKind::Prismarine => false, + BlockKind::PrismarineBricks => false, + BlockKind::DarkPrismarine => false, + BlockKind::PrismarineStairs => true, + BlockKind::PrismarineBrickStairs => true, + BlockKind::DarkPrismarineStairs => true, + BlockKind::PrismarineSlab => true, + BlockKind::PrismarineBrickSlab => true, + BlockKind::DarkPrismarineSlab => true, + BlockKind::SeaLantern => true, + BlockKind::HayBlock => false, + BlockKind::WhiteCarpet => true, + BlockKind::OrangeCarpet => true, + BlockKind::MagentaCarpet => true, + BlockKind::LightBlueCarpet => true, + BlockKind::YellowCarpet => true, + BlockKind::LimeCarpet => true, + BlockKind::PinkCarpet => true, + BlockKind::GrayCarpet => true, + BlockKind::LightGrayCarpet => true, + BlockKind::CyanCarpet => true, + BlockKind::PurpleCarpet => true, + BlockKind::BlueCarpet => true, + BlockKind::BrownCarpet => true, + BlockKind::GreenCarpet => true, + BlockKind::RedCarpet => true, + BlockKind::BlackCarpet => true, + BlockKind::Terracotta => false, + BlockKind::CoalBlock => false, + BlockKind::PackedIce => false, + BlockKind::Sunflower => true, + BlockKind::Lilac => true, + BlockKind::RoseBush => true, + BlockKind::Peony => false, + BlockKind::TallGrass => true, + BlockKind::LargeFern => true, + BlockKind::WhiteBanner => true, + BlockKind::OrangeBanner => true, + BlockKind::MagentaBanner => true, + BlockKind::LightBlueBanner => true, + BlockKind::YellowBanner => true, + BlockKind::LimeBanner => true, + BlockKind::PinkBanner => true, + BlockKind::GrayBanner => true, + BlockKind::LightGrayBanner => true, + BlockKind::CyanBanner => true, + BlockKind::PurpleBanner => true, + BlockKind::BlueBanner => true, + BlockKind::BrownBanner => true, + BlockKind::GreenBanner => true, + BlockKind::RedBanner => true, + BlockKind::BlackBanner => true, + BlockKind::WhiteWallBanner => true, + BlockKind::OrangeWallBanner => true, + BlockKind::MagentaWallBanner => true, + BlockKind::LightBlueWallBanner => true, + BlockKind::YellowWallBanner => true, + BlockKind::LimeWallBanner => true, + BlockKind::PinkWallBanner => true, + BlockKind::GrayWallBanner => true, + BlockKind::LightGrayWallBanner => true, + BlockKind::CyanWallBanner => true, + BlockKind::PurpleWallBanner => true, + BlockKind::BlueWallBanner => true, + BlockKind::BrownWallBanner => true, + BlockKind::GreenWallBanner => true, + BlockKind::RedWallBanner => true, + BlockKind::BlackWallBanner => true, + BlockKind::RedSandstone => false, + BlockKind::ChiseledRedSandstone => false, + BlockKind::CutRedSandstone => false, + BlockKind::RedSandstoneStairs => true, + BlockKind::OakSlab => true, + BlockKind::SpruceSlab => true, + BlockKind::BirchSlab => true, + BlockKind::JungleSlab => true, + BlockKind::AcaciaSlab => true, + BlockKind::DarkOakSlab => true, + BlockKind::StoneSlab => true, + BlockKind::SmoothStoneSlab => true, + BlockKind::SandstoneSlab => true, + BlockKind::CutSandstoneSlab => true, + BlockKind::PetrifiedOakSlab => true, + BlockKind::CobblestoneSlab => true, + BlockKind::BrickSlab => true, + BlockKind::StoneBrickSlab => true, + BlockKind::NetherBrickSlab => true, + BlockKind::QuartzSlab => true, + BlockKind::RedSandstoneSlab => true, + BlockKind::CutRedSandstoneSlab => true, + BlockKind::PurpurSlab => true, + BlockKind::SmoothStone => false, + BlockKind::SmoothSandstone => false, + BlockKind::SmoothQuartz => false, + BlockKind::SmoothRedSandstone => false, + BlockKind::SpruceFenceGate => true, + BlockKind::BirchFenceGate => true, + BlockKind::JungleFenceGate => true, + BlockKind::AcaciaFenceGate => true, + BlockKind::DarkOakFenceGate => true, + BlockKind::SpruceFence => true, + BlockKind::BirchFence => true, + BlockKind::JungleFence => true, + BlockKind::AcaciaFence => true, + BlockKind::DarkOakFence => true, + BlockKind::SpruceDoor => true, + BlockKind::BirchDoor => true, + BlockKind::JungleDoor => true, + BlockKind::AcaciaDoor => true, + BlockKind::DarkOakDoor => true, + BlockKind::EndRod => false, + BlockKind::ChorusPlant => true, + BlockKind::ChorusFlower => true, + BlockKind::PurpurBlock => false, + BlockKind::PurpurPillar => false, + BlockKind::PurpurStairs => true, + BlockKind::EndStoneBricks => false, + BlockKind::Beetroots => true, + BlockKind::GrassPath => true, + BlockKind::EndGateway => false, + BlockKind::RepeatingCommandBlock => false, + BlockKind::ChainCommandBlock => false, + BlockKind::FrostedIce => true, + BlockKind::MagmaBlock => false, + BlockKind::NetherWartBlock => false, + BlockKind::RedNetherBricks => false, + BlockKind::BoneBlock => false, + BlockKind::StructureVoid => false, + BlockKind::Observer => true, + BlockKind::ShulkerBox => true, + BlockKind::WhiteShulkerBox => true, + BlockKind::OrangeShulkerBox => true, + BlockKind::MagentaShulkerBox => true, + BlockKind::LightBlueShulkerBox => true, + BlockKind::YellowShulkerBox => true, + BlockKind::LimeShulkerBox => true, + BlockKind::PinkShulkerBox => true, + BlockKind::GrayShulkerBox => true, + BlockKind::LightGrayShulkerBox => true, + BlockKind::CyanShulkerBox => true, + BlockKind::PurpleShulkerBox => true, + BlockKind::BlueShulkerBox => true, + BlockKind::BrownShulkerBox => true, + BlockKind::GreenShulkerBox => true, + BlockKind::RedShulkerBox => true, + BlockKind::BlackShulkerBox => true, + BlockKind::WhiteGlazedTerracotta => false, + BlockKind::OrangeGlazedTerracotta => false, + BlockKind::MagentaGlazedTerracotta => false, + BlockKind::LightBlueGlazedTerracotta => false, + BlockKind::YellowGlazedTerracotta => false, + BlockKind::LimeGlazedTerracotta => false, + BlockKind::PinkGlazedTerracotta => false, + BlockKind::GrayGlazedTerracotta => false, + BlockKind::LightGrayGlazedTerracotta => false, + BlockKind::CyanGlazedTerracotta => false, + BlockKind::PurpleGlazedTerracotta => false, + BlockKind::BlueGlazedTerracotta => false, + BlockKind::BrownGlazedTerracotta => false, + BlockKind::GreenGlazedTerracotta => false, + BlockKind::RedGlazedTerracotta => false, + BlockKind::BlackGlazedTerracotta => false, + BlockKind::WhiteConcrete => false, + BlockKind::OrangeConcrete => false, + BlockKind::MagentaConcrete => false, + BlockKind::LightBlueConcrete => false, + BlockKind::YellowConcrete => false, + BlockKind::LimeConcrete => false, + BlockKind::PinkConcrete => false, + BlockKind::GrayConcrete => false, + BlockKind::LightGrayConcrete => false, + BlockKind::CyanConcrete => false, + BlockKind::PurpleConcrete => false, + BlockKind::BlueConcrete => false, + BlockKind::BrownConcrete => false, + BlockKind::GreenConcrete => false, + BlockKind::RedConcrete => false, + BlockKind::BlackConcrete => false, + BlockKind::WhiteConcretePowder => false, + BlockKind::OrangeConcretePowder => false, + BlockKind::MagentaConcretePowder => false, + BlockKind::LightBlueConcretePowder => false, + BlockKind::YellowConcretePowder => false, + BlockKind::LimeConcretePowder => false, + BlockKind::PinkConcretePowder => false, + BlockKind::GrayConcretePowder => false, + BlockKind::LightGrayConcretePowder => false, + BlockKind::CyanConcretePowder => false, + BlockKind::PurpleConcretePowder => false, + BlockKind::BlueConcretePowder => false, + BlockKind::BrownConcretePowder => false, + BlockKind::GreenConcretePowder => false, + BlockKind::RedConcretePowder => false, + BlockKind::BlackConcretePowder => false, + BlockKind::Kelp => true, + BlockKind::KelpPlant => true, + BlockKind::DriedKelpBlock => false, + BlockKind::TurtleEgg => false, + BlockKind::DeadTubeCoralBlock => false, + BlockKind::DeadBrainCoralBlock => false, + BlockKind::DeadBubbleCoralBlock => false, + BlockKind::DeadFireCoralBlock => false, + BlockKind::DeadHornCoralBlock => false, + BlockKind::TubeCoralBlock => false, + BlockKind::BrainCoralBlock => false, + BlockKind::BubbleCoralBlock => false, + BlockKind::FireCoralBlock => false, + BlockKind::HornCoralBlock => false, + BlockKind::DeadTubeCoral => true, + BlockKind::DeadBrainCoral => true, + BlockKind::DeadBubbleCoral => true, + BlockKind::DeadFireCoral => true, + BlockKind::DeadHornCoral => true, + BlockKind::TubeCoral => true, + BlockKind::BrainCoral => true, + BlockKind::BubbleCoral => true, + BlockKind::FireCoral => true, + BlockKind::HornCoral => true, + BlockKind::DeadTubeCoralFan => true, + BlockKind::DeadBrainCoralFan => true, + BlockKind::DeadBubbleCoralFan => true, + BlockKind::DeadFireCoralFan => true, + BlockKind::DeadHornCoralFan => true, + BlockKind::TubeCoralFan => true, + BlockKind::BrainCoralFan => true, + BlockKind::BubbleCoralFan => true, + BlockKind::FireCoralFan => true, + BlockKind::HornCoralFan => true, + BlockKind::DeadTubeCoralWallFan => true, + BlockKind::DeadBrainCoralWallFan => true, + BlockKind::DeadBubbleCoralWallFan => true, + BlockKind::DeadFireCoralWallFan => true, + BlockKind::DeadHornCoralWallFan => true, + BlockKind::TubeCoralWallFan => true, + BlockKind::BrainCoralWallFan => true, + BlockKind::BubbleCoralWallFan => true, + BlockKind::FireCoralWallFan => true, + BlockKind::HornCoralWallFan => true, + BlockKind::SeaPickle => false, + BlockKind::BlueIce => false, + BlockKind::Conduit => false, + BlockKind::BambooSapling => false, + BlockKind::Bamboo => false, + BlockKind::PottedBamboo => true, + BlockKind::VoidAir => true, + BlockKind::CaveAir => true, + BlockKind::BubbleColumn => true, + BlockKind::PolishedGraniteStairs => true, + BlockKind::SmoothRedSandstoneStairs => true, + BlockKind::MossyStoneBrickStairs => true, + BlockKind::PolishedDioriteStairs => true, + BlockKind::MossyCobblestoneStairs => true, + BlockKind::EndStoneBrickStairs => true, + BlockKind::StoneStairs => true, + BlockKind::SmoothSandstoneStairs => true, + BlockKind::SmoothQuartzStairs => true, + BlockKind::GraniteStairs => true, + BlockKind::AndesiteStairs => true, + BlockKind::RedNetherBrickStairs => true, + BlockKind::PolishedAndesiteStairs => true, + BlockKind::DioriteStairs => true, + BlockKind::PolishedGraniteSlab => true, + BlockKind::SmoothRedSandstoneSlab => true, + BlockKind::MossyStoneBrickSlab => true, + BlockKind::PolishedDioriteSlab => true, + BlockKind::MossyCobblestoneSlab => true, + BlockKind::EndStoneBrickSlab => true, + BlockKind::SmoothSandstoneSlab => true, + BlockKind::SmoothQuartzSlab => true, + BlockKind::GraniteSlab => true, + BlockKind::AndesiteSlab => true, + BlockKind::RedNetherBrickSlab => true, + BlockKind::PolishedAndesiteSlab => true, + BlockKind::DioriteSlab => true, + BlockKind::BrickWall => true, + BlockKind::PrismarineWall => true, + BlockKind::RedSandstoneWall => true, + BlockKind::MossyStoneBrickWall => true, + BlockKind::GraniteWall => true, + BlockKind::StoneBrickWall => true, + BlockKind::NetherBrickWall => true, + BlockKind::AndesiteWall => true, + BlockKind::RedNetherBrickWall => true, + BlockKind::SandstoneWall => true, + BlockKind::EndStoneBrickWall => true, + BlockKind::DioriteWall => true, + BlockKind::Scaffolding => true, + BlockKind::Loom => false, + BlockKind::Barrel => true, + BlockKind::Smoker => true, + BlockKind::BlastFurnace => true, + BlockKind::CartographyTable => false, + BlockKind::FletchingTable => false, + BlockKind::Grindstone => true, + BlockKind::Lectern => false, + BlockKind::SmithingTable => false, + BlockKind::Stonecutter => false, + BlockKind::Bell => true, + BlockKind::Lantern => true, + BlockKind::SoulLantern => true, + BlockKind::Campfire => false, + BlockKind::SoulCampfire => false, + BlockKind::SweetBerryBush => true, + BlockKind::WarpedStem => false, + BlockKind::StrippedWarpedStem => false, + BlockKind::WarpedHyphae => false, + BlockKind::StrippedWarpedHyphae => false, + BlockKind::WarpedNylium => false, + BlockKind::WarpedFungus => true, + BlockKind::WarpedWartBlock => false, + BlockKind::WarpedRoots => true, + BlockKind::NetherSprouts => true, + BlockKind::CrimsonStem => false, + BlockKind::StrippedCrimsonStem => false, + BlockKind::CrimsonHyphae => false, + BlockKind::StrippedCrimsonHyphae => false, + BlockKind::CrimsonNylium => false, + BlockKind::CrimsonFungus => true, + BlockKind::Shroomlight => false, + BlockKind::WeepingVines => true, + BlockKind::WeepingVinesPlant => true, + BlockKind::TwistingVines => true, + BlockKind::TwistingVinesPlant => true, + BlockKind::CrimsonRoots => true, + BlockKind::CrimsonPlanks => false, + BlockKind::WarpedPlanks => false, + BlockKind::CrimsonSlab => true, + BlockKind::WarpedSlab => true, + BlockKind::CrimsonPressurePlate => true, + BlockKind::WarpedPressurePlate => true, + BlockKind::CrimsonFence => true, + BlockKind::WarpedFence => true, + BlockKind::CrimsonTrapdoor => true, + BlockKind::WarpedTrapdoor => true, + BlockKind::CrimsonFenceGate => true, + BlockKind::WarpedFenceGate => true, + BlockKind::CrimsonStairs => true, + BlockKind::WarpedStairs => true, + BlockKind::CrimsonButton => true, + BlockKind::WarpedButton => true, + BlockKind::CrimsonDoor => true, + BlockKind::WarpedDoor => true, + BlockKind::CrimsonSign => true, + BlockKind::WarpedSign => true, + BlockKind::CrimsonWallSign => true, + BlockKind::WarpedWallSign => true, + BlockKind::StructureBlock => false, + BlockKind::Jigsaw => false, + BlockKind::Composter => true, + BlockKind::Target => true, + BlockKind::BeeNest => false, + BlockKind::Beehive => false, + BlockKind::HoneyBlock => true, + BlockKind::HoneycombBlock => false, + BlockKind::NetheriteBlock => false, + BlockKind::AncientDebris => false, + BlockKind::CryingObsidian => false, + BlockKind::RespawnAnchor => false, + BlockKind::PottedCrimsonFungus => true, + BlockKind::PottedWarpedFungus => true, + BlockKind::PottedCrimsonRoots => true, + BlockKind::PottedWarpedRoots => true, + BlockKind::Lodestone => false, + BlockKind::Blackstone => false, + BlockKind::BlackstoneStairs => true, + BlockKind::BlackstoneWall => true, + BlockKind::BlackstoneSlab => true, + BlockKind::PolishedBlackstone => false, + BlockKind::PolishedBlackstoneBricks => false, + BlockKind::CrackedPolishedBlackstoneBricks => false, + BlockKind::ChiseledPolishedBlackstone => true, + BlockKind::PolishedBlackstoneBrickSlab => true, + BlockKind::PolishedBlackstoneBrickStairs => true, + BlockKind::PolishedBlackstoneBrickWall => true, + BlockKind::GildedBlackstone => false, + BlockKind::PolishedBlackstoneStairs => true, + BlockKind::PolishedBlackstoneSlab => true, + BlockKind::PolishedBlackstonePressurePlate => true, + BlockKind::PolishedBlackstoneButton => true, + BlockKind::PolishedBlackstoneWall => true, + BlockKind::ChiseledNetherBricks => false, + BlockKind::CrackedNetherBricks => false, + BlockKind::QuartzBricks => false, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `light_emission` property of this `BlockKind`. + pub fn light_emission(&self) -> u8 { + match self { + BlockKind::Air => 0, + BlockKind::Stone => 0, + BlockKind::Granite => 0, + BlockKind::PolishedGranite => 0, + BlockKind::Diorite => 0, + BlockKind::PolishedDiorite => 0, + BlockKind::Andesite => 0, + BlockKind::PolishedAndesite => 0, + BlockKind::GrassBlock => 0, + BlockKind::Dirt => 0, + BlockKind::CoarseDirt => 0, + BlockKind::Podzol => 0, + BlockKind::Cobblestone => 0, + BlockKind::OakPlanks => 0, + BlockKind::SprucePlanks => 0, + BlockKind::BirchPlanks => 0, + BlockKind::JunglePlanks => 0, + BlockKind::AcaciaPlanks => 0, + BlockKind::DarkOakPlanks => 0, + BlockKind::OakSapling => 0, + BlockKind::SpruceSapling => 0, + BlockKind::BirchSapling => 0, + BlockKind::JungleSapling => 0, + BlockKind::AcaciaSapling => 0, + BlockKind::DarkOakSapling => 0, + BlockKind::Bedrock => 0, + BlockKind::Water => 0, + BlockKind::Lava => 15, + BlockKind::Sand => 0, + BlockKind::RedSand => 0, + BlockKind::Gravel => 0, + BlockKind::GoldOre => 0, + BlockKind::IronOre => 0, + BlockKind::CoalOre => 0, + BlockKind::NetherGoldOre => 0, + BlockKind::OakLog => 0, + BlockKind::SpruceLog => 0, + BlockKind::BirchLog => 0, + BlockKind::JungleLog => 0, + BlockKind::AcaciaLog => 0, + BlockKind::DarkOakLog => 0, + BlockKind::StrippedSpruceLog => 0, + BlockKind::StrippedBirchLog => 0, + BlockKind::StrippedJungleLog => 0, + BlockKind::StrippedAcaciaLog => 0, + BlockKind::StrippedDarkOakLog => 0, + BlockKind::StrippedOakLog => 0, + BlockKind::OakWood => 0, + BlockKind::SpruceWood => 0, + BlockKind::BirchWood => 0, + BlockKind::JungleWood => 0, + BlockKind::AcaciaWood => 0, + BlockKind::DarkOakWood => 0, + BlockKind::StrippedOakWood => 0, + BlockKind::StrippedSpruceWood => 0, + BlockKind::StrippedBirchWood => 0, + BlockKind::StrippedJungleWood => 0, + BlockKind::StrippedAcaciaWood => 0, + BlockKind::StrippedDarkOakWood => 0, + BlockKind::OakLeaves => 0, + BlockKind::SpruceLeaves => 0, + BlockKind::BirchLeaves => 0, + BlockKind::JungleLeaves => 0, + BlockKind::AcaciaLeaves => 0, + BlockKind::DarkOakLeaves => 0, + BlockKind::Sponge => 0, + BlockKind::WetSponge => 0, + BlockKind::Glass => 0, + BlockKind::LapisOre => 0, + BlockKind::LapisBlock => 0, + BlockKind::Dispenser => 0, + BlockKind::Sandstone => 0, + BlockKind::ChiseledSandstone => 0, + BlockKind::CutSandstone => 0, + BlockKind::NoteBlock => 0, + BlockKind::WhiteBed => 0, + BlockKind::OrangeBed => 0, + BlockKind::MagentaBed => 0, + BlockKind::LightBlueBed => 0, + BlockKind::YellowBed => 0, + BlockKind::LimeBed => 0, + BlockKind::PinkBed => 0, + BlockKind::GrayBed => 0, + BlockKind::LightGrayBed => 0, + BlockKind::CyanBed => 0, + BlockKind::PurpleBed => 0, + BlockKind::BlueBed => 0, + BlockKind::BrownBed => 0, + BlockKind::GreenBed => 0, + BlockKind::RedBed => 0, + BlockKind::BlackBed => 0, + BlockKind::PoweredRail => 0, + BlockKind::DetectorRail => 0, + BlockKind::StickyPiston => 0, + BlockKind::Cobweb => 0, + BlockKind::Grass => 0, + BlockKind::Fern => 0, + BlockKind::DeadBush => 0, + BlockKind::Seagrass => 0, + BlockKind::TallSeagrass => 0, + BlockKind::Piston => 0, + BlockKind::PistonHead => 0, + BlockKind::WhiteWool => 0, + BlockKind::OrangeWool => 0, + BlockKind::MagentaWool => 0, + BlockKind::LightBlueWool => 0, + BlockKind::YellowWool => 0, + BlockKind::LimeWool => 0, + BlockKind::PinkWool => 0, + BlockKind::GrayWool => 0, + BlockKind::LightGrayWool => 0, + BlockKind::CyanWool => 0, + BlockKind::PurpleWool => 0, + BlockKind::BlueWool => 0, + BlockKind::BrownWool => 0, + BlockKind::GreenWool => 0, + BlockKind::RedWool => 0, + BlockKind::BlackWool => 0, + BlockKind::MovingPiston => 0, + BlockKind::Dandelion => 0, + BlockKind::Poppy => 0, + BlockKind::BlueOrchid => 0, + BlockKind::Allium => 0, + BlockKind::AzureBluet => 0, + BlockKind::RedTulip => 0, + BlockKind::OrangeTulip => 0, + BlockKind::WhiteTulip => 0, + BlockKind::PinkTulip => 0, + BlockKind::OxeyeDaisy => 0, + BlockKind::Cornflower => 0, + BlockKind::WitherRose => 0, + BlockKind::LilyOfTheValley => 0, + BlockKind::BrownMushroom => 1, + BlockKind::RedMushroom => 1, + BlockKind::GoldBlock => 0, + BlockKind::IronBlock => 0, + BlockKind::Bricks => 0, + BlockKind::Tnt => 0, + BlockKind::Bookshelf => 0, + BlockKind::MossyCobblestone => 0, + BlockKind::Obsidian => 0, + BlockKind::Torch => 14, + BlockKind::WallTorch => 14, + BlockKind::Fire => 15, + BlockKind::SoulFire => 0, + BlockKind::Spawner => 0, + BlockKind::OakStairs => 0, + BlockKind::Chest => 0, + BlockKind::RedstoneWire => 0, + BlockKind::DiamondOre => 0, + BlockKind::DiamondBlock => 0, + BlockKind::CraftingTable => 0, + BlockKind::Wheat => 0, + BlockKind::Farmland => 0, + BlockKind::Furnace => 13, + BlockKind::OakSign => 0, + BlockKind::SpruceSign => 0, + BlockKind::BirchSign => 0, + BlockKind::AcaciaSign => 0, + BlockKind::JungleSign => 0, + BlockKind::DarkOakSign => 0, + BlockKind::OakDoor => 0, + BlockKind::Ladder => 0, + BlockKind::Rail => 0, + BlockKind::CobblestoneStairs => 0, + BlockKind::OakWallSign => 0, + BlockKind::SpruceWallSign => 0, + BlockKind::BirchWallSign => 0, + BlockKind::AcaciaWallSign => 0, + BlockKind::JungleWallSign => 0, + BlockKind::DarkOakWallSign => 0, + BlockKind::Lever => 0, + BlockKind::StonePressurePlate => 0, + BlockKind::IronDoor => 0, + BlockKind::OakPressurePlate => 0, + BlockKind::SprucePressurePlate => 0, + BlockKind::BirchPressurePlate => 0, + BlockKind::JunglePressurePlate => 0, + BlockKind::AcaciaPressurePlate => 0, + BlockKind::DarkOakPressurePlate => 0, + BlockKind::RedstoneOre => 9, + BlockKind::RedstoneTorch => 7, + BlockKind::RedstoneWallTorch => 7, + BlockKind::StoneButton => 0, + BlockKind::Snow => 0, + BlockKind::Ice => 0, + BlockKind::SnowBlock => 0, + BlockKind::Cactus => 0, + BlockKind::Clay => 0, + BlockKind::SugarCane => 0, + BlockKind::Jukebox => 0, + BlockKind::OakFence => 0, + BlockKind::Pumpkin => 0, + BlockKind::Netherrack => 0, + BlockKind::SoulSand => 0, + BlockKind::SoulSoil => 0, + BlockKind::Basalt => 0, + BlockKind::PolishedBasalt => 0, + BlockKind::SoulTorch => 0, + BlockKind::SoulWallTorch => 0, + BlockKind::Glowstone => 15, + BlockKind::NetherPortal => 11, + BlockKind::CarvedPumpkin => 0, + BlockKind::JackOLantern => 15, + BlockKind::Cake => 0, + BlockKind::Repeater => 0, + BlockKind::WhiteStainedGlass => 0, + BlockKind::OrangeStainedGlass => 0, + BlockKind::MagentaStainedGlass => 0, + BlockKind::LightBlueStainedGlass => 0, + BlockKind::YellowStainedGlass => 0, + BlockKind::LimeStainedGlass => 0, + BlockKind::PinkStainedGlass => 0, + BlockKind::GrayStainedGlass => 0, + BlockKind::LightGrayStainedGlass => 0, + BlockKind::CyanStainedGlass => 0, + BlockKind::PurpleStainedGlass => 0, + BlockKind::BlueStainedGlass => 0, + BlockKind::BrownStainedGlass => 0, + BlockKind::GreenStainedGlass => 0, + BlockKind::RedStainedGlass => 0, + BlockKind::BlackStainedGlass => 0, + BlockKind::OakTrapdoor => 0, + BlockKind::SpruceTrapdoor => 0, + BlockKind::BirchTrapdoor => 0, + BlockKind::JungleTrapdoor => 0, + BlockKind::AcaciaTrapdoor => 0, + BlockKind::DarkOakTrapdoor => 0, + BlockKind::StoneBricks => 0, + BlockKind::MossyStoneBricks => 0, + BlockKind::CrackedStoneBricks => 0, + BlockKind::ChiseledStoneBricks => 0, + BlockKind::InfestedStone => 0, + BlockKind::InfestedCobblestone => 0, + BlockKind::InfestedStoneBricks => 0, + BlockKind::InfestedMossyStoneBricks => 0, + BlockKind::InfestedCrackedStoneBricks => 0, + BlockKind::InfestedChiseledStoneBricks => 0, + BlockKind::BrownMushroomBlock => 0, + BlockKind::RedMushroomBlock => 0, + BlockKind::MushroomStem => 0, + BlockKind::IronBars => 0, + BlockKind::Chain => 0, + BlockKind::GlassPane => 0, + BlockKind::Melon => 0, + BlockKind::AttachedPumpkinStem => 0, + BlockKind::AttachedMelonStem => 0, + BlockKind::PumpkinStem => 0, + BlockKind::MelonStem => 0, + BlockKind::Vine => 0, + BlockKind::OakFenceGate => 0, + BlockKind::BrickStairs => 0, + BlockKind::StoneBrickStairs => 0, + BlockKind::Mycelium => 0, + BlockKind::LilyPad => 0, + BlockKind::NetherBricks => 0, + BlockKind::NetherBrickFence => 0, + BlockKind::NetherBrickStairs => 0, + BlockKind::NetherWart => 0, + BlockKind::EnchantingTable => 0, + BlockKind::BrewingStand => 1, + BlockKind::Cauldron => 0, + BlockKind::EndPortal => 15, + BlockKind::EndPortalFrame => 1, + BlockKind::EndStone => 0, + BlockKind::DragonEgg => 0, + BlockKind::RedstoneLamp => 15, + BlockKind::Cocoa => 0, + BlockKind::SandstoneStairs => 0, + BlockKind::EmeraldOre => 0, + BlockKind::EnderChest => 0, + BlockKind::TripwireHook => 0, + BlockKind::Tripwire => 0, + BlockKind::EmeraldBlock => 0, + BlockKind::SpruceStairs => 0, + BlockKind::BirchStairs => 0, + BlockKind::JungleStairs => 0, + BlockKind::CommandBlock => 0, + BlockKind::Beacon => 15, + BlockKind::CobblestoneWall => 0, + BlockKind::MossyCobblestoneWall => 0, + BlockKind::FlowerPot => 0, + BlockKind::PottedOakSapling => 0, + BlockKind::PottedSpruceSapling => 0, + BlockKind::PottedBirchSapling => 0, + BlockKind::PottedJungleSapling => 0, + BlockKind::PottedAcaciaSapling => 0, + BlockKind::PottedDarkOakSapling => 0, + BlockKind::PottedFern => 0, + BlockKind::PottedDandelion => 0, + BlockKind::PottedPoppy => 0, + BlockKind::PottedBlueOrchid => 0, + BlockKind::PottedAllium => 0, + BlockKind::PottedAzureBluet => 0, + BlockKind::PottedRedTulip => 0, + BlockKind::PottedOrangeTulip => 0, + BlockKind::PottedWhiteTulip => 0, + BlockKind::PottedPinkTulip => 0, + BlockKind::PottedOxeyeDaisy => 0, + BlockKind::PottedCornflower => 0, + BlockKind::PottedLilyOfTheValley => 0, + BlockKind::PottedWitherRose => 0, + BlockKind::PottedRedMushroom => 0, + BlockKind::PottedBrownMushroom => 0, + BlockKind::PottedDeadBush => 0, + BlockKind::PottedCactus => 0, + BlockKind::Carrots => 0, + BlockKind::Potatoes => 0, + BlockKind::OakButton => 0, + BlockKind::SpruceButton => 0, + BlockKind::BirchButton => 0, + BlockKind::JungleButton => 0, + BlockKind::AcaciaButton => 0, + BlockKind::DarkOakButton => 0, + BlockKind::SkeletonSkull => 0, + BlockKind::SkeletonWallSkull => 0, + BlockKind::WitherSkeletonSkull => 0, + BlockKind::WitherSkeletonWallSkull => 0, + BlockKind::ZombieHead => 0, + BlockKind::ZombieWallHead => 0, + BlockKind::PlayerHead => 0, + BlockKind::PlayerWallHead => 0, + BlockKind::CreeperHead => 0, + BlockKind::CreeperWallHead => 0, + BlockKind::DragonHead => 0, + BlockKind::DragonWallHead => 0, + BlockKind::Anvil => 0, + BlockKind::ChippedAnvil => 0, + BlockKind::DamagedAnvil => 0, + BlockKind::TrappedChest => 0, + BlockKind::LightWeightedPressurePlate => 0, + BlockKind::HeavyWeightedPressurePlate => 0, + BlockKind::Comparator => 0, + BlockKind::DaylightDetector => 0, + BlockKind::RedstoneBlock => 0, + BlockKind::NetherQuartzOre => 0, + BlockKind::Hopper => 0, + BlockKind::QuartzBlock => 0, + BlockKind::ChiseledQuartzBlock => 0, + BlockKind::QuartzPillar => 0, + BlockKind::QuartzStairs => 0, + BlockKind::ActivatorRail => 0, + BlockKind::Dropper => 0, + BlockKind::WhiteTerracotta => 0, + BlockKind::OrangeTerracotta => 0, + BlockKind::MagentaTerracotta => 0, + BlockKind::LightBlueTerracotta => 0, + BlockKind::YellowTerracotta => 0, + BlockKind::LimeTerracotta => 0, + BlockKind::PinkTerracotta => 0, + BlockKind::GrayTerracotta => 0, + BlockKind::LightGrayTerracotta => 0, + BlockKind::CyanTerracotta => 0, + BlockKind::PurpleTerracotta => 0, + BlockKind::BlueTerracotta => 0, + BlockKind::BrownTerracotta => 0, + BlockKind::GreenTerracotta => 0, + BlockKind::RedTerracotta => 0, + BlockKind::BlackTerracotta => 0, + BlockKind::WhiteStainedGlassPane => 0, + BlockKind::OrangeStainedGlassPane => 0, + BlockKind::MagentaStainedGlassPane => 0, + BlockKind::LightBlueStainedGlassPane => 0, + BlockKind::YellowStainedGlassPane => 0, + BlockKind::LimeStainedGlassPane => 0, + BlockKind::PinkStainedGlassPane => 0, + BlockKind::GrayStainedGlassPane => 0, + BlockKind::LightGrayStainedGlassPane => 0, + BlockKind::CyanStainedGlassPane => 0, + BlockKind::PurpleStainedGlassPane => 0, + BlockKind::BlueStainedGlassPane => 0, + BlockKind::BrownStainedGlassPane => 0, + BlockKind::GreenStainedGlassPane => 0, + BlockKind::RedStainedGlassPane => 0, + BlockKind::BlackStainedGlassPane => 0, + BlockKind::AcaciaStairs => 0, + BlockKind::DarkOakStairs => 0, + BlockKind::SlimeBlock => 0, + BlockKind::Barrier => 0, + BlockKind::IronTrapdoor => 0, + BlockKind::Prismarine => 0, + BlockKind::PrismarineBricks => 0, + BlockKind::DarkPrismarine => 0, + BlockKind::PrismarineStairs => 0, + BlockKind::PrismarineBrickStairs => 0, + BlockKind::DarkPrismarineStairs => 0, + BlockKind::PrismarineSlab => 0, + BlockKind::PrismarineBrickSlab => 0, + BlockKind::DarkPrismarineSlab => 0, + BlockKind::SeaLantern => 15, + BlockKind::HayBlock => 0, + BlockKind::WhiteCarpet => 0, + BlockKind::OrangeCarpet => 0, + BlockKind::MagentaCarpet => 0, + BlockKind::LightBlueCarpet => 0, + BlockKind::YellowCarpet => 0, + BlockKind::LimeCarpet => 0, + BlockKind::PinkCarpet => 0, + BlockKind::GrayCarpet => 0, + BlockKind::LightGrayCarpet => 0, + BlockKind::CyanCarpet => 0, + BlockKind::PurpleCarpet => 0, + BlockKind::BlueCarpet => 0, + BlockKind::BrownCarpet => 0, + BlockKind::GreenCarpet => 0, + BlockKind::RedCarpet => 0, + BlockKind::BlackCarpet => 0, + BlockKind::Terracotta => 0, + BlockKind::CoalBlock => 0, + BlockKind::PackedIce => 0, + BlockKind::Sunflower => 0, + BlockKind::Lilac => 0, + BlockKind::RoseBush => 0, + BlockKind::Peony => 0, + BlockKind::TallGrass => 0, + BlockKind::LargeFern => 0, + BlockKind::WhiteBanner => 0, + BlockKind::OrangeBanner => 0, + BlockKind::MagentaBanner => 0, + BlockKind::LightBlueBanner => 0, + BlockKind::YellowBanner => 0, + BlockKind::LimeBanner => 0, + BlockKind::PinkBanner => 0, + BlockKind::GrayBanner => 0, + BlockKind::LightGrayBanner => 0, + BlockKind::CyanBanner => 0, + BlockKind::PurpleBanner => 0, + BlockKind::BlueBanner => 0, + BlockKind::BrownBanner => 0, + BlockKind::GreenBanner => 0, + BlockKind::RedBanner => 0, + BlockKind::BlackBanner => 0, + BlockKind::WhiteWallBanner => 0, + BlockKind::OrangeWallBanner => 0, + BlockKind::MagentaWallBanner => 0, + BlockKind::LightBlueWallBanner => 0, + BlockKind::YellowWallBanner => 0, + BlockKind::LimeWallBanner => 0, + BlockKind::PinkWallBanner => 0, + BlockKind::GrayWallBanner => 0, + BlockKind::LightGrayWallBanner => 0, + BlockKind::CyanWallBanner => 0, + BlockKind::PurpleWallBanner => 0, + BlockKind::BlueWallBanner => 0, + BlockKind::BrownWallBanner => 0, + BlockKind::GreenWallBanner => 0, + BlockKind::RedWallBanner => 0, + BlockKind::BlackWallBanner => 0, + BlockKind::RedSandstone => 0, + BlockKind::ChiseledRedSandstone => 0, + BlockKind::CutRedSandstone => 0, + BlockKind::RedSandstoneStairs => 0, + BlockKind::OakSlab => 0, + BlockKind::SpruceSlab => 0, + BlockKind::BirchSlab => 0, + BlockKind::JungleSlab => 0, + BlockKind::AcaciaSlab => 0, + BlockKind::DarkOakSlab => 0, + BlockKind::StoneSlab => 0, + BlockKind::SmoothStoneSlab => 0, + BlockKind::SandstoneSlab => 0, + BlockKind::CutSandstoneSlab => 0, + BlockKind::PetrifiedOakSlab => 0, + BlockKind::CobblestoneSlab => 0, + BlockKind::BrickSlab => 0, + BlockKind::StoneBrickSlab => 0, + BlockKind::NetherBrickSlab => 0, + BlockKind::QuartzSlab => 0, + BlockKind::RedSandstoneSlab => 0, + BlockKind::CutRedSandstoneSlab => 0, + BlockKind::PurpurSlab => 0, + BlockKind::SmoothStone => 0, + BlockKind::SmoothSandstone => 0, + BlockKind::SmoothQuartz => 0, + BlockKind::SmoothRedSandstone => 0, + BlockKind::SpruceFenceGate => 0, + BlockKind::BirchFenceGate => 0, + BlockKind::JungleFenceGate => 0, + BlockKind::AcaciaFenceGate => 0, + BlockKind::DarkOakFenceGate => 0, + BlockKind::SpruceFence => 0, + BlockKind::BirchFence => 0, + BlockKind::JungleFence => 0, + BlockKind::AcaciaFence => 0, + BlockKind::DarkOakFence => 0, + BlockKind::SpruceDoor => 0, + BlockKind::BirchDoor => 0, + BlockKind::JungleDoor => 0, + BlockKind::AcaciaDoor => 0, + BlockKind::DarkOakDoor => 0, + BlockKind::EndRod => 14, + BlockKind::ChorusPlant => 0, + BlockKind::ChorusFlower => 0, + BlockKind::PurpurBlock => 0, + BlockKind::PurpurPillar => 0, + BlockKind::PurpurStairs => 0, + BlockKind::EndStoneBricks => 0, + BlockKind::Beetroots => 0, + BlockKind::GrassPath => 0, + BlockKind::EndGateway => 15, + BlockKind::RepeatingCommandBlock => 0, + BlockKind::ChainCommandBlock => 0, + BlockKind::FrostedIce => 0, + BlockKind::MagmaBlock => 0, + BlockKind::NetherWartBlock => 0, + BlockKind::RedNetherBricks => 0, + BlockKind::BoneBlock => 0, + BlockKind::StructureVoid => 0, + BlockKind::Observer => 0, + BlockKind::ShulkerBox => 0, + BlockKind::WhiteShulkerBox => 0, + BlockKind::OrangeShulkerBox => 0, + BlockKind::MagentaShulkerBox => 0, + BlockKind::LightBlueShulkerBox => 0, + BlockKind::YellowShulkerBox => 0, + BlockKind::LimeShulkerBox => 0, + BlockKind::PinkShulkerBox => 0, + BlockKind::GrayShulkerBox => 0, + BlockKind::LightGrayShulkerBox => 0, + BlockKind::CyanShulkerBox => 0, + BlockKind::PurpleShulkerBox => 0, + BlockKind::BlueShulkerBox => 0, + BlockKind::BrownShulkerBox => 0, + BlockKind::GreenShulkerBox => 0, + BlockKind::RedShulkerBox => 0, + BlockKind::BlackShulkerBox => 0, + BlockKind::WhiteGlazedTerracotta => 0, + BlockKind::OrangeGlazedTerracotta => 0, + BlockKind::MagentaGlazedTerracotta => 0, + BlockKind::LightBlueGlazedTerracotta => 0, + BlockKind::YellowGlazedTerracotta => 0, + BlockKind::LimeGlazedTerracotta => 0, + BlockKind::PinkGlazedTerracotta => 0, + BlockKind::GrayGlazedTerracotta => 0, + BlockKind::LightGrayGlazedTerracotta => 0, + BlockKind::CyanGlazedTerracotta => 0, + BlockKind::PurpleGlazedTerracotta => 0, + BlockKind::BlueGlazedTerracotta => 0, + BlockKind::BrownGlazedTerracotta => 0, + BlockKind::GreenGlazedTerracotta => 0, + BlockKind::RedGlazedTerracotta => 0, + BlockKind::BlackGlazedTerracotta => 0, + BlockKind::WhiteConcrete => 0, + BlockKind::OrangeConcrete => 0, + BlockKind::MagentaConcrete => 0, + BlockKind::LightBlueConcrete => 0, + BlockKind::YellowConcrete => 0, + BlockKind::LimeConcrete => 0, + BlockKind::PinkConcrete => 0, + BlockKind::GrayConcrete => 0, + BlockKind::LightGrayConcrete => 0, + BlockKind::CyanConcrete => 0, + BlockKind::PurpleConcrete => 0, + BlockKind::BlueConcrete => 0, + BlockKind::BrownConcrete => 0, + BlockKind::GreenConcrete => 0, + BlockKind::RedConcrete => 0, + BlockKind::BlackConcrete => 0, + BlockKind::WhiteConcretePowder => 0, + BlockKind::OrangeConcretePowder => 0, + BlockKind::MagentaConcretePowder => 0, + BlockKind::LightBlueConcretePowder => 0, + BlockKind::YellowConcretePowder => 0, + BlockKind::LimeConcretePowder => 0, + BlockKind::PinkConcretePowder => 0, + BlockKind::GrayConcretePowder => 0, + BlockKind::LightGrayConcretePowder => 0, + BlockKind::CyanConcretePowder => 0, + BlockKind::PurpleConcretePowder => 0, + BlockKind::BlueConcretePowder => 0, + BlockKind::BrownConcretePowder => 0, + BlockKind::GreenConcretePowder => 0, + BlockKind::RedConcretePowder => 0, + BlockKind::BlackConcretePowder => 0, + BlockKind::Kelp => 0, + BlockKind::KelpPlant => 0, + BlockKind::DriedKelpBlock => 0, + BlockKind::TurtleEgg => 0, + BlockKind::DeadTubeCoralBlock => 0, + BlockKind::DeadBrainCoralBlock => 0, + BlockKind::DeadBubbleCoralBlock => 0, + BlockKind::DeadFireCoralBlock => 0, + BlockKind::DeadHornCoralBlock => 0, + BlockKind::TubeCoralBlock => 0, + BlockKind::BrainCoralBlock => 0, + BlockKind::BubbleCoralBlock => 0, + BlockKind::FireCoralBlock => 0, + BlockKind::HornCoralBlock => 0, + BlockKind::DeadTubeCoral => 0, + BlockKind::DeadBrainCoral => 0, + BlockKind::DeadBubbleCoral => 0, + BlockKind::DeadFireCoral => 0, + BlockKind::DeadHornCoral => 0, + BlockKind::TubeCoral => 0, + BlockKind::BrainCoral => 0, + BlockKind::BubbleCoral => 0, + BlockKind::FireCoral => 0, + BlockKind::HornCoral => 0, + BlockKind::DeadTubeCoralFan => 0, + BlockKind::DeadBrainCoralFan => 0, + BlockKind::DeadBubbleCoralFan => 0, + BlockKind::DeadFireCoralFan => 0, + BlockKind::DeadHornCoralFan => 0, + BlockKind::TubeCoralFan => 0, + BlockKind::BrainCoralFan => 0, + BlockKind::BubbleCoralFan => 0, + BlockKind::FireCoralFan => 0, + BlockKind::HornCoralFan => 0, + BlockKind::DeadTubeCoralWallFan => 0, + BlockKind::DeadBrainCoralWallFan => 0, + BlockKind::DeadBubbleCoralWallFan => 0, + BlockKind::DeadFireCoralWallFan => 0, + BlockKind::DeadHornCoralWallFan => 0, + BlockKind::TubeCoralWallFan => 0, + BlockKind::BrainCoralWallFan => 0, + BlockKind::BubbleCoralWallFan => 0, + BlockKind::FireCoralWallFan => 0, + BlockKind::HornCoralWallFan => 0, + BlockKind::SeaPickle => 0, + BlockKind::BlueIce => 0, + BlockKind::Conduit => 0, + BlockKind::BambooSapling => 0, + BlockKind::Bamboo => 0, + BlockKind::PottedBamboo => 0, + BlockKind::VoidAir => 0, + BlockKind::CaveAir => 0, + BlockKind::BubbleColumn => 0, + BlockKind::PolishedGraniteStairs => 0, + BlockKind::SmoothRedSandstoneStairs => 0, + BlockKind::MossyStoneBrickStairs => 0, + BlockKind::PolishedDioriteStairs => 0, + BlockKind::MossyCobblestoneStairs => 0, + BlockKind::EndStoneBrickStairs => 0, + BlockKind::StoneStairs => 0, + BlockKind::SmoothSandstoneStairs => 0, + BlockKind::SmoothQuartzStairs => 0, + BlockKind::GraniteStairs => 0, + BlockKind::AndesiteStairs => 0, + BlockKind::RedNetherBrickStairs => 0, + BlockKind::PolishedAndesiteStairs => 0, + BlockKind::DioriteStairs => 0, + BlockKind::PolishedGraniteSlab => 0, + BlockKind::SmoothRedSandstoneSlab => 0, + BlockKind::MossyStoneBrickSlab => 0, + BlockKind::PolishedDioriteSlab => 0, + BlockKind::MossyCobblestoneSlab => 0, + BlockKind::EndStoneBrickSlab => 0, + BlockKind::SmoothSandstoneSlab => 0, + BlockKind::SmoothQuartzSlab => 0, + BlockKind::GraniteSlab => 0, + BlockKind::AndesiteSlab => 0, + BlockKind::RedNetherBrickSlab => 0, + BlockKind::PolishedAndesiteSlab => 0, + BlockKind::DioriteSlab => 0, + BlockKind::BrickWall => 0, + BlockKind::PrismarineWall => 0, + BlockKind::RedSandstoneWall => 0, + BlockKind::MossyStoneBrickWall => 0, + BlockKind::GraniteWall => 0, + BlockKind::StoneBrickWall => 0, + BlockKind::NetherBrickWall => 0, + BlockKind::AndesiteWall => 0, + BlockKind::RedNetherBrickWall => 0, + BlockKind::SandstoneWall => 0, + BlockKind::EndStoneBrickWall => 0, + BlockKind::DioriteWall => 0, + BlockKind::Scaffolding => 0, + BlockKind::Loom => 0, + BlockKind::Barrel => 0, + BlockKind::Smoker => 0, + BlockKind::BlastFurnace => 0, + BlockKind::CartographyTable => 0, + BlockKind::FletchingTable => 0, + BlockKind::Grindstone => 0, + BlockKind::Lectern => 0, + BlockKind::SmithingTable => 0, + BlockKind::Stonecutter => 0, + BlockKind::Bell => 0, + BlockKind::Lantern => 0, + BlockKind::SoulLantern => 0, + BlockKind::Campfire => 0, + BlockKind::SoulCampfire => 0, + BlockKind::SweetBerryBush => 0, + BlockKind::WarpedStem => 0, + BlockKind::StrippedWarpedStem => 0, + BlockKind::WarpedHyphae => 0, + BlockKind::StrippedWarpedHyphae => 0, + BlockKind::WarpedNylium => 0, + BlockKind::WarpedFungus => 0, + BlockKind::WarpedWartBlock => 0, + BlockKind::WarpedRoots => 0, + BlockKind::NetherSprouts => 0, + BlockKind::CrimsonStem => 0, + BlockKind::StrippedCrimsonStem => 0, + BlockKind::CrimsonHyphae => 0, + BlockKind::StrippedCrimsonHyphae => 0, + BlockKind::CrimsonNylium => 0, + BlockKind::CrimsonFungus => 0, + BlockKind::Shroomlight => 0, + BlockKind::WeepingVines => 0, + BlockKind::WeepingVinesPlant => 0, + BlockKind::TwistingVines => 0, + BlockKind::TwistingVinesPlant => 0, + BlockKind::CrimsonRoots => 0, + BlockKind::CrimsonPlanks => 0, + BlockKind::WarpedPlanks => 0, + BlockKind::CrimsonSlab => 0, + BlockKind::WarpedSlab => 0, + BlockKind::CrimsonPressurePlate => 0, + BlockKind::WarpedPressurePlate => 0, + BlockKind::CrimsonFence => 0, + BlockKind::WarpedFence => 0, + BlockKind::CrimsonTrapdoor => 0, + BlockKind::WarpedTrapdoor => 0, + BlockKind::CrimsonFenceGate => 0, + BlockKind::WarpedFenceGate => 0, + BlockKind::CrimsonStairs => 0, + BlockKind::WarpedStairs => 0, + BlockKind::CrimsonButton => 0, + BlockKind::WarpedButton => 0, + BlockKind::CrimsonDoor => 0, + BlockKind::WarpedDoor => 0, + BlockKind::CrimsonSign => 0, + BlockKind::WarpedSign => 0, + BlockKind::CrimsonWallSign => 0, + BlockKind::WarpedWallSign => 0, + BlockKind::StructureBlock => 0, + BlockKind::Jigsaw => 0, + BlockKind::Composter => 0, + BlockKind::Target => 0, + BlockKind::BeeNest => 0, + BlockKind::Beehive => 0, + BlockKind::HoneyBlock => 0, + BlockKind::HoneycombBlock => 0, + BlockKind::NetheriteBlock => 0, + BlockKind::AncientDebris => 0, + BlockKind::CryingObsidian => 0, + BlockKind::RespawnAnchor => 2, + BlockKind::PottedCrimsonFungus => 0, + BlockKind::PottedWarpedFungus => 0, + BlockKind::PottedCrimsonRoots => 0, + BlockKind::PottedWarpedRoots => 0, + BlockKind::Lodestone => 0, + BlockKind::Blackstone => 0, + BlockKind::BlackstoneStairs => 0, + BlockKind::BlackstoneWall => 0, + BlockKind::BlackstoneSlab => 0, + BlockKind::PolishedBlackstone => 0, + BlockKind::PolishedBlackstoneBricks => 0, + BlockKind::CrackedPolishedBlackstoneBricks => 0, + BlockKind::ChiseledPolishedBlackstone => 0, + BlockKind::PolishedBlackstoneBrickSlab => 0, + BlockKind::PolishedBlackstoneBrickStairs => 0, + BlockKind::PolishedBlackstoneBrickWall => 0, + BlockKind::GildedBlackstone => 0, + BlockKind::PolishedBlackstoneStairs => 0, + BlockKind::PolishedBlackstoneSlab => 0, + BlockKind::PolishedBlackstonePressurePlate => 0, + BlockKind::PolishedBlackstoneButton => 0, + BlockKind::PolishedBlackstoneWall => 0, + BlockKind::ChiseledNetherBricks => 0, + BlockKind::CrackedNetherBricks => 0, + BlockKind::QuartzBricks => 0, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `light_filter` property of this `BlockKind`. + pub fn light_filter(&self) -> u8 { + match self { + BlockKind::Air => 0, + BlockKind::Stone => 15, + BlockKind::Granite => 15, + BlockKind::PolishedGranite => 15, + BlockKind::Diorite => 15, + BlockKind::PolishedDiorite => 15, + BlockKind::Andesite => 15, + BlockKind::PolishedAndesite => 15, + BlockKind::GrassBlock => 15, + BlockKind::Dirt => 15, + BlockKind::CoarseDirt => 15, + BlockKind::Podzol => 15, + BlockKind::Cobblestone => 15, + BlockKind::OakPlanks => 15, + BlockKind::SprucePlanks => 15, + BlockKind::BirchPlanks => 15, + BlockKind::JunglePlanks => 15, + BlockKind::AcaciaPlanks => 15, + BlockKind::DarkOakPlanks => 15, + BlockKind::OakSapling => 0, + BlockKind::SpruceSapling => 0, + BlockKind::BirchSapling => 0, + BlockKind::JungleSapling => 0, + BlockKind::AcaciaSapling => 0, + BlockKind::DarkOakSapling => 0, + BlockKind::Bedrock => 15, + BlockKind::Water => 2, + BlockKind::Lava => 0, + BlockKind::Sand => 15, + BlockKind::RedSand => 15, + BlockKind::Gravel => 15, + BlockKind::GoldOre => 15, + BlockKind::IronOre => 15, + BlockKind::CoalOre => 15, + BlockKind::NetherGoldOre => 15, + BlockKind::OakLog => 15, + BlockKind::SpruceLog => 15, + BlockKind::BirchLog => 15, + BlockKind::JungleLog => 15, + BlockKind::AcaciaLog => 15, + BlockKind::DarkOakLog => 15, + BlockKind::StrippedSpruceLog => 15, + BlockKind::StrippedBirchLog => 15, + BlockKind::StrippedJungleLog => 15, + BlockKind::StrippedAcaciaLog => 15, + BlockKind::StrippedDarkOakLog => 15, + BlockKind::StrippedOakLog => 15, + BlockKind::OakWood => 15, + BlockKind::SpruceWood => 15, + BlockKind::BirchWood => 15, + BlockKind::JungleWood => 15, + BlockKind::AcaciaWood => 15, + BlockKind::DarkOakWood => 15, + BlockKind::StrippedOakWood => 15, + BlockKind::StrippedSpruceWood => 15, + BlockKind::StrippedBirchWood => 15, + BlockKind::StrippedJungleWood => 15, + BlockKind::StrippedAcaciaWood => 15, + BlockKind::StrippedDarkOakWood => 15, + BlockKind::OakLeaves => 0, + BlockKind::SpruceLeaves => 0, + BlockKind::BirchLeaves => 0, + BlockKind::JungleLeaves => 0, + BlockKind::AcaciaLeaves => 0, + BlockKind::DarkOakLeaves => 0, + BlockKind::Sponge => 15, + BlockKind::WetSponge => 15, + BlockKind::Glass => 0, + BlockKind::LapisOre => 15, + BlockKind::LapisBlock => 15, + BlockKind::Dispenser => 15, + BlockKind::Sandstone => 15, + BlockKind::ChiseledSandstone => 15, + BlockKind::CutSandstone => 15, + BlockKind::NoteBlock => 15, + BlockKind::WhiteBed => 0, + BlockKind::OrangeBed => 0, + BlockKind::MagentaBed => 0, + BlockKind::LightBlueBed => 0, + BlockKind::YellowBed => 0, + BlockKind::LimeBed => 0, + BlockKind::PinkBed => 0, + BlockKind::GrayBed => 0, + BlockKind::LightGrayBed => 0, + BlockKind::CyanBed => 0, + BlockKind::PurpleBed => 0, + BlockKind::BlueBed => 0, + BlockKind::BrownBed => 0, + BlockKind::GreenBed => 0, + BlockKind::RedBed => 0, + BlockKind::BlackBed => 0, + BlockKind::PoweredRail => 0, + BlockKind::DetectorRail => 0, + BlockKind::StickyPiston => 0, + BlockKind::Cobweb => 0, + BlockKind::Grass => 15, + BlockKind::Fern => 0, + BlockKind::DeadBush => 0, + BlockKind::Seagrass => 0, + BlockKind::TallSeagrass => 0, + BlockKind::Piston => 0, + BlockKind::PistonHead => 0, + BlockKind::WhiteWool => 15, + BlockKind::OrangeWool => 15, + BlockKind::MagentaWool => 15, + BlockKind::LightBlueWool => 15, + BlockKind::YellowWool => 15, + BlockKind::LimeWool => 15, + BlockKind::PinkWool => 15, + BlockKind::GrayWool => 15, + BlockKind::LightGrayWool => 15, + BlockKind::CyanWool => 15, + BlockKind::PurpleWool => 15, + BlockKind::BlueWool => 15, + BlockKind::BrownWool => 15, + BlockKind::GreenWool => 15, + BlockKind::RedWool => 15, + BlockKind::BlackWool => 15, + BlockKind::MovingPiston => 0, + BlockKind::Dandelion => 15, + BlockKind::Poppy => 15, + BlockKind::BlueOrchid => 0, + BlockKind::Allium => 15, + BlockKind::AzureBluet => 15, + BlockKind::RedTulip => 0, + BlockKind::OrangeTulip => 0, + BlockKind::WhiteTulip => 0, + BlockKind::PinkTulip => 0, + BlockKind::OxeyeDaisy => 15, + BlockKind::Cornflower => 0, + BlockKind::WitherRose => 0, + BlockKind::LilyOfTheValley => 0, + BlockKind::BrownMushroom => 15, + BlockKind::RedMushroom => 15, + BlockKind::GoldBlock => 15, + BlockKind::IronBlock => 15, + BlockKind::Bricks => 15, + BlockKind::Tnt => 0, + BlockKind::Bookshelf => 15, + BlockKind::MossyCobblestone => 15, + BlockKind::Obsidian => 15, + BlockKind::Torch => 0, + BlockKind::WallTorch => 0, + BlockKind::Fire => 0, + BlockKind::SoulFire => 15, + BlockKind::Spawner => 0, + BlockKind::OakStairs => 15, + BlockKind::Chest => 0, + BlockKind::RedstoneWire => 0, + BlockKind::DiamondOre => 15, + BlockKind::DiamondBlock => 15, + BlockKind::CraftingTable => 15, + BlockKind::Wheat => 0, + BlockKind::Farmland => 0, + BlockKind::Furnace => 0, + BlockKind::OakSign => 0, + BlockKind::SpruceSign => 0, + BlockKind::BirchSign => 0, + BlockKind::AcaciaSign => 0, + BlockKind::JungleSign => 0, + BlockKind::DarkOakSign => 0, + BlockKind::OakDoor => 0, + BlockKind::Ladder => 0, + BlockKind::Rail => 0, + BlockKind::CobblestoneStairs => 15, + BlockKind::OakWallSign => 0, + BlockKind::SpruceWallSign => 0, + BlockKind::BirchWallSign => 0, + BlockKind::AcaciaWallSign => 0, + BlockKind::JungleWallSign => 0, + BlockKind::DarkOakWallSign => 0, + BlockKind::Lever => 0, + BlockKind::StonePressurePlate => 0, + BlockKind::IronDoor => 0, + BlockKind::OakPressurePlate => 0, + BlockKind::SprucePressurePlate => 0, + BlockKind::BirchPressurePlate => 0, + BlockKind::JunglePressurePlate => 0, + BlockKind::AcaciaPressurePlate => 0, + BlockKind::DarkOakPressurePlate => 0, + BlockKind::RedstoneOre => 0, + BlockKind::RedstoneTorch => 0, + BlockKind::RedstoneWallTorch => 0, + BlockKind::StoneButton => 0, + BlockKind::Snow => 15, + BlockKind::Ice => 0, + BlockKind::SnowBlock => 15, + BlockKind::Cactus => 0, + BlockKind::Clay => 15, + BlockKind::SugarCane => 0, + BlockKind::Jukebox => 15, + BlockKind::OakFence => 0, + BlockKind::Pumpkin => 15, + BlockKind::Netherrack => 15, + BlockKind::SoulSand => 15, + BlockKind::SoulSoil => 15, + BlockKind::Basalt => 15, + BlockKind::PolishedBasalt => 15, + BlockKind::SoulTorch => 0, + BlockKind::SoulWallTorch => 0, + BlockKind::Glowstone => 0, + BlockKind::NetherPortal => 0, + BlockKind::CarvedPumpkin => 15, + BlockKind::JackOLantern => 15, + BlockKind::Cake => 0, + BlockKind::Repeater => 0, + BlockKind::WhiteStainedGlass => 0, + BlockKind::OrangeStainedGlass => 0, + BlockKind::MagentaStainedGlass => 0, + BlockKind::LightBlueStainedGlass => 0, + BlockKind::YellowStainedGlass => 0, + BlockKind::LimeStainedGlass => 0, + BlockKind::PinkStainedGlass => 0, + BlockKind::GrayStainedGlass => 0, + BlockKind::LightGrayStainedGlass => 0, + BlockKind::CyanStainedGlass => 0, + BlockKind::PurpleStainedGlass => 0, + BlockKind::BlueStainedGlass => 0, + BlockKind::BrownStainedGlass => 0, + BlockKind::GreenStainedGlass => 0, + BlockKind::RedStainedGlass => 0, + BlockKind::BlackStainedGlass => 0, + BlockKind::OakTrapdoor => 0, + BlockKind::SpruceTrapdoor => 0, + BlockKind::BirchTrapdoor => 0, + BlockKind::JungleTrapdoor => 0, + BlockKind::AcaciaTrapdoor => 0, + BlockKind::DarkOakTrapdoor => 0, + BlockKind::StoneBricks => 15, + BlockKind::MossyStoneBricks => 15, + BlockKind::CrackedStoneBricks => 15, + BlockKind::ChiseledStoneBricks => 15, + BlockKind::InfestedStone => 15, + BlockKind::InfestedCobblestone => 15, + BlockKind::InfestedStoneBricks => 15, + BlockKind::InfestedMossyStoneBricks => 15, + BlockKind::InfestedCrackedStoneBricks => 15, + BlockKind::InfestedChiseledStoneBricks => 15, + BlockKind::BrownMushroomBlock => 15, + BlockKind::RedMushroomBlock => 15, + BlockKind::MushroomStem => 15, + BlockKind::IronBars => 0, + BlockKind::Chain => 0, + BlockKind::GlassPane => 0, + BlockKind::Melon => 15, + BlockKind::AttachedPumpkinStem => 0, + BlockKind::AttachedMelonStem => 0, + BlockKind::PumpkinStem => 0, + BlockKind::MelonStem => 0, + BlockKind::Vine => 0, + BlockKind::OakFenceGate => 0, + BlockKind::BrickStairs => 15, + BlockKind::StoneBrickStairs => 15, + BlockKind::Mycelium => 15, + BlockKind::LilyPad => 0, + BlockKind::NetherBricks => 15, + BlockKind::NetherBrickFence => 0, + BlockKind::NetherBrickStairs => 15, + BlockKind::NetherWart => 0, + BlockKind::EnchantingTable => 0, + BlockKind::BrewingStand => 0, + BlockKind::Cauldron => 0, + BlockKind::EndPortal => 0, + BlockKind::EndPortalFrame => 0, + BlockKind::EndStone => 15, + BlockKind::DragonEgg => 0, + BlockKind::RedstoneLamp => 0, + BlockKind::Cocoa => 0, + BlockKind::SandstoneStairs => 15, + BlockKind::EmeraldOre => 15, + BlockKind::EnderChest => 0, + BlockKind::TripwireHook => 0, + BlockKind::Tripwire => 0, + BlockKind::EmeraldBlock => 15, + BlockKind::SpruceStairs => 15, + BlockKind::BirchStairs => 15, + BlockKind::JungleStairs => 15, + BlockKind::CommandBlock => 15, + BlockKind::Beacon => 0, + BlockKind::CobblestoneWall => 0, + BlockKind::MossyCobblestoneWall => 0, + BlockKind::FlowerPot => 0, + BlockKind::PottedOakSapling => 0, + BlockKind::PottedSpruceSapling => 0, + BlockKind::PottedBirchSapling => 0, + BlockKind::PottedJungleSapling => 0, + BlockKind::PottedAcaciaSapling => 0, + BlockKind::PottedDarkOakSapling => 0, + BlockKind::PottedFern => 0, + BlockKind::PottedDandelion => 0, + BlockKind::PottedPoppy => 0, + BlockKind::PottedBlueOrchid => 0, + BlockKind::PottedAllium => 0, + BlockKind::PottedAzureBluet => 0, + BlockKind::PottedRedTulip => 0, + BlockKind::PottedOrangeTulip => 0, + BlockKind::PottedWhiteTulip => 0, + BlockKind::PottedPinkTulip => 0, + BlockKind::PottedOxeyeDaisy => 0, + BlockKind::PottedCornflower => 0, + BlockKind::PottedLilyOfTheValley => 0, + BlockKind::PottedWitherRose => 0, + BlockKind::PottedRedMushroom => 0, + BlockKind::PottedBrownMushroom => 0, + BlockKind::PottedDeadBush => 0, + BlockKind::PottedCactus => 0, + BlockKind::Carrots => 15, + BlockKind::Potatoes => 15, + BlockKind::OakButton => 0, + BlockKind::SpruceButton => 0, + BlockKind::BirchButton => 0, + BlockKind::JungleButton => 0, + BlockKind::AcaciaButton => 0, + BlockKind::DarkOakButton => 0, + BlockKind::SkeletonSkull => 0, + BlockKind::SkeletonWallSkull => 0, + BlockKind::WitherSkeletonSkull => 0, + BlockKind::WitherSkeletonWallSkull => 0, + BlockKind::ZombieHead => 0, + BlockKind::ZombieWallHead => 0, + BlockKind::PlayerHead => 0, + BlockKind::PlayerWallHead => 0, + BlockKind::CreeperHead => 0, + BlockKind::CreeperWallHead => 0, + BlockKind::DragonHead => 0, + BlockKind::DragonWallHead => 0, + BlockKind::Anvil => 0, + BlockKind::ChippedAnvil => 0, + BlockKind::DamagedAnvil => 0, + BlockKind::TrappedChest => 0, + BlockKind::LightWeightedPressurePlate => 0, + BlockKind::HeavyWeightedPressurePlate => 0, + BlockKind::Comparator => 0, + BlockKind::DaylightDetector => 0, + BlockKind::RedstoneBlock => 0, + BlockKind::NetherQuartzOre => 15, + BlockKind::Hopper => 0, + BlockKind::QuartzBlock => 15, + BlockKind::ChiseledQuartzBlock => 15, + BlockKind::QuartzPillar => 15, + BlockKind::QuartzStairs => 15, + BlockKind::ActivatorRail => 0, + BlockKind::Dropper => 15, + BlockKind::WhiteTerracotta => 15, + BlockKind::OrangeTerracotta => 15, + BlockKind::MagentaTerracotta => 15, + BlockKind::LightBlueTerracotta => 15, + BlockKind::YellowTerracotta => 15, + BlockKind::LimeTerracotta => 15, + BlockKind::PinkTerracotta => 15, + BlockKind::GrayTerracotta => 15, + BlockKind::LightGrayTerracotta => 15, + BlockKind::CyanTerracotta => 15, + BlockKind::PurpleTerracotta => 15, + BlockKind::BlueTerracotta => 15, + BlockKind::BrownTerracotta => 15, + BlockKind::GreenTerracotta => 15, + BlockKind::RedTerracotta => 15, + BlockKind::BlackTerracotta => 15, + BlockKind::WhiteStainedGlassPane => 0, + BlockKind::OrangeStainedGlassPane => 0, + BlockKind::MagentaStainedGlassPane => 0, + BlockKind::LightBlueStainedGlassPane => 0, + BlockKind::YellowStainedGlassPane => 0, + BlockKind::LimeStainedGlassPane => 0, + BlockKind::PinkStainedGlassPane => 0, + BlockKind::GrayStainedGlassPane => 0, + BlockKind::LightGrayStainedGlassPane => 0, + BlockKind::CyanStainedGlassPane => 0, + BlockKind::PurpleStainedGlassPane => 0, + BlockKind::BlueStainedGlassPane => 0, + BlockKind::BrownStainedGlassPane => 0, + BlockKind::GreenStainedGlassPane => 0, + BlockKind::RedStainedGlassPane => 0, + BlockKind::BlackStainedGlassPane => 0, + BlockKind::AcaciaStairs => 15, + BlockKind::DarkOakStairs => 15, + BlockKind::SlimeBlock => 0, + BlockKind::Barrier => 0, + BlockKind::IronTrapdoor => 0, + BlockKind::Prismarine => 15, + BlockKind::PrismarineBricks => 15, + BlockKind::DarkPrismarine => 15, + BlockKind::PrismarineStairs => 15, + BlockKind::PrismarineBrickStairs => 15, + BlockKind::DarkPrismarineStairs => 15, + BlockKind::PrismarineSlab => 0, + BlockKind::PrismarineBrickSlab => 0, + BlockKind::DarkPrismarineSlab => 0, + BlockKind::SeaLantern => 0, + BlockKind::HayBlock => 15, + BlockKind::WhiteCarpet => 0, + BlockKind::OrangeCarpet => 0, + BlockKind::MagentaCarpet => 0, + BlockKind::LightBlueCarpet => 0, + BlockKind::YellowCarpet => 0, + BlockKind::LimeCarpet => 0, + BlockKind::PinkCarpet => 0, + BlockKind::GrayCarpet => 0, + BlockKind::LightGrayCarpet => 0, + BlockKind::CyanCarpet => 0, + BlockKind::PurpleCarpet => 0, + BlockKind::BlueCarpet => 0, + BlockKind::BrownCarpet => 0, + BlockKind::GreenCarpet => 0, + BlockKind::RedCarpet => 0, + BlockKind::BlackCarpet => 0, + BlockKind::Terracotta => 15, + BlockKind::CoalBlock => 15, + BlockKind::PackedIce => 15, + BlockKind::Sunflower => 0, + BlockKind::Lilac => 0, + BlockKind::RoseBush => 0, + BlockKind::Peony => 15, + BlockKind::TallGrass => 0, + BlockKind::LargeFern => 0, + BlockKind::WhiteBanner => 0, + BlockKind::OrangeBanner => 0, + BlockKind::MagentaBanner => 0, + BlockKind::LightBlueBanner => 0, + BlockKind::YellowBanner => 0, + BlockKind::LimeBanner => 0, + BlockKind::PinkBanner => 0, + BlockKind::GrayBanner => 0, + BlockKind::LightGrayBanner => 0, + BlockKind::CyanBanner => 0, + BlockKind::PurpleBanner => 0, + BlockKind::BlueBanner => 0, + BlockKind::BrownBanner => 0, + BlockKind::GreenBanner => 0, + BlockKind::RedBanner => 0, + BlockKind::BlackBanner => 0, + BlockKind::WhiteWallBanner => 0, + BlockKind::OrangeWallBanner => 0, + BlockKind::MagentaWallBanner => 0, + BlockKind::LightBlueWallBanner => 0, + BlockKind::YellowWallBanner => 0, + BlockKind::LimeWallBanner => 0, + BlockKind::PinkWallBanner => 0, + BlockKind::GrayWallBanner => 0, + BlockKind::LightGrayWallBanner => 0, + BlockKind::CyanWallBanner => 0, + BlockKind::PurpleWallBanner => 0, + BlockKind::BlueWallBanner => 0, + BlockKind::BrownWallBanner => 0, + BlockKind::GreenWallBanner => 0, + BlockKind::RedWallBanner => 0, + BlockKind::BlackWallBanner => 0, + BlockKind::RedSandstone => 15, + BlockKind::ChiseledRedSandstone => 15, + BlockKind::CutRedSandstone => 15, + BlockKind::RedSandstoneStairs => 15, + BlockKind::OakSlab => 0, + BlockKind::SpruceSlab => 0, + BlockKind::BirchSlab => 0, + BlockKind::JungleSlab => 0, + BlockKind::AcaciaSlab => 0, + BlockKind::DarkOakSlab => 0, + BlockKind::StoneSlab => 0, + BlockKind::SmoothStoneSlab => 0, + BlockKind::SandstoneSlab => 0, + BlockKind::CutSandstoneSlab => 0, + BlockKind::PetrifiedOakSlab => 0, + BlockKind::CobblestoneSlab => 0, + BlockKind::BrickSlab => 0, + BlockKind::StoneBrickSlab => 0, + BlockKind::NetherBrickSlab => 0, + BlockKind::QuartzSlab => 0, + BlockKind::RedSandstoneSlab => 0, + BlockKind::CutRedSandstoneSlab => 0, + BlockKind::PurpurSlab => 0, + BlockKind::SmoothStone => 15, + BlockKind::SmoothSandstone => 15, + BlockKind::SmoothQuartz => 15, + BlockKind::SmoothRedSandstone => 15, + BlockKind::SpruceFenceGate => 0, + BlockKind::BirchFenceGate => 0, + BlockKind::JungleFenceGate => 0, + BlockKind::AcaciaFenceGate => 0, + BlockKind::DarkOakFenceGate => 0, + BlockKind::SpruceFence => 0, + BlockKind::BirchFence => 0, + BlockKind::JungleFence => 0, + BlockKind::AcaciaFence => 0, + BlockKind::DarkOakFence => 0, + BlockKind::SpruceDoor => 0, + BlockKind::BirchDoor => 0, + BlockKind::JungleDoor => 0, + BlockKind::AcaciaDoor => 0, + BlockKind::DarkOakDoor => 0, + BlockKind::EndRod => 15, + BlockKind::ChorusPlant => 0, + BlockKind::ChorusFlower => 0, + BlockKind::PurpurBlock => 15, + BlockKind::PurpurPillar => 15, + BlockKind::PurpurStairs => 15, + BlockKind::EndStoneBricks => 15, + BlockKind::Beetroots => 0, + BlockKind::GrassPath => 0, + BlockKind::EndGateway => 15, + BlockKind::RepeatingCommandBlock => 15, + BlockKind::ChainCommandBlock => 15, + BlockKind::FrostedIce => 2, + BlockKind::MagmaBlock => 15, + BlockKind::NetherWartBlock => 15, + BlockKind::RedNetherBricks => 15, + BlockKind::BoneBlock => 15, + BlockKind::StructureVoid => 15, + BlockKind::Observer => 0, + BlockKind::ShulkerBox => 0, + BlockKind::WhiteShulkerBox => 0, + BlockKind::OrangeShulkerBox => 0, + BlockKind::MagentaShulkerBox => 0, + BlockKind::LightBlueShulkerBox => 0, + BlockKind::YellowShulkerBox => 0, + BlockKind::LimeShulkerBox => 0, + BlockKind::PinkShulkerBox => 0, + BlockKind::GrayShulkerBox => 0, + BlockKind::LightGrayShulkerBox => 0, + BlockKind::CyanShulkerBox => 0, + BlockKind::PurpleShulkerBox => 0, + BlockKind::BlueShulkerBox => 0, + BlockKind::BrownShulkerBox => 0, + BlockKind::GreenShulkerBox => 0, + BlockKind::RedShulkerBox => 0, + BlockKind::BlackShulkerBox => 0, + BlockKind::WhiteGlazedTerracotta => 15, + BlockKind::OrangeGlazedTerracotta => 15, + BlockKind::MagentaGlazedTerracotta => 15, + BlockKind::LightBlueGlazedTerracotta => 15, + BlockKind::YellowGlazedTerracotta => 15, + BlockKind::LimeGlazedTerracotta => 15, + BlockKind::PinkGlazedTerracotta => 15, + BlockKind::GrayGlazedTerracotta => 15, + BlockKind::LightGrayGlazedTerracotta => 15, + BlockKind::CyanGlazedTerracotta => 15, + BlockKind::PurpleGlazedTerracotta => 15, + BlockKind::BlueGlazedTerracotta => 15, + BlockKind::BrownGlazedTerracotta => 15, + BlockKind::GreenGlazedTerracotta => 15, + BlockKind::RedGlazedTerracotta => 15, + BlockKind::BlackGlazedTerracotta => 15, + BlockKind::WhiteConcrete => 15, + BlockKind::OrangeConcrete => 15, + BlockKind::MagentaConcrete => 15, + BlockKind::LightBlueConcrete => 15, + BlockKind::YellowConcrete => 15, + BlockKind::LimeConcrete => 15, + BlockKind::PinkConcrete => 15, + BlockKind::GrayConcrete => 15, + BlockKind::LightGrayConcrete => 15, + BlockKind::CyanConcrete => 15, + BlockKind::PurpleConcrete => 15, + BlockKind::BlueConcrete => 15, + BlockKind::BrownConcrete => 15, + BlockKind::GreenConcrete => 15, + BlockKind::RedConcrete => 15, + BlockKind::BlackConcrete => 15, + BlockKind::WhiteConcretePowder => 15, + BlockKind::OrangeConcretePowder => 15, + BlockKind::MagentaConcretePowder => 15, + BlockKind::LightBlueConcretePowder => 15, + BlockKind::YellowConcretePowder => 15, + BlockKind::LimeConcretePowder => 15, + BlockKind::PinkConcretePowder => 15, + BlockKind::GrayConcretePowder => 15, + BlockKind::LightGrayConcretePowder => 15, + BlockKind::CyanConcretePowder => 15, + BlockKind::PurpleConcretePowder => 15, + BlockKind::BlueConcretePowder => 15, + BlockKind::BrownConcretePowder => 15, + BlockKind::GreenConcretePowder => 15, + BlockKind::RedConcretePowder => 15, + BlockKind::BlackConcretePowder => 15, + BlockKind::Kelp => 0, + BlockKind::KelpPlant => 0, + BlockKind::DriedKelpBlock => 15, + BlockKind::TurtleEgg => 15, + BlockKind::DeadTubeCoralBlock => 15, + BlockKind::DeadBrainCoralBlock => 15, + BlockKind::DeadBubbleCoralBlock => 15, + BlockKind::DeadFireCoralBlock => 15, + BlockKind::DeadHornCoralBlock => 15, + BlockKind::TubeCoralBlock => 15, + BlockKind::BrainCoralBlock => 15, + BlockKind::BubbleCoralBlock => 15, + BlockKind::FireCoralBlock => 15, + BlockKind::HornCoralBlock => 15, + BlockKind::DeadTubeCoral => 0, + BlockKind::DeadBrainCoral => 0, + BlockKind::DeadBubbleCoral => 0, + BlockKind::DeadFireCoral => 0, + BlockKind::DeadHornCoral => 0, + BlockKind::TubeCoral => 0, + BlockKind::BrainCoral => 0, + BlockKind::BubbleCoral => 0, + BlockKind::FireCoral => 0, + BlockKind::HornCoral => 0, + BlockKind::DeadTubeCoralFan => 0, + BlockKind::DeadBrainCoralFan => 0, + BlockKind::DeadBubbleCoralFan => 0, + BlockKind::DeadFireCoralFan => 0, + BlockKind::DeadHornCoralFan => 0, + BlockKind::TubeCoralFan => 0, + BlockKind::BrainCoralFan => 0, + BlockKind::BubbleCoralFan => 0, + BlockKind::FireCoralFan => 0, + BlockKind::HornCoralFan => 0, + BlockKind::DeadTubeCoralWallFan => 0, + BlockKind::DeadBrainCoralWallFan => 0, + BlockKind::DeadBubbleCoralWallFan => 0, + BlockKind::DeadFireCoralWallFan => 0, + BlockKind::DeadHornCoralWallFan => 0, + BlockKind::TubeCoralWallFan => 0, + BlockKind::BrainCoralWallFan => 0, + BlockKind::BubbleCoralWallFan => 0, + BlockKind::FireCoralWallFan => 0, + BlockKind::HornCoralWallFan => 0, + BlockKind::SeaPickle => 15, + BlockKind::BlueIce => 15, + BlockKind::Conduit => 15, + BlockKind::BambooSapling => 15, + BlockKind::Bamboo => 15, + BlockKind::PottedBamboo => 0, + BlockKind::VoidAir => 0, + BlockKind::CaveAir => 0, + BlockKind::BubbleColumn => 0, + BlockKind::PolishedGraniteStairs => 15, + BlockKind::SmoothRedSandstoneStairs => 15, + BlockKind::MossyStoneBrickStairs => 15, + BlockKind::PolishedDioriteStairs => 15, + BlockKind::MossyCobblestoneStairs => 15, + BlockKind::EndStoneBrickStairs => 15, + BlockKind::StoneStairs => 15, + BlockKind::SmoothSandstoneStairs => 15, + BlockKind::SmoothQuartzStairs => 15, + BlockKind::GraniteStairs => 15, + BlockKind::AndesiteStairs => 15, + BlockKind::RedNetherBrickStairs => 15, + BlockKind::PolishedAndesiteStairs => 15, + BlockKind::DioriteStairs => 15, + BlockKind::PolishedGraniteSlab => 0, + BlockKind::SmoothRedSandstoneSlab => 0, + BlockKind::MossyStoneBrickSlab => 0, + BlockKind::PolishedDioriteSlab => 0, + BlockKind::MossyCobblestoneSlab => 0, + BlockKind::EndStoneBrickSlab => 0, + BlockKind::SmoothSandstoneSlab => 0, + BlockKind::SmoothQuartzSlab => 0, + BlockKind::GraniteSlab => 0, + BlockKind::AndesiteSlab => 0, + BlockKind::RedNetherBrickSlab => 0, + BlockKind::PolishedAndesiteSlab => 0, + BlockKind::DioriteSlab => 0, + BlockKind::BrickWall => 0, + BlockKind::PrismarineWall => 0, + BlockKind::RedSandstoneWall => 0, + BlockKind::MossyStoneBrickWall => 0, + BlockKind::GraniteWall => 0, + BlockKind::StoneBrickWall => 0, + BlockKind::NetherBrickWall => 0, + BlockKind::AndesiteWall => 0, + BlockKind::RedNetherBrickWall => 0, + BlockKind::SandstoneWall => 0, + BlockKind::EndStoneBrickWall => 0, + BlockKind::DioriteWall => 0, + BlockKind::Scaffolding => 15, + BlockKind::Loom => 15, + BlockKind::Barrel => 0, + BlockKind::Smoker => 15, + BlockKind::BlastFurnace => 15, + BlockKind::CartographyTable => 15, + BlockKind::FletchingTable => 15, + BlockKind::Grindstone => 0, + BlockKind::Lectern => 15, + BlockKind::SmithingTable => 15, + BlockKind::Stonecutter => 15, + BlockKind::Bell => 0, + BlockKind::Lantern => 0, + BlockKind::SoulLantern => 0, + BlockKind::Campfire => 15, + BlockKind::SoulCampfire => 15, + BlockKind::SweetBerryBush => 0, + BlockKind::WarpedStem => 15, + BlockKind::StrippedWarpedStem => 15, + BlockKind::WarpedHyphae => 15, + BlockKind::StrippedWarpedHyphae => 15, + BlockKind::WarpedNylium => 15, + BlockKind::WarpedFungus => 0, + BlockKind::WarpedWartBlock => 15, + BlockKind::WarpedRoots => 0, + BlockKind::NetherSprouts => 0, + BlockKind::CrimsonStem => 15, + BlockKind::StrippedCrimsonStem => 15, + BlockKind::CrimsonHyphae => 15, + BlockKind::StrippedCrimsonHyphae => 15, + BlockKind::CrimsonNylium => 15, + BlockKind::CrimsonFungus => 0, + BlockKind::Shroomlight => 15, + BlockKind::WeepingVines => 0, + BlockKind::WeepingVinesPlant => 0, + BlockKind::TwistingVines => 0, + BlockKind::TwistingVinesPlant => 0, + BlockKind::CrimsonRoots => 0, + BlockKind::CrimsonPlanks => 15, + BlockKind::WarpedPlanks => 15, + BlockKind::CrimsonSlab => 15, + BlockKind::WarpedSlab => 15, + BlockKind::CrimsonPressurePlate => 0, + BlockKind::WarpedPressurePlate => 0, + BlockKind::CrimsonFence => 0, + BlockKind::WarpedFence => 0, + BlockKind::CrimsonTrapdoor => 0, + BlockKind::WarpedTrapdoor => 0, + BlockKind::CrimsonFenceGate => 0, + BlockKind::WarpedFenceGate => 0, + BlockKind::CrimsonStairs => 15, + BlockKind::WarpedStairs => 15, + BlockKind::CrimsonButton => 0, + BlockKind::WarpedButton => 0, + BlockKind::CrimsonDoor => 0, + BlockKind::WarpedDoor => 0, + BlockKind::CrimsonSign => 0, + BlockKind::WarpedSign => 0, + BlockKind::CrimsonWallSign => 0, + BlockKind::WarpedWallSign => 0, + BlockKind::StructureBlock => 15, + BlockKind::Jigsaw => 15, + BlockKind::Composter => 0, + BlockKind::Target => 15, + BlockKind::BeeNest => 15, + BlockKind::Beehive => 15, + BlockKind::HoneyBlock => 15, + BlockKind::HoneycombBlock => 15, + BlockKind::NetheriteBlock => 15, + BlockKind::AncientDebris => 15, + BlockKind::CryingObsidian => 15, + BlockKind::RespawnAnchor => 15, + BlockKind::PottedCrimsonFungus => 0, + BlockKind::PottedWarpedFungus => 0, + BlockKind::PottedCrimsonRoots => 0, + BlockKind::PottedWarpedRoots => 0, + BlockKind::Lodestone => 15, + BlockKind::Blackstone => 15, + BlockKind::BlackstoneStairs => 15, + BlockKind::BlackstoneWall => 0, + BlockKind::BlackstoneSlab => 15, + BlockKind::PolishedBlackstone => 15, + BlockKind::PolishedBlackstoneBricks => 15, + BlockKind::CrackedPolishedBlackstoneBricks => 15, + BlockKind::ChiseledPolishedBlackstone => 15, + BlockKind::PolishedBlackstoneBrickSlab => 15, + BlockKind::PolishedBlackstoneBrickStairs => 15, + BlockKind::PolishedBlackstoneBrickWall => 0, + BlockKind::GildedBlackstone => 15, + BlockKind::PolishedBlackstoneStairs => 15, + BlockKind::PolishedBlackstoneSlab => 15, + BlockKind::PolishedBlackstonePressurePlate => 0, + BlockKind::PolishedBlackstoneButton => 0, + BlockKind::PolishedBlackstoneWall => 0, + BlockKind::ChiseledNetherBricks => 15, + BlockKind::CrackedNetherBricks => 15, + BlockKind::QuartzBricks => 15, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `solid` property of this `BlockKind`. + pub fn solid(&self) -> bool { + match self { + BlockKind::Air => false, + BlockKind::Stone => true, + BlockKind::Granite => true, + BlockKind::PolishedGranite => true, + BlockKind::Diorite => true, + BlockKind::PolishedDiorite => true, + BlockKind::Andesite => true, + BlockKind::PolishedAndesite => true, + BlockKind::GrassBlock => true, + BlockKind::Dirt => true, + BlockKind::CoarseDirt => true, + BlockKind::Podzol => true, + BlockKind::Cobblestone => true, + BlockKind::OakPlanks => true, + BlockKind::SprucePlanks => true, + BlockKind::BirchPlanks => true, + BlockKind::JunglePlanks => true, + BlockKind::AcaciaPlanks => true, + BlockKind::DarkOakPlanks => true, + BlockKind::OakSapling => false, + BlockKind::SpruceSapling => false, + BlockKind::BirchSapling => false, + BlockKind::JungleSapling => false, + BlockKind::AcaciaSapling => false, + BlockKind::DarkOakSapling => false, + BlockKind::Bedrock => true, + BlockKind::Water => false, + BlockKind::Lava => false, + BlockKind::Sand => true, + BlockKind::RedSand => true, + BlockKind::Gravel => true, + BlockKind::GoldOre => true, + BlockKind::IronOre => true, + BlockKind::CoalOre => true, + BlockKind::NetherGoldOre => true, + BlockKind::OakLog => true, + BlockKind::SpruceLog => true, + BlockKind::BirchLog => true, + BlockKind::JungleLog => true, + BlockKind::AcaciaLog => true, + BlockKind::DarkOakLog => true, + BlockKind::StrippedSpruceLog => true, + BlockKind::StrippedBirchLog => true, + BlockKind::StrippedJungleLog => true, + BlockKind::StrippedAcaciaLog => true, + BlockKind::StrippedDarkOakLog => true, + BlockKind::StrippedOakLog => true, + BlockKind::OakWood => true, + BlockKind::SpruceWood => true, + BlockKind::BirchWood => true, + BlockKind::JungleWood => true, + BlockKind::AcaciaWood => true, + BlockKind::DarkOakWood => true, + BlockKind::StrippedOakWood => true, + BlockKind::StrippedSpruceWood => true, + BlockKind::StrippedBirchWood => true, + BlockKind::StrippedJungleWood => true, + BlockKind::StrippedAcaciaWood => true, + BlockKind::StrippedDarkOakWood => true, + BlockKind::OakLeaves => true, + BlockKind::SpruceLeaves => true, + BlockKind::BirchLeaves => true, + BlockKind::JungleLeaves => true, + BlockKind::AcaciaLeaves => true, + BlockKind::DarkOakLeaves => true, + BlockKind::Sponge => true, + BlockKind::WetSponge => true, + BlockKind::Glass => true, + BlockKind::LapisOre => true, + BlockKind::LapisBlock => true, + BlockKind::Dispenser => true, + BlockKind::Sandstone => true, + BlockKind::ChiseledSandstone => true, + BlockKind::CutSandstone => true, + BlockKind::NoteBlock => true, + BlockKind::WhiteBed => true, + BlockKind::OrangeBed => true, + BlockKind::MagentaBed => true, + BlockKind::LightBlueBed => true, + BlockKind::YellowBed => true, + BlockKind::LimeBed => true, + BlockKind::PinkBed => true, + BlockKind::GrayBed => true, + BlockKind::LightGrayBed => true, + BlockKind::CyanBed => true, + BlockKind::PurpleBed => true, + BlockKind::BlueBed => true, + BlockKind::BrownBed => true, + BlockKind::GreenBed => true, + BlockKind::RedBed => true, + BlockKind::BlackBed => true, + BlockKind::PoweredRail => false, + BlockKind::DetectorRail => false, + BlockKind::StickyPiston => true, + BlockKind::Cobweb => false, + BlockKind::Grass => false, + BlockKind::Fern => false, + BlockKind::DeadBush => false, + BlockKind::Seagrass => false, + BlockKind::TallSeagrass => false, + BlockKind::Piston => true, + BlockKind::PistonHead => true, + BlockKind::WhiteWool => true, + BlockKind::OrangeWool => true, + BlockKind::MagentaWool => true, + BlockKind::LightBlueWool => true, + BlockKind::YellowWool => true, + BlockKind::LimeWool => true, + BlockKind::PinkWool => true, + BlockKind::GrayWool => true, + BlockKind::LightGrayWool => true, + BlockKind::CyanWool => true, + BlockKind::PurpleWool => true, + BlockKind::BlueWool => true, + BlockKind::BrownWool => true, + BlockKind::GreenWool => true, + BlockKind::RedWool => true, + BlockKind::BlackWool => true, + BlockKind::MovingPiston => false, + BlockKind::Dandelion => false, + BlockKind::Poppy => false, + BlockKind::BlueOrchid => false, + BlockKind::Allium => false, + BlockKind::AzureBluet => false, + BlockKind::RedTulip => false, + BlockKind::OrangeTulip => false, + BlockKind::WhiteTulip => false, + BlockKind::PinkTulip => false, + BlockKind::OxeyeDaisy => false, + BlockKind::Cornflower => false, + BlockKind::WitherRose => false, + BlockKind::LilyOfTheValley => false, + BlockKind::BrownMushroom => false, + BlockKind::RedMushroom => false, + BlockKind::GoldBlock => true, + BlockKind::IronBlock => true, + BlockKind::Bricks => true, + BlockKind::Tnt => true, + BlockKind::Bookshelf => true, + BlockKind::MossyCobblestone => true, + BlockKind::Obsidian => true, + BlockKind::Torch => false, + BlockKind::WallTorch => false, + BlockKind::Fire => false, + BlockKind::SoulFire => false, + BlockKind::Spawner => true, + BlockKind::OakStairs => true, + BlockKind::Chest => true, + BlockKind::RedstoneWire => false, + BlockKind::DiamondOre => true, + BlockKind::DiamondBlock => true, + BlockKind::CraftingTable => true, + BlockKind::Wheat => false, + BlockKind::Farmland => true, + BlockKind::Furnace => true, + BlockKind::OakSign => false, + BlockKind::SpruceSign => false, + BlockKind::BirchSign => false, + BlockKind::AcaciaSign => false, + BlockKind::JungleSign => false, + BlockKind::DarkOakSign => false, + BlockKind::OakDoor => true, + BlockKind::Ladder => true, + BlockKind::Rail => false, + BlockKind::CobblestoneStairs => true, + BlockKind::OakWallSign => false, + BlockKind::SpruceWallSign => false, + BlockKind::BirchWallSign => false, + BlockKind::AcaciaWallSign => false, + BlockKind::JungleWallSign => false, + BlockKind::DarkOakWallSign => false, + BlockKind::Lever => false, + BlockKind::StonePressurePlate => false, + BlockKind::IronDoor => true, + BlockKind::OakPressurePlate => false, + BlockKind::SprucePressurePlate => false, + BlockKind::BirchPressurePlate => false, + BlockKind::JunglePressurePlate => false, + BlockKind::AcaciaPressurePlate => false, + BlockKind::DarkOakPressurePlate => false, + BlockKind::RedstoneOre => true, + BlockKind::RedstoneTorch => false, + BlockKind::RedstoneWallTorch => false, + BlockKind::StoneButton => false, + BlockKind::Snow => true, + BlockKind::Ice => true, + BlockKind::SnowBlock => true, + BlockKind::Cactus => true, + BlockKind::Clay => true, + BlockKind::SugarCane => false, + BlockKind::Jukebox => true, + BlockKind::OakFence => true, + BlockKind::Pumpkin => true, + BlockKind::Netherrack => true, + BlockKind::SoulSand => true, + BlockKind::SoulSoil => true, + BlockKind::Basalt => true, + BlockKind::PolishedBasalt => true, + BlockKind::SoulTorch => false, + BlockKind::SoulWallTorch => false, + BlockKind::Glowstone => true, + BlockKind::NetherPortal => false, + BlockKind::CarvedPumpkin => true, + BlockKind::JackOLantern => true, + BlockKind::Cake => true, + BlockKind::Repeater => true, + BlockKind::WhiteStainedGlass => true, + BlockKind::OrangeStainedGlass => true, + BlockKind::MagentaStainedGlass => true, + BlockKind::LightBlueStainedGlass => true, + BlockKind::YellowStainedGlass => true, + BlockKind::LimeStainedGlass => true, + BlockKind::PinkStainedGlass => true, + BlockKind::GrayStainedGlass => true, + BlockKind::LightGrayStainedGlass => true, + BlockKind::CyanStainedGlass => true, + BlockKind::PurpleStainedGlass => true, + BlockKind::BlueStainedGlass => true, + BlockKind::BrownStainedGlass => true, + BlockKind::GreenStainedGlass => true, + BlockKind::RedStainedGlass => true, + BlockKind::BlackStainedGlass => true, + BlockKind::OakTrapdoor => true, + BlockKind::SpruceTrapdoor => true, + BlockKind::BirchTrapdoor => true, + BlockKind::JungleTrapdoor => true, + BlockKind::AcaciaTrapdoor => true, + BlockKind::DarkOakTrapdoor => true, + BlockKind::StoneBricks => true, + BlockKind::MossyStoneBricks => true, + BlockKind::CrackedStoneBricks => true, + BlockKind::ChiseledStoneBricks => true, + BlockKind::InfestedStone => true, + BlockKind::InfestedCobblestone => true, + BlockKind::InfestedStoneBricks => true, + BlockKind::InfestedMossyStoneBricks => true, + BlockKind::InfestedCrackedStoneBricks => true, + BlockKind::InfestedChiseledStoneBricks => true, + BlockKind::BrownMushroomBlock => true, + BlockKind::RedMushroomBlock => true, + BlockKind::MushroomStem => true, + BlockKind::IronBars => true, + BlockKind::Chain => true, + BlockKind::GlassPane => true, + BlockKind::Melon => true, + BlockKind::AttachedPumpkinStem => false, + BlockKind::AttachedMelonStem => false, + BlockKind::PumpkinStem => false, + BlockKind::MelonStem => false, + BlockKind::Vine => false, + BlockKind::OakFenceGate => true, + BlockKind::BrickStairs => true, + BlockKind::StoneBrickStairs => true, + BlockKind::Mycelium => true, + BlockKind::LilyPad => true, + BlockKind::NetherBricks => true, + BlockKind::NetherBrickFence => true, + BlockKind::NetherBrickStairs => true, + BlockKind::NetherWart => false, + BlockKind::EnchantingTable => true, + BlockKind::BrewingStand => true, + BlockKind::Cauldron => true, + BlockKind::EndPortal => false, + BlockKind::EndPortalFrame => true, + BlockKind::EndStone => true, + BlockKind::DragonEgg => true, + BlockKind::RedstoneLamp => true, + BlockKind::Cocoa => true, + BlockKind::SandstoneStairs => true, + BlockKind::EmeraldOre => true, + BlockKind::EnderChest => true, + BlockKind::TripwireHook => false, + BlockKind::Tripwire => false, + BlockKind::EmeraldBlock => true, + BlockKind::SpruceStairs => true, + BlockKind::BirchStairs => true, + BlockKind::JungleStairs => true, + BlockKind::CommandBlock => true, + BlockKind::Beacon => true, + BlockKind::CobblestoneWall => true, + BlockKind::MossyCobblestoneWall => true, + BlockKind::FlowerPot => true, + BlockKind::PottedOakSapling => true, + BlockKind::PottedSpruceSapling => true, + BlockKind::PottedBirchSapling => true, + BlockKind::PottedJungleSapling => true, + BlockKind::PottedAcaciaSapling => true, + BlockKind::PottedDarkOakSapling => true, + BlockKind::PottedFern => true, + BlockKind::PottedDandelion => true, + BlockKind::PottedPoppy => true, + BlockKind::PottedBlueOrchid => true, + BlockKind::PottedAllium => true, + BlockKind::PottedAzureBluet => true, + BlockKind::PottedRedTulip => true, + BlockKind::PottedOrangeTulip => true, + BlockKind::PottedWhiteTulip => true, + BlockKind::PottedPinkTulip => true, + BlockKind::PottedOxeyeDaisy => true, + BlockKind::PottedCornflower => true, + BlockKind::PottedLilyOfTheValley => true, + BlockKind::PottedWitherRose => true, + BlockKind::PottedRedMushroom => true, + BlockKind::PottedBrownMushroom => true, + BlockKind::PottedDeadBush => true, + BlockKind::PottedCactus => true, + BlockKind::Carrots => false, + BlockKind::Potatoes => false, + BlockKind::OakButton => false, + BlockKind::SpruceButton => false, + BlockKind::BirchButton => false, + BlockKind::JungleButton => false, + BlockKind::AcaciaButton => false, + BlockKind::DarkOakButton => false, + BlockKind::SkeletonSkull => true, + BlockKind::SkeletonWallSkull => true, + BlockKind::WitherSkeletonSkull => true, + BlockKind::WitherSkeletonWallSkull => true, + BlockKind::ZombieHead => true, + BlockKind::ZombieWallHead => true, + BlockKind::PlayerHead => true, + BlockKind::PlayerWallHead => true, + BlockKind::CreeperHead => true, + BlockKind::CreeperWallHead => true, + BlockKind::DragonHead => true, + BlockKind::DragonWallHead => true, + BlockKind::Anvil => true, + BlockKind::ChippedAnvil => true, + BlockKind::DamagedAnvil => true, + BlockKind::TrappedChest => true, + BlockKind::LightWeightedPressurePlate => false, + BlockKind::HeavyWeightedPressurePlate => false, + BlockKind::Comparator => true, + BlockKind::DaylightDetector => true, + BlockKind::RedstoneBlock => true, + BlockKind::NetherQuartzOre => true, + BlockKind::Hopper => true, + BlockKind::QuartzBlock => true, + BlockKind::ChiseledQuartzBlock => true, + BlockKind::QuartzPillar => true, + BlockKind::QuartzStairs => true, + BlockKind::ActivatorRail => false, + BlockKind::Dropper => true, + BlockKind::WhiteTerracotta => true, + BlockKind::OrangeTerracotta => true, + BlockKind::MagentaTerracotta => true, + BlockKind::LightBlueTerracotta => true, + BlockKind::YellowTerracotta => true, + BlockKind::LimeTerracotta => true, + BlockKind::PinkTerracotta => true, + BlockKind::GrayTerracotta => true, + BlockKind::LightGrayTerracotta => true, + BlockKind::CyanTerracotta => true, + BlockKind::PurpleTerracotta => true, + BlockKind::BlueTerracotta => true, + BlockKind::BrownTerracotta => true, + BlockKind::GreenTerracotta => true, + BlockKind::RedTerracotta => true, + BlockKind::BlackTerracotta => true, + BlockKind::WhiteStainedGlassPane => true, + BlockKind::OrangeStainedGlassPane => true, + BlockKind::MagentaStainedGlassPane => true, + BlockKind::LightBlueStainedGlassPane => true, + BlockKind::YellowStainedGlassPane => true, + BlockKind::LimeStainedGlassPane => true, + BlockKind::PinkStainedGlassPane => true, + BlockKind::GrayStainedGlassPane => true, + BlockKind::LightGrayStainedGlassPane => true, + BlockKind::CyanStainedGlassPane => true, + BlockKind::PurpleStainedGlassPane => true, + BlockKind::BlueStainedGlassPane => true, + BlockKind::BrownStainedGlassPane => true, + BlockKind::GreenStainedGlassPane => true, + BlockKind::RedStainedGlassPane => true, + BlockKind::BlackStainedGlassPane => true, + BlockKind::AcaciaStairs => true, + BlockKind::DarkOakStairs => true, + BlockKind::SlimeBlock => true, + BlockKind::Barrier => true, + BlockKind::IronTrapdoor => true, + BlockKind::Prismarine => true, + BlockKind::PrismarineBricks => true, + BlockKind::DarkPrismarine => true, + BlockKind::PrismarineStairs => true, + BlockKind::PrismarineBrickStairs => true, + BlockKind::DarkPrismarineStairs => true, + BlockKind::PrismarineSlab => true, + BlockKind::PrismarineBrickSlab => true, + BlockKind::DarkPrismarineSlab => true, + BlockKind::SeaLantern => true, + BlockKind::HayBlock => true, + BlockKind::WhiteCarpet => true, + BlockKind::OrangeCarpet => true, + BlockKind::MagentaCarpet => true, + BlockKind::LightBlueCarpet => true, + BlockKind::YellowCarpet => true, + BlockKind::LimeCarpet => true, + BlockKind::PinkCarpet => true, + BlockKind::GrayCarpet => true, + BlockKind::LightGrayCarpet => true, + BlockKind::CyanCarpet => true, + BlockKind::PurpleCarpet => true, + BlockKind::BlueCarpet => true, + BlockKind::BrownCarpet => true, + BlockKind::GreenCarpet => true, + BlockKind::RedCarpet => true, + BlockKind::BlackCarpet => true, + BlockKind::Terracotta => true, + BlockKind::CoalBlock => true, + BlockKind::PackedIce => true, + BlockKind::Sunflower => false, + BlockKind::Lilac => false, + BlockKind::RoseBush => false, + BlockKind::Peony => false, + BlockKind::TallGrass => false, + BlockKind::LargeFern => false, + BlockKind::WhiteBanner => false, + BlockKind::OrangeBanner => false, + BlockKind::MagentaBanner => false, + BlockKind::LightBlueBanner => false, + BlockKind::YellowBanner => false, + BlockKind::LimeBanner => false, + BlockKind::PinkBanner => false, + BlockKind::GrayBanner => false, + BlockKind::LightGrayBanner => false, + BlockKind::CyanBanner => false, + BlockKind::PurpleBanner => false, + BlockKind::BlueBanner => false, + BlockKind::BrownBanner => false, + BlockKind::GreenBanner => false, + BlockKind::RedBanner => false, + BlockKind::BlackBanner => false, + BlockKind::WhiteWallBanner => false, + BlockKind::OrangeWallBanner => false, + BlockKind::MagentaWallBanner => false, + BlockKind::LightBlueWallBanner => false, + BlockKind::YellowWallBanner => false, + BlockKind::LimeWallBanner => false, + BlockKind::PinkWallBanner => false, + BlockKind::GrayWallBanner => false, + BlockKind::LightGrayWallBanner => false, + BlockKind::CyanWallBanner => false, + BlockKind::PurpleWallBanner => false, + BlockKind::BlueWallBanner => false, + BlockKind::BrownWallBanner => false, + BlockKind::GreenWallBanner => false, + BlockKind::RedWallBanner => false, + BlockKind::BlackWallBanner => false, + BlockKind::RedSandstone => true, + BlockKind::ChiseledRedSandstone => true, + BlockKind::CutRedSandstone => true, + BlockKind::RedSandstoneStairs => true, + BlockKind::OakSlab => true, + BlockKind::SpruceSlab => true, + BlockKind::BirchSlab => true, + BlockKind::JungleSlab => true, + BlockKind::AcaciaSlab => true, + BlockKind::DarkOakSlab => true, + BlockKind::StoneSlab => true, + BlockKind::SmoothStoneSlab => true, + BlockKind::SandstoneSlab => true, + BlockKind::CutSandstoneSlab => true, + BlockKind::PetrifiedOakSlab => true, + BlockKind::CobblestoneSlab => true, + BlockKind::BrickSlab => true, + BlockKind::StoneBrickSlab => true, + BlockKind::NetherBrickSlab => true, + BlockKind::QuartzSlab => true, + BlockKind::RedSandstoneSlab => true, + BlockKind::CutRedSandstoneSlab => true, + BlockKind::PurpurSlab => true, + BlockKind::SmoothStone => true, + BlockKind::SmoothSandstone => true, + BlockKind::SmoothQuartz => true, + BlockKind::SmoothRedSandstone => true, + BlockKind::SpruceFenceGate => true, + BlockKind::BirchFenceGate => true, + BlockKind::JungleFenceGate => true, + BlockKind::AcaciaFenceGate => true, + BlockKind::DarkOakFenceGate => true, + BlockKind::SpruceFence => true, + BlockKind::BirchFence => true, + BlockKind::JungleFence => true, + BlockKind::AcaciaFence => true, + BlockKind::DarkOakFence => true, + BlockKind::SpruceDoor => true, + BlockKind::BirchDoor => true, + BlockKind::JungleDoor => true, + BlockKind::AcaciaDoor => true, + BlockKind::DarkOakDoor => true, + BlockKind::EndRod => true, + BlockKind::ChorusPlant => true, + BlockKind::ChorusFlower => true, + BlockKind::PurpurBlock => true, + BlockKind::PurpurPillar => true, + BlockKind::PurpurStairs => true, + BlockKind::EndStoneBricks => true, + BlockKind::Beetroots => false, + BlockKind::GrassPath => true, + BlockKind::EndGateway => false, + BlockKind::RepeatingCommandBlock => true, + BlockKind::ChainCommandBlock => true, + BlockKind::FrostedIce => true, + BlockKind::MagmaBlock => true, + BlockKind::NetherWartBlock => true, + BlockKind::RedNetherBricks => true, + BlockKind::BoneBlock => true, + BlockKind::StructureVoid => false, + BlockKind::Observer => true, + BlockKind::ShulkerBox => true, + BlockKind::WhiteShulkerBox => true, + BlockKind::OrangeShulkerBox => true, + BlockKind::MagentaShulkerBox => true, + BlockKind::LightBlueShulkerBox => true, + BlockKind::YellowShulkerBox => true, + BlockKind::LimeShulkerBox => true, + BlockKind::PinkShulkerBox => true, + BlockKind::GrayShulkerBox => true, + BlockKind::LightGrayShulkerBox => true, + BlockKind::CyanShulkerBox => true, + BlockKind::PurpleShulkerBox => true, + BlockKind::BlueShulkerBox => true, + BlockKind::BrownShulkerBox => true, + BlockKind::GreenShulkerBox => true, + BlockKind::RedShulkerBox => true, + BlockKind::BlackShulkerBox => true, + BlockKind::WhiteGlazedTerracotta => true, + BlockKind::OrangeGlazedTerracotta => true, + BlockKind::MagentaGlazedTerracotta => true, + BlockKind::LightBlueGlazedTerracotta => true, + BlockKind::YellowGlazedTerracotta => true, + BlockKind::LimeGlazedTerracotta => true, + BlockKind::PinkGlazedTerracotta => true, + BlockKind::GrayGlazedTerracotta => true, + BlockKind::LightGrayGlazedTerracotta => true, + BlockKind::CyanGlazedTerracotta => true, + BlockKind::PurpleGlazedTerracotta => true, + BlockKind::BlueGlazedTerracotta => true, + BlockKind::BrownGlazedTerracotta => true, + BlockKind::GreenGlazedTerracotta => true, + BlockKind::RedGlazedTerracotta => true, + BlockKind::BlackGlazedTerracotta => true, + BlockKind::WhiteConcrete => true, + BlockKind::OrangeConcrete => true, + BlockKind::MagentaConcrete => true, + BlockKind::LightBlueConcrete => true, + BlockKind::YellowConcrete => true, + BlockKind::LimeConcrete => true, + BlockKind::PinkConcrete => true, + BlockKind::GrayConcrete => true, + BlockKind::LightGrayConcrete => true, + BlockKind::CyanConcrete => true, + BlockKind::PurpleConcrete => true, + BlockKind::BlueConcrete => true, + BlockKind::BrownConcrete => true, + BlockKind::GreenConcrete => true, + BlockKind::RedConcrete => true, + BlockKind::BlackConcrete => true, + BlockKind::WhiteConcretePowder => true, + BlockKind::OrangeConcretePowder => true, + BlockKind::MagentaConcretePowder => true, + BlockKind::LightBlueConcretePowder => true, + BlockKind::YellowConcretePowder => true, + BlockKind::LimeConcretePowder => true, + BlockKind::PinkConcretePowder => true, + BlockKind::GrayConcretePowder => true, + BlockKind::LightGrayConcretePowder => true, + BlockKind::CyanConcretePowder => true, + BlockKind::PurpleConcretePowder => true, + BlockKind::BlueConcretePowder => true, + BlockKind::BrownConcretePowder => true, + BlockKind::GreenConcretePowder => true, + BlockKind::RedConcretePowder => true, + BlockKind::BlackConcretePowder => true, + BlockKind::Kelp => false, + BlockKind::KelpPlant => false, + BlockKind::DriedKelpBlock => true, + BlockKind::TurtleEgg => true, + BlockKind::DeadTubeCoralBlock => true, + BlockKind::DeadBrainCoralBlock => true, + BlockKind::DeadBubbleCoralBlock => true, + BlockKind::DeadFireCoralBlock => true, + BlockKind::DeadHornCoralBlock => true, + BlockKind::TubeCoralBlock => true, + BlockKind::BrainCoralBlock => true, + BlockKind::BubbleCoralBlock => true, + BlockKind::FireCoralBlock => true, + BlockKind::HornCoralBlock => true, + BlockKind::DeadTubeCoral => false, + BlockKind::DeadBrainCoral => false, + BlockKind::DeadBubbleCoral => false, + BlockKind::DeadFireCoral => false, + BlockKind::DeadHornCoral => false, + BlockKind::TubeCoral => false, + BlockKind::BrainCoral => false, + BlockKind::BubbleCoral => false, + BlockKind::FireCoral => false, + BlockKind::HornCoral => false, + BlockKind::DeadTubeCoralFan => false, + BlockKind::DeadBrainCoralFan => false, + BlockKind::DeadBubbleCoralFan => false, + BlockKind::DeadFireCoralFan => false, + BlockKind::DeadHornCoralFan => false, + BlockKind::TubeCoralFan => false, + BlockKind::BrainCoralFan => false, + BlockKind::BubbleCoralFan => false, + BlockKind::FireCoralFan => false, + BlockKind::HornCoralFan => false, + BlockKind::DeadTubeCoralWallFan => false, + BlockKind::DeadBrainCoralWallFan => false, + BlockKind::DeadBubbleCoralWallFan => false, + BlockKind::DeadFireCoralWallFan => false, + BlockKind::DeadHornCoralWallFan => false, + BlockKind::TubeCoralWallFan => false, + BlockKind::BrainCoralWallFan => false, + BlockKind::BubbleCoralWallFan => false, + BlockKind::FireCoralWallFan => false, + BlockKind::HornCoralWallFan => false, + BlockKind::SeaPickle => true, + BlockKind::BlueIce => true, + BlockKind::Conduit => true, + BlockKind::BambooSapling => false, + BlockKind::Bamboo => true, + BlockKind::PottedBamboo => true, + BlockKind::VoidAir => false, + BlockKind::CaveAir => false, + BlockKind::BubbleColumn => false, + BlockKind::PolishedGraniteStairs => true, + BlockKind::SmoothRedSandstoneStairs => true, + BlockKind::MossyStoneBrickStairs => true, + BlockKind::PolishedDioriteStairs => true, + BlockKind::MossyCobblestoneStairs => true, + BlockKind::EndStoneBrickStairs => true, + BlockKind::StoneStairs => true, + BlockKind::SmoothSandstoneStairs => true, + BlockKind::SmoothQuartzStairs => true, + BlockKind::GraniteStairs => true, + BlockKind::AndesiteStairs => true, + BlockKind::RedNetherBrickStairs => true, + BlockKind::PolishedAndesiteStairs => true, + BlockKind::DioriteStairs => true, + BlockKind::PolishedGraniteSlab => true, + BlockKind::SmoothRedSandstoneSlab => true, + BlockKind::MossyStoneBrickSlab => true, + BlockKind::PolishedDioriteSlab => true, + BlockKind::MossyCobblestoneSlab => true, + BlockKind::EndStoneBrickSlab => true, + BlockKind::SmoothSandstoneSlab => true, + BlockKind::SmoothQuartzSlab => true, + BlockKind::GraniteSlab => true, + BlockKind::AndesiteSlab => true, + BlockKind::RedNetherBrickSlab => true, + BlockKind::PolishedAndesiteSlab => true, + BlockKind::DioriteSlab => true, + BlockKind::BrickWall => true, + BlockKind::PrismarineWall => true, + BlockKind::RedSandstoneWall => true, + BlockKind::MossyStoneBrickWall => true, + BlockKind::GraniteWall => true, + BlockKind::StoneBrickWall => true, + BlockKind::NetherBrickWall => true, + BlockKind::AndesiteWall => true, + BlockKind::RedNetherBrickWall => true, + BlockKind::SandstoneWall => true, + BlockKind::EndStoneBrickWall => true, + BlockKind::DioriteWall => true, + BlockKind::Scaffolding => true, + BlockKind::Loom => true, + BlockKind::Barrel => true, + BlockKind::Smoker => true, + BlockKind::BlastFurnace => true, + BlockKind::CartographyTable => true, + BlockKind::FletchingTable => true, + BlockKind::Grindstone => true, + BlockKind::Lectern => true, + BlockKind::SmithingTable => true, + BlockKind::Stonecutter => true, + BlockKind::Bell => true, + BlockKind::Lantern => true, + BlockKind::SoulLantern => true, + BlockKind::Campfire => true, + BlockKind::SoulCampfire => true, + BlockKind::SweetBerryBush => false, + BlockKind::WarpedStem => true, + BlockKind::StrippedWarpedStem => true, + BlockKind::WarpedHyphae => true, + BlockKind::StrippedWarpedHyphae => true, + BlockKind::WarpedNylium => true, + BlockKind::WarpedFungus => false, + BlockKind::WarpedWartBlock => true, + BlockKind::WarpedRoots => false, + BlockKind::NetherSprouts => false, + BlockKind::CrimsonStem => true, + BlockKind::StrippedCrimsonStem => true, + BlockKind::CrimsonHyphae => true, + BlockKind::StrippedCrimsonHyphae => true, + BlockKind::CrimsonNylium => true, + BlockKind::CrimsonFungus => false, + BlockKind::Shroomlight => true, + BlockKind::WeepingVines => false, + BlockKind::WeepingVinesPlant => false, + BlockKind::TwistingVines => false, + BlockKind::TwistingVinesPlant => false, + BlockKind::CrimsonRoots => false, + BlockKind::CrimsonPlanks => true, + BlockKind::WarpedPlanks => true, + BlockKind::CrimsonSlab => true, + BlockKind::WarpedSlab => true, + BlockKind::CrimsonPressurePlate => false, + BlockKind::WarpedPressurePlate => false, + BlockKind::CrimsonFence => true, + BlockKind::WarpedFence => true, + BlockKind::CrimsonTrapdoor => true, + BlockKind::WarpedTrapdoor => true, + BlockKind::CrimsonFenceGate => true, + BlockKind::WarpedFenceGate => true, + BlockKind::CrimsonStairs => true, + BlockKind::WarpedStairs => true, + BlockKind::CrimsonButton => false, + BlockKind::WarpedButton => false, + BlockKind::CrimsonDoor => true, + BlockKind::WarpedDoor => true, + BlockKind::CrimsonSign => false, + BlockKind::WarpedSign => false, + BlockKind::CrimsonWallSign => false, + BlockKind::WarpedWallSign => false, + BlockKind::StructureBlock => true, + BlockKind::Jigsaw => true, + BlockKind::Composter => true, + BlockKind::Target => true, + BlockKind::BeeNest => true, + BlockKind::Beehive => true, + BlockKind::HoneyBlock => true, + BlockKind::HoneycombBlock => true, + BlockKind::NetheriteBlock => true, + BlockKind::AncientDebris => true, + BlockKind::CryingObsidian => true, + BlockKind::RespawnAnchor => true, + BlockKind::PottedCrimsonFungus => true, + BlockKind::PottedWarpedFungus => true, + BlockKind::PottedCrimsonRoots => true, + BlockKind::PottedWarpedRoots => true, + BlockKind::Lodestone => true, + BlockKind::Blackstone => true, + BlockKind::BlackstoneStairs => true, + BlockKind::BlackstoneWall => true, + BlockKind::BlackstoneSlab => true, + BlockKind::PolishedBlackstone => true, + BlockKind::PolishedBlackstoneBricks => true, + BlockKind::CrackedPolishedBlackstoneBricks => true, + BlockKind::ChiseledPolishedBlackstone => true, + BlockKind::PolishedBlackstoneBrickSlab => true, + BlockKind::PolishedBlackstoneBrickStairs => true, + BlockKind::PolishedBlackstoneBrickWall => true, + BlockKind::GildedBlackstone => true, + BlockKind::PolishedBlackstoneStairs => true, + BlockKind::PolishedBlackstoneSlab => true, + BlockKind::PolishedBlackstonePressurePlate => false, + BlockKind::PolishedBlackstoneButton => false, + BlockKind::PolishedBlackstoneWall => true, + BlockKind::ChiseledNetherBricks => true, + BlockKind::CrackedNetherBricks => true, + BlockKind::QuartzBricks => true, + } + } +} +#[allow(dead_code, non_upper_case_globals)] +const DIG_MULTIPLIERS_rock: &[(libcraft_items::Item, f32)] = &[ + (libcraft_items::Item::IronPickaxe, 6.0_f32), + (libcraft_items::Item::WoodenPickaxe, 2.0_f32), + (libcraft_items::Item::StonePickaxe, 4.0_f32), + (libcraft_items::Item::DiamondPickaxe, 8.0_f32), + (libcraft_items::Item::NetheritePickaxe, 9.0_f32), + (libcraft_items::Item::GoldenPickaxe, 12.0_f32), +]; +#[allow(dead_code, non_upper_case_globals)] +const DIG_MULTIPLIERS_wood: &[(libcraft_items::Item, f32)] = &[ + (libcraft_items::Item::IronAxe, 6.0_f32), + (libcraft_items::Item::WoodenAxe, 2.0_f32), + (libcraft_items::Item::StoneAxe, 4.0_f32), + (libcraft_items::Item::DiamondAxe, 8.0_f32), + (libcraft_items::Item::NetheriteAxe, 9.0_f32), + (libcraft_items::Item::GoldenAxe, 12.0_f32), +]; +#[allow(dead_code, non_upper_case_globals)] +const DIG_MULTIPLIERS_plant: &[(libcraft_items::Item, f32)] = &[ + (libcraft_items::Item::IronAxe, 6.0_f32), + (libcraft_items::Item::IronSword, 1.5_f32), + (libcraft_items::Item::WoodenSword, 1.5_f32), + (libcraft_items::Item::WoodenAxe, 2.0_f32), + (libcraft_items::Item::StoneSword, 1.5_f32), + (libcraft_items::Item::StoneAxe, 4.0_f32), + (libcraft_items::Item::DiamondSword, 1.5_f32), + (libcraft_items::Item::DiamondAxe, 8.0_f32), + (libcraft_items::Item::NetheriteAxe, 9.0_f32), + (libcraft_items::Item::NetheriteSword, 1.5_f32), + (libcraft_items::Item::GoldenSword, 1.5_f32), + (libcraft_items::Item::GoldenAxe, 12.0_f32), +]; +#[allow(dead_code, non_upper_case_globals)] +const DIG_MULTIPLIERS_melon: &[(libcraft_items::Item, f32)] = &[ + (libcraft_items::Item::IronSword, 1.5_f32), + (libcraft_items::Item::WoodenSword, 1.5_f32), + (libcraft_items::Item::StoneSword, 1.5_f32), + (libcraft_items::Item::DiamondSword, 1.5_f32), + (libcraft_items::Item::NetheriteSword, 1.5_f32), + (libcraft_items::Item::GoldenSword, 1.5_f32), +]; +#[allow(dead_code, non_upper_case_globals)] +const DIG_MULTIPLIERS_leaves: &[(libcraft_items::Item, f32)] = &[ + (libcraft_items::Item::IronSword, 1.5_f32), + (libcraft_items::Item::WoodenSword, 1.5_f32), + (libcraft_items::Item::StoneSword, 1.5_f32), + (libcraft_items::Item::DiamondSword, 1.5_f32), + (libcraft_items::Item::GoldenSword, 1.5_f32), + (libcraft_items::Item::NetheriteSword, 1.5_f32), + (libcraft_items::Item::Shears, 6.0_f32), +]; +#[allow(dead_code, non_upper_case_globals)] +const DIG_MULTIPLIERS_dirt: &[(libcraft_items::Item, f32)] = &[ + (libcraft_items::Item::IronShovel, 6.0_f32), + (libcraft_items::Item::WoodenShovel, 2.0_f32), + (libcraft_items::Item::StoneShovel, 4.0_f32), + (libcraft_items::Item::DiamondShovel, 8.0_f32), + (libcraft_items::Item::NetheriteShovel, 9.0_f32), + (libcraft_items::Item::GoldenShovel, 12.0_f32), +]; +#[allow(dead_code, non_upper_case_globals)] +const DIG_MULTIPLIERS_web: &[(libcraft_items::Item, f32)] = &[ + (libcraft_items::Item::IronSword, 15.0_f32), + (libcraft_items::Item::WoodenSword, 15.0_f32), + (libcraft_items::Item::StoneSword, 15.0_f32), + (libcraft_items::Item::DiamondSword, 15.0_f32), + (libcraft_items::Item::GoldenSword, 15.0_f32), + (libcraft_items::Item::NetheriteSword, 15.0_f32), + (libcraft_items::Item::Shears, 15.0_f32), +]; +#[allow(dead_code, non_upper_case_globals)] +const DIG_MULTIPLIERS_wool: &[(libcraft_items::Item, f32)] = + &[(libcraft_items::Item::Shears, 4.8_f32)]; +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `dig_multipliers` property of this `BlockKind`. + pub fn dig_multipliers(&self) -> &'static [(libcraft_items::Item, f32)] { + match self { + BlockKind::Air => &[], + BlockKind::Stone => DIG_MULTIPLIERS_rock, + BlockKind::Granite => DIG_MULTIPLIERS_rock, + BlockKind::PolishedGranite => DIG_MULTIPLIERS_rock, + BlockKind::Diorite => DIG_MULTIPLIERS_rock, + BlockKind::PolishedDiorite => DIG_MULTIPLIERS_rock, + BlockKind::Andesite => DIG_MULTIPLIERS_rock, + BlockKind::PolishedAndesite => DIG_MULTIPLIERS_rock, + BlockKind::GrassBlock => DIG_MULTIPLIERS_dirt, + BlockKind::Dirt => DIG_MULTIPLIERS_dirt, + BlockKind::CoarseDirt => DIG_MULTIPLIERS_plant, + BlockKind::Podzol => DIG_MULTIPLIERS_plant, + BlockKind::Cobblestone => DIG_MULTIPLIERS_rock, + BlockKind::OakPlanks => DIG_MULTIPLIERS_wood, + BlockKind::SprucePlanks => DIG_MULTIPLIERS_wood, + BlockKind::BirchPlanks => DIG_MULTIPLIERS_wood, + BlockKind::JunglePlanks => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaPlanks => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakPlanks => DIG_MULTIPLIERS_wood, + BlockKind::OakSapling => DIG_MULTIPLIERS_plant, + BlockKind::SpruceSapling => DIG_MULTIPLIERS_plant, + BlockKind::BirchSapling => DIG_MULTIPLIERS_plant, + BlockKind::JungleSapling => DIG_MULTIPLIERS_plant, + BlockKind::AcaciaSapling => DIG_MULTIPLIERS_plant, + BlockKind::DarkOakSapling => DIG_MULTIPLIERS_plant, + BlockKind::Bedrock => &[], + BlockKind::Water => &[], + BlockKind::Lava => &[], + BlockKind::Sand => DIG_MULTIPLIERS_dirt, + BlockKind::RedSand => DIG_MULTIPLIERS_dirt, + BlockKind::Gravel => DIG_MULTIPLIERS_dirt, + BlockKind::GoldOre => DIG_MULTIPLIERS_rock, + BlockKind::IronOre => DIG_MULTIPLIERS_rock, + BlockKind::CoalOre => DIG_MULTIPLIERS_rock, + BlockKind::NetherGoldOre => DIG_MULTIPLIERS_rock, + BlockKind::OakLog => DIG_MULTIPLIERS_wood, + BlockKind::SpruceLog => DIG_MULTIPLIERS_wood, + BlockKind::BirchLog => DIG_MULTIPLIERS_wood, + BlockKind::JungleLog => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaLog => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakLog => DIG_MULTIPLIERS_wood, + BlockKind::StrippedSpruceLog => DIG_MULTIPLIERS_wood, + BlockKind::StrippedBirchLog => DIG_MULTIPLIERS_wood, + BlockKind::StrippedJungleLog => DIG_MULTIPLIERS_wood, + BlockKind::StrippedAcaciaLog => DIG_MULTIPLIERS_wood, + BlockKind::StrippedDarkOakLog => DIG_MULTIPLIERS_wood, + BlockKind::StrippedOakLog => DIG_MULTIPLIERS_wood, + BlockKind::OakWood => DIG_MULTIPLIERS_wood, + BlockKind::SpruceWood => DIG_MULTIPLIERS_wood, + BlockKind::BirchWood => DIG_MULTIPLIERS_wood, + BlockKind::JungleWood => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaWood => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakWood => DIG_MULTIPLIERS_wood, + BlockKind::StrippedOakWood => DIG_MULTIPLIERS_wood, + BlockKind::StrippedSpruceWood => DIG_MULTIPLIERS_wood, + BlockKind::StrippedBirchWood => DIG_MULTIPLIERS_wood, + BlockKind::StrippedJungleWood => DIG_MULTIPLIERS_wood, + BlockKind::StrippedAcaciaWood => DIG_MULTIPLIERS_wood, + BlockKind::StrippedDarkOakWood => DIG_MULTIPLIERS_wood, + BlockKind::OakLeaves => DIG_MULTIPLIERS_plant, + BlockKind::SpruceLeaves => DIG_MULTIPLIERS_plant, + BlockKind::BirchLeaves => DIG_MULTIPLIERS_plant, + BlockKind::JungleLeaves => DIG_MULTIPLIERS_plant, + BlockKind::AcaciaLeaves => DIG_MULTIPLIERS_plant, + BlockKind::DarkOakLeaves => DIG_MULTIPLIERS_plant, + BlockKind::Sponge => &[], + BlockKind::WetSponge => &[], + BlockKind::Glass => &[], + BlockKind::LapisOre => DIG_MULTIPLIERS_rock, + BlockKind::LapisBlock => DIG_MULTIPLIERS_rock, + BlockKind::Dispenser => DIG_MULTIPLIERS_rock, + BlockKind::Sandstone => DIG_MULTIPLIERS_rock, + BlockKind::ChiseledSandstone => DIG_MULTIPLIERS_rock, + BlockKind::CutSandstone => DIG_MULTIPLIERS_rock, + BlockKind::NoteBlock => DIG_MULTIPLIERS_wood, + BlockKind::WhiteBed => &[], + BlockKind::OrangeBed => &[], + BlockKind::MagentaBed => &[], + BlockKind::LightBlueBed => &[], + BlockKind::YellowBed => &[], + BlockKind::LimeBed => &[], + BlockKind::PinkBed => &[], + BlockKind::GrayBed => &[], + BlockKind::LightGrayBed => &[], + BlockKind::CyanBed => &[], + BlockKind::PurpleBed => &[], + BlockKind::BlueBed => &[], + BlockKind::BrownBed => &[], + BlockKind::GreenBed => &[], + BlockKind::RedBed => &[], + BlockKind::BlackBed => &[], + BlockKind::PoweredRail => DIG_MULTIPLIERS_rock, + BlockKind::DetectorRail => DIG_MULTIPLIERS_rock, + BlockKind::StickyPiston => &[], + BlockKind::Cobweb => DIG_MULTIPLIERS_web, + BlockKind::Grass => DIG_MULTIPLIERS_plant, + BlockKind::Fern => DIG_MULTIPLIERS_plant, + BlockKind::DeadBush => DIG_MULTIPLIERS_plant, + BlockKind::Seagrass => DIG_MULTIPLIERS_plant, + BlockKind::TallSeagrass => DIG_MULTIPLIERS_plant, + BlockKind::Piston => &[], + BlockKind::PistonHead => &[], + BlockKind::WhiteWool => DIG_MULTIPLIERS_wool, + BlockKind::OrangeWool => DIG_MULTIPLIERS_wool, + BlockKind::MagentaWool => DIG_MULTIPLIERS_wool, + BlockKind::LightBlueWool => DIG_MULTIPLIERS_wool, + BlockKind::YellowWool => DIG_MULTIPLIERS_wool, + BlockKind::LimeWool => DIG_MULTIPLIERS_wool, + BlockKind::PinkWool => DIG_MULTIPLIERS_wool, + BlockKind::GrayWool => DIG_MULTIPLIERS_wool, + BlockKind::LightGrayWool => DIG_MULTIPLIERS_wool, + BlockKind::CyanWool => DIG_MULTIPLIERS_wool, + BlockKind::PurpleWool => DIG_MULTIPLIERS_wool, + BlockKind::BlueWool => DIG_MULTIPLIERS_wool, + BlockKind::BrownWool => DIG_MULTIPLIERS_wool, + BlockKind::GreenWool => DIG_MULTIPLIERS_wool, + BlockKind::RedWool => DIG_MULTIPLIERS_wool, + BlockKind::BlackWool => DIG_MULTIPLIERS_wool, + BlockKind::MovingPiston => &[], + BlockKind::Dandelion => DIG_MULTIPLIERS_plant, + BlockKind::Poppy => DIG_MULTIPLIERS_plant, + BlockKind::BlueOrchid => DIG_MULTIPLIERS_plant, + BlockKind::Allium => DIG_MULTIPLIERS_plant, + BlockKind::AzureBluet => DIG_MULTIPLIERS_plant, + BlockKind::RedTulip => DIG_MULTIPLIERS_plant, + BlockKind::OrangeTulip => DIG_MULTIPLIERS_plant, + BlockKind::WhiteTulip => DIG_MULTIPLIERS_plant, + BlockKind::PinkTulip => DIG_MULTIPLIERS_plant, + BlockKind::OxeyeDaisy => DIG_MULTIPLIERS_plant, + BlockKind::Cornflower => DIG_MULTIPLIERS_plant, + BlockKind::WitherRose => DIG_MULTIPLIERS_plant, + BlockKind::LilyOfTheValley => DIG_MULTIPLIERS_plant, + BlockKind::BrownMushroom => DIG_MULTIPLIERS_plant, + BlockKind::RedMushroom => DIG_MULTIPLIERS_plant, + BlockKind::GoldBlock => DIG_MULTIPLIERS_rock, + BlockKind::IronBlock => DIG_MULTIPLIERS_rock, + BlockKind::Bricks => DIG_MULTIPLIERS_rock, + BlockKind::Tnt => &[], + BlockKind::Bookshelf => DIG_MULTIPLIERS_wood, + BlockKind::MossyCobblestone => DIG_MULTIPLIERS_rock, + BlockKind::Obsidian => DIG_MULTIPLIERS_rock, + BlockKind::Torch => &[], + BlockKind::WallTorch => &[], + BlockKind::Fire => &[], + BlockKind::SoulFire => &[], + BlockKind::Spawner => DIG_MULTIPLIERS_rock, + BlockKind::OakStairs => DIG_MULTIPLIERS_wood, + BlockKind::Chest => DIG_MULTIPLIERS_wood, + BlockKind::RedstoneWire => &[], + BlockKind::DiamondOre => DIG_MULTIPLIERS_rock, + BlockKind::DiamondBlock => DIG_MULTIPLIERS_rock, + BlockKind::CraftingTable => DIG_MULTIPLIERS_wood, + BlockKind::Wheat => DIG_MULTIPLIERS_plant, + BlockKind::Farmland => DIG_MULTIPLIERS_dirt, + BlockKind::Furnace => DIG_MULTIPLIERS_rock, + BlockKind::OakSign => DIG_MULTIPLIERS_wood, + BlockKind::SpruceSign => DIG_MULTIPLIERS_wood, + BlockKind::BirchSign => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaSign => DIG_MULTIPLIERS_wood, + BlockKind::JungleSign => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakSign => DIG_MULTIPLIERS_wood, + BlockKind::OakDoor => DIG_MULTIPLIERS_wood, + BlockKind::Ladder => &[], + BlockKind::Rail => DIG_MULTIPLIERS_rock, + BlockKind::CobblestoneStairs => DIG_MULTIPLIERS_rock, + BlockKind::OakWallSign => DIG_MULTIPLIERS_wood, + BlockKind::SpruceWallSign => DIG_MULTIPLIERS_wood, + BlockKind::BirchWallSign => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaWallSign => DIG_MULTIPLIERS_wood, + BlockKind::JungleWallSign => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakWallSign => DIG_MULTIPLIERS_wood, + BlockKind::Lever => &[], + BlockKind::StonePressurePlate => DIG_MULTIPLIERS_rock, + BlockKind::IronDoor => DIG_MULTIPLIERS_rock, + BlockKind::OakPressurePlate => DIG_MULTIPLIERS_wood, + BlockKind::SprucePressurePlate => DIG_MULTIPLIERS_wood, + BlockKind::BirchPressurePlate => DIG_MULTIPLIERS_wood, + BlockKind::JunglePressurePlate => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaPressurePlate => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakPressurePlate => DIG_MULTIPLIERS_wood, + BlockKind::RedstoneOre => DIG_MULTIPLIERS_rock, + BlockKind::RedstoneTorch => &[], + BlockKind::RedstoneWallTorch => &[], + BlockKind::StoneButton => DIG_MULTIPLIERS_rock, + BlockKind::Snow => DIG_MULTIPLIERS_dirt, + BlockKind::Ice => DIG_MULTIPLIERS_rock, + BlockKind::SnowBlock => DIG_MULTIPLIERS_dirt, + BlockKind::Cactus => DIG_MULTIPLIERS_plant, + BlockKind::Clay => DIG_MULTIPLIERS_dirt, + BlockKind::SugarCane => DIG_MULTIPLIERS_plant, + BlockKind::Jukebox => DIG_MULTIPLIERS_wood, + BlockKind::OakFence => DIG_MULTIPLIERS_wood, + BlockKind::Pumpkin => DIG_MULTIPLIERS_plant, + BlockKind::Netherrack => DIG_MULTIPLIERS_rock, + BlockKind::SoulSand => DIG_MULTIPLIERS_dirt, + BlockKind::SoulSoil => DIG_MULTIPLIERS_dirt, + BlockKind::Basalt => DIG_MULTIPLIERS_rock, + BlockKind::PolishedBasalt => DIG_MULTIPLIERS_rock, + BlockKind::SoulTorch => &[], + BlockKind::SoulWallTorch => &[], + BlockKind::Glowstone => &[], + BlockKind::NetherPortal => &[], + BlockKind::CarvedPumpkin => DIG_MULTIPLIERS_plant, + BlockKind::JackOLantern => DIG_MULTIPLIERS_plant, + BlockKind::Cake => &[], + BlockKind::Repeater => &[], + BlockKind::WhiteStainedGlass => &[], + BlockKind::OrangeStainedGlass => &[], + BlockKind::MagentaStainedGlass => &[], + BlockKind::LightBlueStainedGlass => &[], + BlockKind::YellowStainedGlass => &[], + BlockKind::LimeStainedGlass => &[], + BlockKind::PinkStainedGlass => &[], + BlockKind::GrayStainedGlass => &[], + BlockKind::LightGrayStainedGlass => &[], + BlockKind::CyanStainedGlass => &[], + BlockKind::PurpleStainedGlass => &[], + BlockKind::BlueStainedGlass => &[], + BlockKind::BrownStainedGlass => &[], + BlockKind::GreenStainedGlass => &[], + BlockKind::RedStainedGlass => &[], + BlockKind::BlackStainedGlass => &[], + BlockKind::OakTrapdoor => DIG_MULTIPLIERS_wood, + BlockKind::SpruceTrapdoor => DIG_MULTIPLIERS_wood, + BlockKind::BirchTrapdoor => DIG_MULTIPLIERS_wood, + BlockKind::JungleTrapdoor => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaTrapdoor => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakTrapdoor => DIG_MULTIPLIERS_wood, + BlockKind::StoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::MossyStoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::CrackedStoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::ChiseledStoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::InfestedStone => DIG_MULTIPLIERS_rock, + BlockKind::InfestedCobblestone => DIG_MULTIPLIERS_rock, + BlockKind::InfestedStoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::InfestedMossyStoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::InfestedCrackedStoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::InfestedChiseledStoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::BrownMushroomBlock => DIG_MULTIPLIERS_wood, + BlockKind::RedMushroomBlock => DIG_MULTIPLIERS_wood, + BlockKind::MushroomStem => DIG_MULTIPLIERS_wood, + BlockKind::IronBars => DIG_MULTIPLIERS_rock, + BlockKind::Chain => DIG_MULTIPLIERS_rock, + BlockKind::GlassPane => &[], + BlockKind::Melon => DIG_MULTIPLIERS_plant, + BlockKind::AttachedPumpkinStem => DIG_MULTIPLIERS_plant, + BlockKind::AttachedMelonStem => DIG_MULTIPLIERS_plant, + BlockKind::PumpkinStem => DIG_MULTIPLIERS_plant, + BlockKind::MelonStem => DIG_MULTIPLIERS_plant, + BlockKind::Vine => DIG_MULTIPLIERS_plant, + BlockKind::OakFenceGate => DIG_MULTIPLIERS_wood, + BlockKind::BrickStairs => DIG_MULTIPLIERS_rock, + BlockKind::StoneBrickStairs => DIG_MULTIPLIERS_rock, + BlockKind::Mycelium => DIG_MULTIPLIERS_dirt, + BlockKind::LilyPad => DIG_MULTIPLIERS_plant, + BlockKind::NetherBricks => DIG_MULTIPLIERS_rock, + BlockKind::NetherBrickFence => DIG_MULTIPLIERS_rock, + BlockKind::NetherBrickStairs => DIG_MULTIPLIERS_rock, + BlockKind::NetherWart => DIG_MULTIPLIERS_plant, + BlockKind::EnchantingTable => DIG_MULTIPLIERS_rock, + BlockKind::BrewingStand => DIG_MULTIPLIERS_rock, + BlockKind::Cauldron => DIG_MULTIPLIERS_rock, + BlockKind::EndPortal => &[], + BlockKind::EndPortalFrame => &[], + BlockKind::EndStone => DIG_MULTIPLIERS_rock, + BlockKind::DragonEgg => &[], + BlockKind::RedstoneLamp => &[], + BlockKind::Cocoa => DIG_MULTIPLIERS_plant, + BlockKind::SandstoneStairs => DIG_MULTIPLIERS_rock, + BlockKind::EmeraldOre => DIG_MULTIPLIERS_rock, + BlockKind::EnderChest => DIG_MULTIPLIERS_rock, + BlockKind::TripwireHook => &[], + BlockKind::Tripwire => &[], + BlockKind::EmeraldBlock => DIG_MULTIPLIERS_rock, + BlockKind::SpruceStairs => DIG_MULTIPLIERS_wood, + BlockKind::BirchStairs => DIG_MULTIPLIERS_wood, + BlockKind::JungleStairs => DIG_MULTIPLIERS_wood, + BlockKind::CommandBlock => &[], + BlockKind::Beacon => &[], + BlockKind::CobblestoneWall => DIG_MULTIPLIERS_rock, + BlockKind::MossyCobblestoneWall => DIG_MULTIPLIERS_rock, + BlockKind::FlowerPot => &[], + BlockKind::PottedOakSapling => &[], + BlockKind::PottedSpruceSapling => &[], + BlockKind::PottedBirchSapling => &[], + BlockKind::PottedJungleSapling => &[], + BlockKind::PottedAcaciaSapling => &[], + BlockKind::PottedDarkOakSapling => &[], + BlockKind::PottedFern => &[], + BlockKind::PottedDandelion => DIG_MULTIPLIERS_plant, + BlockKind::PottedPoppy => &[], + BlockKind::PottedBlueOrchid => &[], + BlockKind::PottedAllium => &[], + BlockKind::PottedAzureBluet => &[], + BlockKind::PottedRedTulip => &[], + BlockKind::PottedOrangeTulip => &[], + BlockKind::PottedWhiteTulip => &[], + BlockKind::PottedPinkTulip => &[], + BlockKind::PottedOxeyeDaisy => &[], + BlockKind::PottedCornflower => &[], + BlockKind::PottedLilyOfTheValley => &[], + BlockKind::PottedWitherRose => &[], + BlockKind::PottedRedMushroom => &[], + BlockKind::PottedBrownMushroom => &[], + BlockKind::PottedDeadBush => &[], + BlockKind::PottedCactus => &[], + BlockKind::Carrots => DIG_MULTIPLIERS_plant, + BlockKind::Potatoes => DIG_MULTIPLIERS_plant, + BlockKind::OakButton => DIG_MULTIPLIERS_wood, + BlockKind::SpruceButton => DIG_MULTIPLIERS_wood, + BlockKind::BirchButton => DIG_MULTIPLIERS_wood, + BlockKind::JungleButton => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaButton => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakButton => DIG_MULTIPLIERS_wood, + BlockKind::SkeletonSkull => &[], + BlockKind::SkeletonWallSkull => &[], + BlockKind::WitherSkeletonSkull => &[], + BlockKind::WitherSkeletonWallSkull => &[], + BlockKind::ZombieHead => &[], + BlockKind::ZombieWallHead => &[], + BlockKind::PlayerHead => &[], + BlockKind::PlayerWallHead => &[], + BlockKind::CreeperHead => &[], + BlockKind::CreeperWallHead => &[], + BlockKind::DragonHead => &[], + BlockKind::DragonWallHead => &[], + BlockKind::Anvil => DIG_MULTIPLIERS_rock, + BlockKind::ChippedAnvil => DIG_MULTIPLIERS_rock, + BlockKind::DamagedAnvil => DIG_MULTIPLIERS_rock, + BlockKind::TrappedChest => DIG_MULTIPLIERS_wood, + BlockKind::LightWeightedPressurePlate => DIG_MULTIPLIERS_rock, + BlockKind::HeavyWeightedPressurePlate => DIG_MULTIPLIERS_rock, + BlockKind::Comparator => &[], + BlockKind::DaylightDetector => DIG_MULTIPLIERS_wood, + BlockKind::RedstoneBlock => DIG_MULTIPLIERS_rock, + BlockKind::NetherQuartzOre => DIG_MULTIPLIERS_rock, + BlockKind::Hopper => DIG_MULTIPLIERS_rock, + BlockKind::QuartzBlock => DIG_MULTIPLIERS_rock, + BlockKind::ChiseledQuartzBlock => DIG_MULTIPLIERS_rock, + BlockKind::QuartzPillar => DIG_MULTIPLIERS_rock, + BlockKind::QuartzStairs => DIG_MULTIPLIERS_rock, + BlockKind::ActivatorRail => DIG_MULTIPLIERS_rock, + BlockKind::Dropper => DIG_MULTIPLIERS_rock, + BlockKind::WhiteTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::OrangeTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::MagentaTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::LightBlueTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::YellowTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::LimeTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::PinkTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::GrayTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::LightGrayTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::CyanTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::PurpleTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::BlueTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::BrownTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::GreenTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::RedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::BlackTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::WhiteStainedGlassPane => &[], + BlockKind::OrangeStainedGlassPane => &[], + BlockKind::MagentaStainedGlassPane => &[], + BlockKind::LightBlueStainedGlassPane => &[], + BlockKind::YellowStainedGlassPane => &[], + BlockKind::LimeStainedGlassPane => &[], + BlockKind::PinkStainedGlassPane => &[], + BlockKind::GrayStainedGlassPane => &[], + BlockKind::LightGrayStainedGlassPane => &[], + BlockKind::CyanStainedGlassPane => &[], + BlockKind::PurpleStainedGlassPane => &[], + BlockKind::BlueStainedGlassPane => &[], + BlockKind::BrownStainedGlassPane => &[], + BlockKind::GreenStainedGlassPane => &[], + BlockKind::RedStainedGlassPane => &[], + BlockKind::BlackStainedGlassPane => &[], + BlockKind::AcaciaStairs => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakStairs => DIG_MULTIPLIERS_wood, + BlockKind::SlimeBlock => &[], + BlockKind::Barrier => &[], + BlockKind::IronTrapdoor => DIG_MULTIPLIERS_rock, + BlockKind::Prismarine => DIG_MULTIPLIERS_rock, + BlockKind::PrismarineBricks => DIG_MULTIPLIERS_rock, + BlockKind::DarkPrismarine => DIG_MULTIPLIERS_rock, + BlockKind::PrismarineStairs => DIG_MULTIPLIERS_rock, + BlockKind::PrismarineBrickStairs => DIG_MULTIPLIERS_rock, + BlockKind::DarkPrismarineStairs => DIG_MULTIPLIERS_rock, + BlockKind::PrismarineSlab => DIG_MULTIPLIERS_rock, + BlockKind::PrismarineBrickSlab => DIG_MULTIPLIERS_rock, + BlockKind::DarkPrismarineSlab => DIG_MULTIPLIERS_rock, + BlockKind::SeaLantern => &[], + BlockKind::HayBlock => &[], + BlockKind::WhiteCarpet => &[], + BlockKind::OrangeCarpet => &[], + BlockKind::MagentaCarpet => &[], + BlockKind::LightBlueCarpet => &[], + BlockKind::YellowCarpet => &[], + BlockKind::LimeCarpet => &[], + BlockKind::PinkCarpet => &[], + BlockKind::GrayCarpet => &[], + BlockKind::LightGrayCarpet => &[], + BlockKind::CyanCarpet => &[], + BlockKind::PurpleCarpet => &[], + BlockKind::BlueCarpet => &[], + BlockKind::BrownCarpet => &[], + BlockKind::GreenCarpet => &[], + BlockKind::RedCarpet => &[], + BlockKind::BlackCarpet => &[], + BlockKind::Terracotta => DIG_MULTIPLIERS_rock, + BlockKind::CoalBlock => DIG_MULTIPLIERS_rock, + BlockKind::PackedIce => DIG_MULTIPLIERS_rock, + BlockKind::Sunflower => DIG_MULTIPLIERS_plant, + BlockKind::Lilac => DIG_MULTIPLIERS_plant, + BlockKind::RoseBush => DIG_MULTIPLIERS_plant, + BlockKind::Peony => DIG_MULTIPLIERS_rock, + BlockKind::TallGrass => DIG_MULTIPLIERS_plant, + BlockKind::LargeFern => DIG_MULTIPLIERS_plant, + BlockKind::WhiteBanner => DIG_MULTIPLIERS_wood, + BlockKind::OrangeBanner => DIG_MULTIPLIERS_wood, + BlockKind::MagentaBanner => DIG_MULTIPLIERS_wood, + BlockKind::LightBlueBanner => DIG_MULTIPLIERS_wood, + BlockKind::YellowBanner => DIG_MULTIPLIERS_wood, + BlockKind::LimeBanner => DIG_MULTIPLIERS_wood, + BlockKind::PinkBanner => DIG_MULTIPLIERS_wood, + BlockKind::GrayBanner => DIG_MULTIPLIERS_wood, + BlockKind::LightGrayBanner => DIG_MULTIPLIERS_wood, + BlockKind::CyanBanner => DIG_MULTIPLIERS_wood, + BlockKind::PurpleBanner => DIG_MULTIPLIERS_wood, + BlockKind::BlueBanner => DIG_MULTIPLIERS_wood, + BlockKind::BrownBanner => DIG_MULTIPLIERS_wood, + BlockKind::GreenBanner => DIG_MULTIPLIERS_wood, + BlockKind::RedBanner => DIG_MULTIPLIERS_wood, + BlockKind::BlackBanner => DIG_MULTIPLIERS_wood, + BlockKind::WhiteWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::OrangeWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::MagentaWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::LightBlueWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::YellowWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::LimeWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::PinkWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::GrayWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::LightGrayWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::CyanWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::PurpleWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::BlueWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::BrownWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::GreenWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::RedWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::BlackWallBanner => DIG_MULTIPLIERS_wood, + BlockKind::RedSandstone => DIG_MULTIPLIERS_rock, + BlockKind::ChiseledRedSandstone => DIG_MULTIPLIERS_rock, + BlockKind::CutRedSandstone => DIG_MULTIPLIERS_rock, + BlockKind::RedSandstoneStairs => DIG_MULTIPLIERS_rock, + BlockKind::OakSlab => DIG_MULTIPLIERS_rock, + BlockKind::SpruceSlab => DIG_MULTIPLIERS_rock, + BlockKind::BirchSlab => DIG_MULTIPLIERS_rock, + BlockKind::JungleSlab => DIG_MULTIPLIERS_rock, + BlockKind::AcaciaSlab => DIG_MULTIPLIERS_rock, + BlockKind::DarkOakSlab => DIG_MULTIPLIERS_rock, + BlockKind::StoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::SmoothStoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::SandstoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::CutSandstoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::PetrifiedOakSlab => DIG_MULTIPLIERS_rock, + BlockKind::CobblestoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::BrickSlab => DIG_MULTIPLIERS_rock, + BlockKind::StoneBrickSlab => DIG_MULTIPLIERS_rock, + BlockKind::NetherBrickSlab => DIG_MULTIPLIERS_rock, + BlockKind::QuartzSlab => DIG_MULTIPLIERS_rock, + BlockKind::RedSandstoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::CutRedSandstoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::PurpurSlab => DIG_MULTIPLIERS_rock, + BlockKind::SmoothStone => DIG_MULTIPLIERS_rock, + BlockKind::SmoothSandstone => DIG_MULTIPLIERS_rock, + BlockKind::SmoothQuartz => DIG_MULTIPLIERS_rock, + BlockKind::SmoothRedSandstone => DIG_MULTIPLIERS_rock, + BlockKind::SpruceFenceGate => DIG_MULTIPLIERS_wood, + BlockKind::BirchFenceGate => DIG_MULTIPLIERS_wood, + BlockKind::JungleFenceGate => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaFenceGate => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakFenceGate => DIG_MULTIPLIERS_wood, + BlockKind::SpruceFence => DIG_MULTIPLIERS_wood, + BlockKind::BirchFence => DIG_MULTIPLIERS_wood, + BlockKind::JungleFence => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaFence => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakFence => DIG_MULTIPLIERS_wood, + BlockKind::SpruceDoor => DIG_MULTIPLIERS_wood, + BlockKind::BirchDoor => DIG_MULTIPLIERS_wood, + BlockKind::JungleDoor => DIG_MULTIPLIERS_wood, + BlockKind::AcaciaDoor => DIG_MULTIPLIERS_wood, + BlockKind::DarkOakDoor => DIG_MULTIPLIERS_wood, + BlockKind::EndRod => &[], + BlockKind::ChorusPlant => &[], + BlockKind::ChorusFlower => &[], + BlockKind::PurpurBlock => &[], + BlockKind::PurpurPillar => &[], + BlockKind::PurpurStairs => DIG_MULTIPLIERS_rock, + BlockKind::EndStoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::Beetroots => &[], + BlockKind::GrassPath => DIG_MULTIPLIERS_dirt, + BlockKind::EndGateway => &[], + BlockKind::RepeatingCommandBlock => &[], + BlockKind::ChainCommandBlock => &[], + BlockKind::FrostedIce => &[], + BlockKind::MagmaBlock => &[], + BlockKind::NetherWartBlock => &[], + BlockKind::RedNetherBricks => &[], + BlockKind::BoneBlock => &[], + BlockKind::StructureVoid => &[], + BlockKind::Observer => &[], + BlockKind::ShulkerBox => &[], + BlockKind::WhiteShulkerBox => &[], + BlockKind::OrangeShulkerBox => &[], + BlockKind::MagentaShulkerBox => &[], + BlockKind::LightBlueShulkerBox => &[], + BlockKind::YellowShulkerBox => &[], + BlockKind::LimeShulkerBox => &[], + BlockKind::PinkShulkerBox => &[], + BlockKind::GrayShulkerBox => &[], + BlockKind::LightGrayShulkerBox => &[], + BlockKind::CyanShulkerBox => &[], + BlockKind::PurpleShulkerBox => &[], + BlockKind::BlueShulkerBox => &[], + BlockKind::BrownShulkerBox => &[], + BlockKind::GreenShulkerBox => &[], + BlockKind::RedShulkerBox => &[], + BlockKind::BlackShulkerBox => &[], + BlockKind::WhiteGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::OrangeGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::MagentaGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::LightBlueGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::YellowGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::LimeGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::PinkGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::GrayGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::LightGrayGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::CyanGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::PurpleGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::BlueGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::BrownGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::GreenGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::RedGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::BlackGlazedTerracotta => DIG_MULTIPLIERS_rock, + BlockKind::WhiteConcrete => DIG_MULTIPLIERS_rock, + BlockKind::OrangeConcrete => DIG_MULTIPLIERS_rock, + BlockKind::MagentaConcrete => DIG_MULTIPLIERS_rock, + BlockKind::LightBlueConcrete => DIG_MULTIPLIERS_rock, + BlockKind::YellowConcrete => DIG_MULTIPLIERS_rock, + BlockKind::LimeConcrete => DIG_MULTIPLIERS_rock, + BlockKind::PinkConcrete => DIG_MULTIPLIERS_rock, + BlockKind::GrayConcrete => DIG_MULTIPLIERS_rock, + BlockKind::LightGrayConcrete => DIG_MULTIPLIERS_rock, + BlockKind::CyanConcrete => DIG_MULTIPLIERS_rock, + BlockKind::PurpleConcrete => DIG_MULTIPLIERS_rock, + BlockKind::BlueConcrete => DIG_MULTIPLIERS_rock, + BlockKind::BrownConcrete => DIG_MULTIPLIERS_rock, + BlockKind::GreenConcrete => DIG_MULTIPLIERS_rock, + BlockKind::RedConcrete => DIG_MULTIPLIERS_rock, + BlockKind::BlackConcrete => DIG_MULTIPLIERS_rock, + BlockKind::WhiteConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::OrangeConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::MagentaConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::LightBlueConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::YellowConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::LimeConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::PinkConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::GrayConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::LightGrayConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::CyanConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::PurpleConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::BlueConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::BrownConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::GreenConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::RedConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::BlackConcretePowder => DIG_MULTIPLIERS_dirt, + BlockKind::Kelp => &[], + BlockKind::KelpPlant => &[], + BlockKind::DriedKelpBlock => &[], + BlockKind::TurtleEgg => &[], + BlockKind::DeadTubeCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::DeadBrainCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::DeadBubbleCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::DeadFireCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::DeadHornCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::TubeCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::BrainCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::BubbleCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::FireCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::HornCoralBlock => DIG_MULTIPLIERS_rock, + BlockKind::DeadTubeCoral => &[], + BlockKind::DeadBrainCoral => &[], + BlockKind::DeadBubbleCoral => &[], + BlockKind::DeadFireCoral => &[], + BlockKind::DeadHornCoral => &[], + BlockKind::TubeCoral => &[], + BlockKind::BrainCoral => &[], + BlockKind::BubbleCoral => &[], + BlockKind::FireCoral => &[], + BlockKind::HornCoral => &[], + BlockKind::DeadTubeCoralFan => &[], + BlockKind::DeadBrainCoralFan => &[], + BlockKind::DeadBubbleCoralFan => &[], + BlockKind::DeadFireCoralFan => &[], + BlockKind::DeadHornCoralFan => &[], + BlockKind::TubeCoralFan => &[], + BlockKind::BrainCoralFan => &[], + BlockKind::BubbleCoralFan => &[], + BlockKind::FireCoralFan => &[], + BlockKind::HornCoralFan => &[], + BlockKind::DeadTubeCoralWallFan => &[], + BlockKind::DeadBrainCoralWallFan => &[], + BlockKind::DeadBubbleCoralWallFan => &[], + BlockKind::DeadFireCoralWallFan => &[], + BlockKind::DeadHornCoralWallFan => &[], + BlockKind::TubeCoralWallFan => &[], + BlockKind::BrainCoralWallFan => &[], + BlockKind::BubbleCoralWallFan => &[], + BlockKind::FireCoralWallFan => &[], + BlockKind::HornCoralWallFan => &[], + BlockKind::SeaPickle => &[], + BlockKind::BlueIce => &[], + BlockKind::Conduit => DIG_MULTIPLIERS_rock, + BlockKind::BambooSapling => &[], + BlockKind::Bamboo => &[], + BlockKind::PottedBamboo => &[], + BlockKind::VoidAir => &[], + BlockKind::CaveAir => &[], + BlockKind::BubbleColumn => &[], + BlockKind::PolishedGraniteStairs => DIG_MULTIPLIERS_rock, + BlockKind::SmoothRedSandstoneStairs => DIG_MULTIPLIERS_rock, + BlockKind::MossyStoneBrickStairs => DIG_MULTIPLIERS_rock, + BlockKind::PolishedDioriteStairs => DIG_MULTIPLIERS_rock, + BlockKind::MossyCobblestoneStairs => DIG_MULTIPLIERS_rock, + BlockKind::EndStoneBrickStairs => DIG_MULTIPLIERS_rock, + BlockKind::StoneStairs => DIG_MULTIPLIERS_rock, + BlockKind::SmoothSandstoneStairs => DIG_MULTIPLIERS_rock, + BlockKind::SmoothQuartzStairs => DIG_MULTIPLIERS_rock, + BlockKind::GraniteStairs => DIG_MULTIPLIERS_rock, + BlockKind::AndesiteStairs => DIG_MULTIPLIERS_rock, + BlockKind::RedNetherBrickStairs => DIG_MULTIPLIERS_rock, + BlockKind::PolishedAndesiteStairs => DIG_MULTIPLIERS_rock, + BlockKind::DioriteStairs => DIG_MULTIPLIERS_rock, + BlockKind::PolishedGraniteSlab => DIG_MULTIPLIERS_rock, + BlockKind::SmoothRedSandstoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::MossyStoneBrickSlab => DIG_MULTIPLIERS_rock, + BlockKind::PolishedDioriteSlab => DIG_MULTIPLIERS_rock, + BlockKind::MossyCobblestoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::EndStoneBrickSlab => DIG_MULTIPLIERS_rock, + BlockKind::SmoothSandstoneSlab => DIG_MULTIPLIERS_rock, + BlockKind::SmoothQuartzSlab => DIG_MULTIPLIERS_rock, + BlockKind::GraniteSlab => DIG_MULTIPLIERS_rock, + BlockKind::AndesiteSlab => DIG_MULTIPLIERS_rock, + BlockKind::RedNetherBrickSlab => DIG_MULTIPLIERS_rock, + BlockKind::PolishedAndesiteSlab => DIG_MULTIPLIERS_rock, + BlockKind::DioriteSlab => DIG_MULTIPLIERS_rock, + BlockKind::BrickWall => DIG_MULTIPLIERS_rock, + BlockKind::PrismarineWall => DIG_MULTIPLIERS_rock, + BlockKind::RedSandstoneWall => DIG_MULTIPLIERS_rock, + BlockKind::MossyStoneBrickWall => DIG_MULTIPLIERS_rock, + BlockKind::GraniteWall => DIG_MULTIPLIERS_rock, + BlockKind::StoneBrickWall => DIG_MULTIPLIERS_rock, + BlockKind::NetherBrickWall => DIG_MULTIPLIERS_rock, + BlockKind::AndesiteWall => DIG_MULTIPLIERS_rock, + BlockKind::RedNetherBrickWall => DIG_MULTIPLIERS_rock, + BlockKind::SandstoneWall => DIG_MULTIPLIERS_rock, + BlockKind::EndStoneBrickWall => DIG_MULTIPLIERS_rock, + BlockKind::DioriteWall => DIG_MULTIPLIERS_rock, + BlockKind::Scaffolding => &[], + BlockKind::Loom => DIG_MULTIPLIERS_wood, + BlockKind::Barrel => DIG_MULTIPLIERS_wood, + BlockKind::Smoker => DIG_MULTIPLIERS_rock, + BlockKind::BlastFurnace => DIG_MULTIPLIERS_rock, + BlockKind::CartographyTable => DIG_MULTIPLIERS_wood, + BlockKind::FletchingTable => DIG_MULTIPLIERS_wood, + BlockKind::Grindstone => DIG_MULTIPLIERS_rock, + BlockKind::Lectern => DIG_MULTIPLIERS_wood, + BlockKind::SmithingTable => DIG_MULTIPLIERS_wood, + BlockKind::Stonecutter => DIG_MULTIPLIERS_rock, + BlockKind::Bell => DIG_MULTIPLIERS_rock, + BlockKind::Lantern => DIG_MULTIPLIERS_rock, + BlockKind::SoulLantern => DIG_MULTIPLIERS_rock, + BlockKind::Campfire => DIG_MULTIPLIERS_wood, + BlockKind::SoulCampfire => DIG_MULTIPLIERS_wood, + BlockKind::SweetBerryBush => &[], + BlockKind::WarpedStem => DIG_MULTIPLIERS_wood, + BlockKind::StrippedWarpedStem => DIG_MULTIPLIERS_wood, + BlockKind::WarpedHyphae => DIG_MULTIPLIERS_wood, + BlockKind::StrippedWarpedHyphae => DIG_MULTIPLIERS_wood, + BlockKind::WarpedNylium => DIG_MULTIPLIERS_rock, + BlockKind::WarpedFungus => &[], + BlockKind::WarpedWartBlock => &[], + BlockKind::WarpedRoots => &[], + BlockKind::NetherSprouts => DIG_MULTIPLIERS_plant, + BlockKind::CrimsonStem => DIG_MULTIPLIERS_wood, + BlockKind::StrippedCrimsonStem => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonHyphae => DIG_MULTIPLIERS_wood, + BlockKind::StrippedCrimsonHyphae => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonNylium => DIG_MULTIPLIERS_rock, + BlockKind::CrimsonFungus => &[], + BlockKind::Shroomlight => &[], + BlockKind::WeepingVines => &[], + BlockKind::WeepingVinesPlant => &[], + BlockKind::TwistingVines => &[], + BlockKind::TwistingVinesPlant => &[], + BlockKind::CrimsonRoots => &[], + BlockKind::CrimsonPlanks => DIG_MULTIPLIERS_wood, + BlockKind::WarpedPlanks => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonSlab => DIG_MULTIPLIERS_wood, + BlockKind::WarpedSlab => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonPressurePlate => DIG_MULTIPLIERS_rock, + BlockKind::WarpedPressurePlate => DIG_MULTIPLIERS_rock, + BlockKind::CrimsonFence => DIG_MULTIPLIERS_wood, + BlockKind::WarpedFence => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonTrapdoor => DIG_MULTIPLIERS_wood, + BlockKind::WarpedTrapdoor => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonFenceGate => DIG_MULTIPLIERS_wood, + BlockKind::WarpedFenceGate => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonStairs => DIG_MULTIPLIERS_wood, + BlockKind::WarpedStairs => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonButton => &[], + BlockKind::WarpedButton => &[], + BlockKind::CrimsonDoor => DIG_MULTIPLIERS_wood, + BlockKind::WarpedDoor => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonSign => DIG_MULTIPLIERS_wood, + BlockKind::WarpedSign => DIG_MULTIPLIERS_wood, + BlockKind::CrimsonWallSign => DIG_MULTIPLIERS_wood, + BlockKind::WarpedWallSign => DIG_MULTIPLIERS_wood, + BlockKind::StructureBlock => &[], + BlockKind::Jigsaw => &[], + BlockKind::Composter => DIG_MULTIPLIERS_wood, + BlockKind::Target => &[], + BlockKind::BeeNest => DIG_MULTIPLIERS_wood, + BlockKind::Beehive => DIG_MULTIPLIERS_wood, + BlockKind::HoneyBlock => &[], + BlockKind::HoneycombBlock => &[], + BlockKind::NetheriteBlock => DIG_MULTIPLIERS_rock, + BlockKind::AncientDebris => DIG_MULTIPLIERS_rock, + BlockKind::CryingObsidian => DIG_MULTIPLIERS_rock, + BlockKind::RespawnAnchor => DIG_MULTIPLIERS_rock, + BlockKind::PottedCrimsonFungus => &[], + BlockKind::PottedWarpedFungus => &[], + BlockKind::PottedCrimsonRoots => &[], + BlockKind::PottedWarpedRoots => &[], + BlockKind::Lodestone => DIG_MULTIPLIERS_rock, + BlockKind::Blackstone => DIG_MULTIPLIERS_rock, + BlockKind::BlackstoneStairs => DIG_MULTIPLIERS_wood, + BlockKind::BlackstoneWall => DIG_MULTIPLIERS_rock, + BlockKind::BlackstoneSlab => DIG_MULTIPLIERS_wood, + BlockKind::PolishedBlackstone => DIG_MULTIPLIERS_rock, + BlockKind::PolishedBlackstoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::CrackedPolishedBlackstoneBricks => DIG_MULTIPLIERS_rock, + BlockKind::ChiseledPolishedBlackstone => &[], + BlockKind::PolishedBlackstoneBrickSlab => DIG_MULTIPLIERS_wood, + BlockKind::PolishedBlackstoneBrickStairs => DIG_MULTIPLIERS_wood, + BlockKind::PolishedBlackstoneBrickWall => DIG_MULTIPLIERS_rock, + BlockKind::GildedBlackstone => DIG_MULTIPLIERS_rock, + BlockKind::PolishedBlackstoneStairs => DIG_MULTIPLIERS_wood, + BlockKind::PolishedBlackstoneSlab => DIG_MULTIPLIERS_wood, + BlockKind::PolishedBlackstonePressurePlate => DIG_MULTIPLIERS_rock, + BlockKind::PolishedBlackstoneButton => &[], + BlockKind::PolishedBlackstoneWall => DIG_MULTIPLIERS_rock, + BlockKind::ChiseledNetherBricks => DIG_MULTIPLIERS_rock, + BlockKind::CrackedNetherBricks => DIG_MULTIPLIERS_rock, + BlockKind::QuartzBricks => DIG_MULTIPLIERS_rock, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `harvest_tools` property of this `BlockKind`. + pub fn harvest_tools(&self) -> Option<&'static [libcraft_items::Item]> { + match self { + BlockKind::Air => None, + BlockKind::Stone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Granite => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedGranite => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Diorite => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedDiorite => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Andesite => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedAndesite => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GrassBlock => None, + BlockKind::Dirt => None, + BlockKind::CoarseDirt => None, + BlockKind::Podzol => None, + BlockKind::Cobblestone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OakPlanks => None, + BlockKind::SprucePlanks => None, + BlockKind::BirchPlanks => None, + BlockKind::JunglePlanks => None, + BlockKind::AcaciaPlanks => None, + BlockKind::DarkOakPlanks => None, + BlockKind::OakSapling => None, + BlockKind::SpruceSapling => None, + BlockKind::BirchSapling => None, + BlockKind::JungleSapling => None, + BlockKind::AcaciaSapling => None, + BlockKind::DarkOakSapling => None, + BlockKind::Bedrock => None, + BlockKind::Water => None, + BlockKind::Lava => None, + BlockKind::Sand => None, + BlockKind::RedSand => None, + BlockKind::Gravel => None, + BlockKind::GoldOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::IronOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CoalOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NetherGoldOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OakLog => None, + BlockKind::SpruceLog => None, + BlockKind::BirchLog => None, + BlockKind::JungleLog => None, + BlockKind::AcaciaLog => None, + BlockKind::DarkOakLog => None, + BlockKind::StrippedSpruceLog => None, + BlockKind::StrippedBirchLog => None, + BlockKind::StrippedJungleLog => None, + BlockKind::StrippedAcaciaLog => None, + BlockKind::StrippedDarkOakLog => None, + BlockKind::StrippedOakLog => None, + BlockKind::OakWood => None, + BlockKind::SpruceWood => None, + BlockKind::BirchWood => None, + BlockKind::JungleWood => None, + BlockKind::AcaciaWood => None, + BlockKind::DarkOakWood => None, + BlockKind::StrippedOakWood => None, + BlockKind::StrippedSpruceWood => None, + BlockKind::StrippedBirchWood => None, + BlockKind::StrippedJungleWood => None, + BlockKind::StrippedAcaciaWood => None, + BlockKind::StrippedDarkOakWood => None, + BlockKind::OakLeaves => None, + BlockKind::SpruceLeaves => None, + BlockKind::BirchLeaves => None, + BlockKind::JungleLeaves => None, + BlockKind::AcaciaLeaves => None, + BlockKind::DarkOakLeaves => None, + BlockKind::Sponge => None, + BlockKind::WetSponge => None, + BlockKind::Glass => None, + BlockKind::LapisOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LapisBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Dispenser => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Sandstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ChiseledSandstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CutSandstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NoteBlock => None, + BlockKind::WhiteBed => None, + BlockKind::OrangeBed => None, + BlockKind::MagentaBed => None, + BlockKind::LightBlueBed => None, + BlockKind::YellowBed => None, + BlockKind::LimeBed => None, + BlockKind::PinkBed => None, + BlockKind::GrayBed => None, + BlockKind::LightGrayBed => None, + BlockKind::CyanBed => None, + BlockKind::PurpleBed => None, + BlockKind::BlueBed => None, + BlockKind::BrownBed => None, + BlockKind::GreenBed => None, + BlockKind::RedBed => None, + BlockKind::BlackBed => None, + BlockKind::PoweredRail => None, + BlockKind::DetectorRail => None, + BlockKind::StickyPiston => None, + BlockKind::Cobweb => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronSword, + libcraft_items::Item::WoodenSword, + libcraft_items::Item::StoneSword, + libcraft_items::Item::DiamondSword, + libcraft_items::Item::GoldenSword, + libcraft_items::Item::Shears, + ]; + Some(TOOLS) + } + BlockKind::Grass => None, + BlockKind::Fern => None, + BlockKind::DeadBush => None, + BlockKind::Seagrass => None, + BlockKind::TallSeagrass => None, + BlockKind::Piston => None, + BlockKind::PistonHead => None, + BlockKind::WhiteWool => None, + BlockKind::OrangeWool => None, + BlockKind::MagentaWool => None, + BlockKind::LightBlueWool => None, + BlockKind::YellowWool => None, + BlockKind::LimeWool => None, + BlockKind::PinkWool => None, + BlockKind::GrayWool => None, + BlockKind::LightGrayWool => None, + BlockKind::CyanWool => None, + BlockKind::PurpleWool => None, + BlockKind::BlueWool => None, + BlockKind::BrownWool => None, + BlockKind::GreenWool => None, + BlockKind::RedWool => None, + BlockKind::BlackWool => None, + BlockKind::MovingPiston => None, + BlockKind::Dandelion => None, + BlockKind::Poppy => None, + BlockKind::BlueOrchid => None, + BlockKind::Allium => None, + BlockKind::AzureBluet => None, + BlockKind::RedTulip => None, + BlockKind::OrangeTulip => None, + BlockKind::WhiteTulip => None, + BlockKind::PinkTulip => None, + BlockKind::OxeyeDaisy => None, + BlockKind::Cornflower => None, + BlockKind::WitherRose => None, + BlockKind::LilyOfTheValley => None, + BlockKind::BrownMushroom => None, + BlockKind::RedMushroom => None, + BlockKind::GoldBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::IronBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Bricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Tnt => None, + BlockKind::Bookshelf => None, + BlockKind::MossyCobblestone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Obsidian => { + const TOOLS: &[libcraft_items::Item] = &[libcraft_items::Item::DiamondPickaxe]; + Some(TOOLS) + } + BlockKind::Torch => None, + BlockKind::WallTorch => None, + BlockKind::Fire => None, + BlockKind::SoulFire => None, + BlockKind::Spawner => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OakStairs => None, + BlockKind::Chest => None, + BlockKind::RedstoneWire => None, + BlockKind::DiamondOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DiamondBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CraftingTable => None, + BlockKind::Wheat => None, + BlockKind::Farmland => None, + BlockKind::Furnace => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OakSign => None, + BlockKind::SpruceSign => None, + BlockKind::BirchSign => None, + BlockKind::AcaciaSign => None, + BlockKind::JungleSign => None, + BlockKind::DarkOakSign => None, + BlockKind::OakDoor => None, + BlockKind::Ladder => None, + BlockKind::Rail => None, + BlockKind::CobblestoneStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OakWallSign => None, + BlockKind::SpruceWallSign => None, + BlockKind::BirchWallSign => None, + BlockKind::AcaciaWallSign => None, + BlockKind::JungleWallSign => None, + BlockKind::DarkOakWallSign => None, + BlockKind::Lever => None, + BlockKind::StonePressurePlate => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::IronDoor => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OakPressurePlate => None, + BlockKind::SprucePressurePlate => None, + BlockKind::BirchPressurePlate => None, + BlockKind::JunglePressurePlate => None, + BlockKind::AcaciaPressurePlate => None, + BlockKind::DarkOakPressurePlate => None, + BlockKind::RedstoneOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedstoneTorch => None, + BlockKind::RedstoneWallTorch => None, + BlockKind::StoneButton => None, + BlockKind::Snow => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronShovel, + libcraft_items::Item::WoodenShovel, + libcraft_items::Item::StoneShovel, + libcraft_items::Item::DiamondShovel, + libcraft_items::Item::GoldenShovel, + ]; + Some(TOOLS) + } + BlockKind::Ice => None, + BlockKind::SnowBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronShovel, + libcraft_items::Item::WoodenShovel, + libcraft_items::Item::StoneShovel, + libcraft_items::Item::DiamondShovel, + libcraft_items::Item::GoldenShovel, + ]; + Some(TOOLS) + } + BlockKind::Cactus => None, + BlockKind::Clay => None, + BlockKind::SugarCane => None, + BlockKind::Jukebox => None, + BlockKind::OakFence => None, + BlockKind::Pumpkin => None, + BlockKind::Netherrack => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SoulSand => None, + BlockKind::SoulSoil => None, + BlockKind::Basalt => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedBasalt => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SoulTorch => None, + BlockKind::SoulWallTorch => None, + BlockKind::Glowstone => None, + BlockKind::NetherPortal => None, + BlockKind::CarvedPumpkin => None, + BlockKind::JackOLantern => None, + BlockKind::Cake => None, + BlockKind::Repeater => None, + BlockKind::WhiteStainedGlass => None, + BlockKind::OrangeStainedGlass => None, + BlockKind::MagentaStainedGlass => None, + BlockKind::LightBlueStainedGlass => None, + BlockKind::YellowStainedGlass => None, + BlockKind::LimeStainedGlass => None, + BlockKind::PinkStainedGlass => None, + BlockKind::GrayStainedGlass => None, + BlockKind::LightGrayStainedGlass => None, + BlockKind::CyanStainedGlass => None, + BlockKind::PurpleStainedGlass => None, + BlockKind::BlueStainedGlass => None, + BlockKind::BrownStainedGlass => None, + BlockKind::GreenStainedGlass => None, + BlockKind::RedStainedGlass => None, + BlockKind::BlackStainedGlass => None, + BlockKind::OakTrapdoor => None, + BlockKind::SpruceTrapdoor => None, + BlockKind::BirchTrapdoor => None, + BlockKind::JungleTrapdoor => None, + BlockKind::AcaciaTrapdoor => None, + BlockKind::DarkOakTrapdoor => None, + BlockKind::StoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::MossyStoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CrackedStoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ChiseledStoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::InfestedStone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::InfestedCobblestone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::InfestedStoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::InfestedMossyStoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::InfestedCrackedStoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::InfestedChiseledStoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BrownMushroomBlock => None, + BlockKind::RedMushroomBlock => None, + BlockKind::MushroomStem => None, + BlockKind::IronBars => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Chain => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GlassPane => None, + BlockKind::Melon => None, + BlockKind::AttachedPumpkinStem => None, + BlockKind::AttachedMelonStem => None, + BlockKind::PumpkinStem => None, + BlockKind::MelonStem => None, + BlockKind::Vine => None, + BlockKind::OakFenceGate => None, + BlockKind::BrickStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::StoneBrickStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Mycelium => None, + BlockKind::LilyPad => None, + BlockKind::NetherBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NetherBrickFence => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NetherBrickStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NetherWart => None, + BlockKind::EnchantingTable => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BrewingStand => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Cauldron => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::EndPortal => None, + BlockKind::EndPortalFrame => None, + BlockKind::EndStone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DragonEgg => None, + BlockKind::RedstoneLamp => None, + BlockKind::Cocoa => None, + BlockKind::SandstoneStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::EmeraldOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::EnderChest => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::TripwireHook => None, + BlockKind::Tripwire => None, + BlockKind::EmeraldBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::DiamondPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SpruceStairs => None, + BlockKind::BirchStairs => None, + BlockKind::JungleStairs => None, + BlockKind::CommandBlock => None, + BlockKind::Beacon => None, + BlockKind::CobblestoneWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::MossyCobblestoneWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::FlowerPot => None, + BlockKind::PottedOakSapling => None, + BlockKind::PottedSpruceSapling => None, + BlockKind::PottedBirchSapling => None, + BlockKind::PottedJungleSapling => None, + BlockKind::PottedAcaciaSapling => None, + BlockKind::PottedDarkOakSapling => None, + BlockKind::PottedFern => None, + BlockKind::PottedDandelion => None, + BlockKind::PottedPoppy => None, + BlockKind::PottedBlueOrchid => None, + BlockKind::PottedAllium => None, + BlockKind::PottedAzureBluet => None, + BlockKind::PottedRedTulip => None, + BlockKind::PottedOrangeTulip => None, + BlockKind::PottedWhiteTulip => None, + BlockKind::PottedPinkTulip => None, + BlockKind::PottedOxeyeDaisy => None, + BlockKind::PottedCornflower => None, + BlockKind::PottedLilyOfTheValley => None, + BlockKind::PottedWitherRose => None, + BlockKind::PottedRedMushroom => None, + BlockKind::PottedBrownMushroom => None, + BlockKind::PottedDeadBush => None, + BlockKind::PottedCactus => None, + BlockKind::Carrots => None, + BlockKind::Potatoes => None, + BlockKind::OakButton => None, + BlockKind::SpruceButton => None, + BlockKind::BirchButton => None, + BlockKind::JungleButton => None, + BlockKind::AcaciaButton => None, + BlockKind::DarkOakButton => None, + BlockKind::SkeletonSkull => None, + BlockKind::SkeletonWallSkull => None, + BlockKind::WitherSkeletonSkull => None, + BlockKind::WitherSkeletonWallSkull => None, + BlockKind::ZombieHead => None, + BlockKind::ZombieWallHead => None, + BlockKind::PlayerHead => None, + BlockKind::PlayerWallHead => None, + BlockKind::CreeperHead => None, + BlockKind::CreeperWallHead => None, + BlockKind::DragonHead => None, + BlockKind::DragonWallHead => None, + BlockKind::Anvil => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ChippedAnvil => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DamagedAnvil => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::TrappedChest => None, + BlockKind::LightWeightedPressurePlate => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::HeavyWeightedPressurePlate => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Comparator => None, + BlockKind::DaylightDetector => None, + BlockKind::RedstoneBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NetherQuartzOre => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Hopper => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::QuartzBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ChiseledQuartzBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::QuartzPillar => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::QuartzStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ActivatorRail => None, + BlockKind::Dropper => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::WhiteTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OrangeTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::MagentaTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LightBlueTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::YellowTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LimeTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PinkTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GrayTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LightGrayTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CyanTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PurpleTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlueTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BrownTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GreenTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlackTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::WhiteStainedGlassPane => None, + BlockKind::OrangeStainedGlassPane => None, + BlockKind::MagentaStainedGlassPane => None, + BlockKind::LightBlueStainedGlassPane => None, + BlockKind::YellowStainedGlassPane => None, + BlockKind::LimeStainedGlassPane => None, + BlockKind::PinkStainedGlassPane => None, + BlockKind::GrayStainedGlassPane => None, + BlockKind::LightGrayStainedGlassPane => None, + BlockKind::CyanStainedGlassPane => None, + BlockKind::PurpleStainedGlassPane => None, + BlockKind::BlueStainedGlassPane => None, + BlockKind::BrownStainedGlassPane => None, + BlockKind::GreenStainedGlassPane => None, + BlockKind::RedStainedGlassPane => None, + BlockKind::BlackStainedGlassPane => None, + BlockKind::AcaciaStairs => None, + BlockKind::DarkOakStairs => None, + BlockKind::SlimeBlock => None, + BlockKind::Barrier => None, + BlockKind::IronTrapdoor => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Prismarine => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PrismarineBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DarkPrismarine => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PrismarineStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PrismarineBrickStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DarkPrismarineStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PrismarineSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PrismarineBrickSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DarkPrismarineSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SeaLantern => None, + BlockKind::HayBlock => None, + BlockKind::WhiteCarpet => None, + BlockKind::OrangeCarpet => None, + BlockKind::MagentaCarpet => None, + BlockKind::LightBlueCarpet => None, + BlockKind::YellowCarpet => None, + BlockKind::LimeCarpet => None, + BlockKind::PinkCarpet => None, + BlockKind::GrayCarpet => None, + BlockKind::LightGrayCarpet => None, + BlockKind::CyanCarpet => None, + BlockKind::PurpleCarpet => None, + BlockKind::BlueCarpet => None, + BlockKind::BrownCarpet => None, + BlockKind::GreenCarpet => None, + BlockKind::RedCarpet => None, + BlockKind::BlackCarpet => None, + BlockKind::Terracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CoalBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PackedIce => None, + BlockKind::Sunflower => None, + BlockKind::Lilac => None, + BlockKind::RoseBush => None, + BlockKind::Peony => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::TallGrass => None, + BlockKind::LargeFern => None, + BlockKind::WhiteBanner => None, + BlockKind::OrangeBanner => None, + BlockKind::MagentaBanner => None, + BlockKind::LightBlueBanner => None, + BlockKind::YellowBanner => None, + BlockKind::LimeBanner => None, + BlockKind::PinkBanner => None, + BlockKind::GrayBanner => None, + BlockKind::LightGrayBanner => None, + BlockKind::CyanBanner => None, + BlockKind::PurpleBanner => None, + BlockKind::BlueBanner => None, + BlockKind::BrownBanner => None, + BlockKind::GreenBanner => None, + BlockKind::RedBanner => None, + BlockKind::BlackBanner => None, + BlockKind::WhiteWallBanner => None, + BlockKind::OrangeWallBanner => None, + BlockKind::MagentaWallBanner => None, + BlockKind::LightBlueWallBanner => None, + BlockKind::YellowWallBanner => None, + BlockKind::LimeWallBanner => None, + BlockKind::PinkWallBanner => None, + BlockKind::GrayWallBanner => None, + BlockKind::LightGrayWallBanner => None, + BlockKind::CyanWallBanner => None, + BlockKind::PurpleWallBanner => None, + BlockKind::BlueWallBanner => None, + BlockKind::BrownWallBanner => None, + BlockKind::GreenWallBanner => None, + BlockKind::RedWallBanner => None, + BlockKind::BlackWallBanner => None, + BlockKind::RedSandstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ChiseledRedSandstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CutRedSandstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedSandstoneStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OakSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SpruceSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BirchSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::JungleSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::AcaciaSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DarkOakSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::StoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SmoothStoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SandstoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CutSandstoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PetrifiedOakSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CobblestoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BrickSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::StoneBrickSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NetherBrickSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::QuartzSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedSandstoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CutRedSandstoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PurpurSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SmoothStone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SmoothSandstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SmoothQuartz => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SmoothRedSandstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SpruceFenceGate => None, + BlockKind::BirchFenceGate => None, + BlockKind::JungleFenceGate => None, + BlockKind::AcaciaFenceGate => None, + BlockKind::DarkOakFenceGate => None, + BlockKind::SpruceFence => None, + BlockKind::BirchFence => None, + BlockKind::JungleFence => None, + BlockKind::AcaciaFence => None, + BlockKind::DarkOakFence => None, + BlockKind::SpruceDoor => None, + BlockKind::BirchDoor => None, + BlockKind::JungleDoor => None, + BlockKind::AcaciaDoor => None, + BlockKind::DarkOakDoor => None, + BlockKind::EndRod => None, + BlockKind::ChorusPlant => None, + BlockKind::ChorusFlower => None, + BlockKind::PurpurBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PurpurPillar => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PurpurStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::EndStoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Beetroots => None, + BlockKind::GrassPath => None, + BlockKind::EndGateway => None, + BlockKind::RepeatingCommandBlock => None, + BlockKind::ChainCommandBlock => None, + BlockKind::FrostedIce => None, + BlockKind::MagmaBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NetherWartBlock => None, + BlockKind::RedNetherBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BoneBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::StructureVoid => None, + BlockKind::Observer => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ShulkerBox => None, + BlockKind::WhiteShulkerBox => None, + BlockKind::OrangeShulkerBox => None, + BlockKind::MagentaShulkerBox => None, + BlockKind::LightBlueShulkerBox => None, + BlockKind::YellowShulkerBox => None, + BlockKind::LimeShulkerBox => None, + BlockKind::PinkShulkerBox => None, + BlockKind::GrayShulkerBox => None, + BlockKind::LightGrayShulkerBox => None, + BlockKind::CyanShulkerBox => None, + BlockKind::PurpleShulkerBox => None, + BlockKind::BlueShulkerBox => None, + BlockKind::BrownShulkerBox => None, + BlockKind::GreenShulkerBox => None, + BlockKind::RedShulkerBox => None, + BlockKind::BlackShulkerBox => None, + BlockKind::WhiteGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OrangeGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::MagentaGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LightBlueGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::YellowGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LimeGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PinkGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GrayGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LightGrayGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CyanGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PurpleGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlueGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BrownGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GreenGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlackGlazedTerracotta => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::WhiteConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::OrangeConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::MagentaConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LightBlueConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::YellowConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LimeConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PinkConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GrayConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::LightGrayConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CyanConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PurpleConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlueConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BrownConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GreenConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlackConcrete => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::WhiteConcretePowder => None, + BlockKind::OrangeConcretePowder => None, + BlockKind::MagentaConcretePowder => None, + BlockKind::LightBlueConcretePowder => None, + BlockKind::YellowConcretePowder => None, + BlockKind::LimeConcretePowder => None, + BlockKind::PinkConcretePowder => None, + BlockKind::GrayConcretePowder => None, + BlockKind::LightGrayConcretePowder => None, + BlockKind::CyanConcretePowder => None, + BlockKind::PurpleConcretePowder => None, + BlockKind::BlueConcretePowder => None, + BlockKind::BrownConcretePowder => None, + BlockKind::GreenConcretePowder => None, + BlockKind::RedConcretePowder => None, + BlockKind::BlackConcretePowder => None, + BlockKind::Kelp => None, + BlockKind::KelpPlant => None, + BlockKind::DriedKelpBlock => None, + BlockKind::TurtleEgg => None, + BlockKind::DeadTubeCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DeadBrainCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DeadBubbleCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DeadFireCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DeadHornCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::TubeCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BrainCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BubbleCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::FireCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::HornCoralBlock => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DeadTubeCoral => None, + BlockKind::DeadBrainCoral => None, + BlockKind::DeadBubbleCoral => None, + BlockKind::DeadFireCoral => None, + BlockKind::DeadHornCoral => None, + BlockKind::TubeCoral => None, + BlockKind::BrainCoral => None, + BlockKind::BubbleCoral => None, + BlockKind::FireCoral => None, + BlockKind::HornCoral => None, + BlockKind::DeadTubeCoralFan => None, + BlockKind::DeadBrainCoralFan => None, + BlockKind::DeadBubbleCoralFan => None, + BlockKind::DeadFireCoralFan => None, + BlockKind::DeadHornCoralFan => None, + BlockKind::TubeCoralFan => None, + BlockKind::BrainCoralFan => None, + BlockKind::BubbleCoralFan => None, + BlockKind::FireCoralFan => None, + BlockKind::HornCoralFan => None, + BlockKind::DeadTubeCoralWallFan => None, + BlockKind::DeadBrainCoralWallFan => None, + BlockKind::DeadBubbleCoralWallFan => None, + BlockKind::DeadFireCoralWallFan => None, + BlockKind::DeadHornCoralWallFan => None, + BlockKind::TubeCoralWallFan => None, + BlockKind::BrainCoralWallFan => None, + BlockKind::BubbleCoralWallFan => None, + BlockKind::FireCoralWallFan => None, + BlockKind::HornCoralWallFan => None, + BlockKind::SeaPickle => None, + BlockKind::BlueIce => None, + BlockKind::Conduit => None, + BlockKind::BambooSapling => None, + BlockKind::Bamboo => None, + BlockKind::PottedBamboo => None, + BlockKind::VoidAir => None, + BlockKind::CaveAir => None, + BlockKind::BubbleColumn => None, + BlockKind::PolishedGraniteStairs => None, + BlockKind::SmoothRedSandstoneStairs => None, + BlockKind::MossyStoneBrickStairs => None, + BlockKind::PolishedDioriteStairs => None, + BlockKind::MossyCobblestoneStairs => None, + BlockKind::EndStoneBrickStairs => None, + BlockKind::StoneStairs => None, + BlockKind::SmoothSandstoneStairs => None, + BlockKind::SmoothQuartzStairs => None, + BlockKind::GraniteStairs => None, + BlockKind::AndesiteStairs => None, + BlockKind::RedNetherBrickStairs => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedAndesiteStairs => None, + BlockKind::DioriteStairs => None, + BlockKind::PolishedGraniteSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SmoothRedSandstoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::MossyStoneBrickSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedDioriteSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::MossyCobblestoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::EndStoneBrickSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SmoothSandstoneSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SmoothQuartzSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GraniteSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::AndesiteSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedNetherBrickSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedAndesiteSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DioriteSlab => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BrickWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PrismarineWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedSandstoneWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::MossyStoneBrickWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GraniteWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::StoneBrickWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::NetherBrickWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::AndesiteWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::RedNetherBrickWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SandstoneWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::EndStoneBrickWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::DioriteWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Scaffolding => None, + BlockKind::Loom => None, + BlockKind::Barrel => None, + BlockKind::Smoker => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlastFurnace => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CartographyTable => None, + BlockKind::FletchingTable => None, + BlockKind::Grindstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Lectern => None, + BlockKind::SmithingTable => None, + BlockKind::Stonecutter => None, + BlockKind::Bell => None, + BlockKind::Lantern => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::SoulLantern => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Campfire => None, + BlockKind::SoulCampfire => None, + BlockKind::SweetBerryBush => None, + BlockKind::WarpedStem => None, + BlockKind::StrippedWarpedStem => None, + BlockKind::WarpedHyphae => None, + BlockKind::StrippedWarpedHyphae => None, + BlockKind::WarpedNylium => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::WarpedFungus => None, + BlockKind::WarpedWartBlock => None, + BlockKind::WarpedRoots => None, + BlockKind::NetherSprouts => None, + BlockKind::CrimsonStem => None, + BlockKind::StrippedCrimsonStem => None, + BlockKind::CrimsonHyphae => None, + BlockKind::StrippedCrimsonHyphae => None, + BlockKind::CrimsonNylium => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CrimsonFungus => None, + BlockKind::Shroomlight => None, + BlockKind::WeepingVines => None, + BlockKind::WeepingVinesPlant => None, + BlockKind::TwistingVines => None, + BlockKind::TwistingVinesPlant => None, + BlockKind::CrimsonRoots => None, + BlockKind::CrimsonPlanks => None, + BlockKind::WarpedPlanks => None, + BlockKind::CrimsonSlab => None, + BlockKind::WarpedSlab => None, + BlockKind::CrimsonPressurePlate => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::WarpedPressurePlate => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CrimsonFence => None, + BlockKind::WarpedFence => None, + BlockKind::CrimsonTrapdoor => None, + BlockKind::WarpedTrapdoor => None, + BlockKind::CrimsonFenceGate => None, + BlockKind::WarpedFenceGate => None, + BlockKind::CrimsonStairs => None, + BlockKind::WarpedStairs => None, + BlockKind::CrimsonButton => None, + BlockKind::WarpedButton => None, + BlockKind::CrimsonDoor => None, + BlockKind::WarpedDoor => None, + BlockKind::CrimsonSign => None, + BlockKind::WarpedSign => None, + BlockKind::CrimsonWallSign => None, + BlockKind::WarpedWallSign => None, + BlockKind::StructureBlock => None, + BlockKind::Jigsaw => None, + BlockKind::Composter => None, + BlockKind::Target => None, + BlockKind::BeeNest => None, + BlockKind::Beehive => None, + BlockKind::HoneyBlock => None, + BlockKind::HoneycombBlock => None, + BlockKind::NetheriteBlock => { + const TOOLS: &[libcraft_items::Item] = &[libcraft_items::Item::DiamondPickaxe]; + Some(TOOLS) + } + BlockKind::AncientDebris => { + const TOOLS: &[libcraft_items::Item] = &[libcraft_items::Item::DiamondPickaxe]; + Some(TOOLS) + } + BlockKind::CryingObsidian => { + const TOOLS: &[libcraft_items::Item] = &[libcraft_items::Item::DiamondPickaxe]; + Some(TOOLS) + } + BlockKind::RespawnAnchor => { + const TOOLS: &[libcraft_items::Item] = &[libcraft_items::Item::DiamondPickaxe]; + Some(TOOLS) + } + BlockKind::PottedCrimsonFungus => None, + BlockKind::PottedWarpedFungus => None, + BlockKind::PottedCrimsonRoots => None, + BlockKind::PottedWarpedRoots => None, + BlockKind::Lodestone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::Blackstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlackstoneStairs => None, + BlockKind::BlackstoneWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::BlackstoneSlab => None, + BlockKind::PolishedBlackstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedBlackstoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CrackedPolishedBlackstoneBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ChiseledPolishedBlackstone => None, + BlockKind::PolishedBlackstoneBrickSlab => None, + BlockKind::PolishedBlackstoneBrickStairs => None, + BlockKind::PolishedBlackstoneBrickWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::GildedBlackstone => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedBlackstoneStairs => None, + BlockKind::PolishedBlackstoneSlab => None, + BlockKind::PolishedBlackstonePressurePlate => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::PolishedBlackstoneButton => None, + BlockKind::PolishedBlackstoneWall => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::ChiseledNetherBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::CrackedNetherBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + BlockKind::QuartzBricks => { + const TOOLS: &[libcraft_items::Item] = &[ + libcraft_items::Item::IronPickaxe, + libcraft_items::Item::WoodenPickaxe, + libcraft_items::Item::StonePickaxe, + libcraft_items::Item::DiamondPickaxe, + libcraft_items::Item::GoldenPickaxe, + ]; + Some(TOOLS) + } + } + } +} diff --git a/libcraft/blocks/src/block_data.rs b/libcraft/blocks/src/block_data.rs new file mode 100644 index 000000000..10d3fe618 --- /dev/null +++ b/libcraft/blocks/src/block_data.rs @@ -0,0 +1,577 @@ +use crate::data::{RawBlockStateProperties, ValidProperties}; +use libcraft_core::block::{ + AttachedFace, Axis, BambooLeaves, BedPart, BellAttachment, BlockFace, BlockHalf, ChestType, + ComparatorMode, Instrument, Orientation, PistonType, RailShape, SlabType, StairShape, + StructureBlockMode, WallConnection, +}; +use libcraft_macros::BlockData; + +/// Represents the data (properties) of a block. +/// +/// Types implementing this trait mirror Bukkit's `BlockData` interface. +/// +/// This trait is internal; don't try implementing it for your +/// own types. +pub trait BlockData { + fn from_raw(raw: &RawBlockStateProperties, valid: &'static ValidProperties) -> Option<Self> + where + Self: Sized; + + fn apply(&self, raw: &mut RawBlockStateProperties); +} + +/// Generalized BlockData structs + +/// A block that has an "age" property that +/// represents crop growth. +/// +/// Fire also has this property. +#[derive(Debug, BlockData)] +pub struct Ageable { + age: u8, + valid_properties: &'static ValidProperties, +} + +/// A block that can be powered with a redstone +/// signal. +#[derive(Debug, BlockData)] +pub struct AnaloguePowerable { + power: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Attachable { + attached: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Bisected { + half: BlockHalf, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Directional { + facing: BlockFace, + valid_properties: &'static ValidProperties, +} + +/// Represents the face to which a lever or +/// button is stuck. +#[derive(Debug, BlockData)] +pub struct FaceAttachable { + attached_face: AttachedFace, + valid_properties: &'static ValidProperties, +} + +/// Represents the fluid level contained +/// within this block. +#[derive(Debug, BlockData)] +pub struct Levelled { + level: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Lightable { + lit: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct MultipleFacing { + down: bool, + east: bool, + north: bool, + south: bool, + west: bool, + up: bool, + valid_properties: &'static ValidProperties, +} + +/// Denotes whether the block can be opened. +#[derive(Debug, BlockData)] +pub struct Openable { + open: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Orientable { + axis: Axis, + valid_properties: &'static ValidProperties, +} + +/// Indicates whether block is in powered state +#[derive(Debug, BlockData)] +pub struct Powerable { + powered: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Rail { + rail_shape: RailShape, + valid_properties: &'static ValidProperties, +} + +/// Current rotation of the block +#[derive(Debug, BlockData)] +pub struct Rotatable { + rotation: BlockFace, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Snowable { + snowy: bool, + valid_properties: &'static ValidProperties, +} + +/// Whether the block has water in it +#[derive(Debug, BlockData)] +pub struct Waterlogged { + waterlogged: bool, + valid_properties: &'static ValidProperties, +} + +// Specific BlockData structs + +#[derive(Debug, BlockData)] +pub struct Bamboo { + age: u8, + stage: u8, + bamboo_leaves: BambooLeaves, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Bed { + facing: BlockFace, + part: BedPart, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Beehive { + facing: BlockFace, + honey_level: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Bell { + facing: BlockFace, + powered: bool, + bell_attachment: BellAttachment, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct BrewingStand { + has_bottle_0: bool, + has_bottle_1: bool, + has_bottle_2: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct BubbleColumn { + drag: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Cake { + bites: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Campfire { + facing: BlockFace, + lit: bool, + waterlogged: bool, + signal_fire: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Chain { + facing: BlockFace, + waterlogged: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Chest { + facing: BlockFace, + waterlogged: bool, + chest_type: ChestType, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Cocoa { + age: u8, + facing: BlockFace, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct CommandBlock { + facing: BlockFace, + conditional: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Comparator { + facing: BlockFace, + powered: bool, + comparator_mode: ComparatorMode, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct CoralWallFan { + facing: BlockFace, + waterlogged: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct DaylightDetector { + power: u8, + inverted: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Dispenser { + facing: BlockFace, + triggered: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Door { + half: BlockHalf, + facing: BlockFace, + open: bool, + powered: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct EndPortalFrame { + facing: BlockFace, + eye: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Farmland { + moisture: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Fence { + waterlogged: bool, + down: bool, + east: bool, + north: bool, + south: bool, + west: bool, + up: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Furnace { + facing: BlockFace, + lit: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Gate { + facing: BlockFace, + open: bool, + powered: bool, + in_wall: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct GlassPane { + facing: BlockFace, + waterlogged: bool, + down: bool, + east: bool, + north: bool, + south: bool, + west: bool, + up: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Grindstone { + facing: BlockFace, + attached_face: AttachedFace, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Hopper { + facing: BlockFace, + enabled: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Jigsaw { + orientation: Orientation, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct JukeBox { + has_record: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Ladder { + facing: BlockFace, + waterlogged: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Lantern { + waterlogged: bool, + hanging: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Leaves { + distance: u8, + persistent: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Lectern { + facing: BlockFace, + powered: bool, + has_book: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct NoteBlock { + powered: bool, + instrument: Instrument, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Observer { + facing: BlockFace, + powered: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Piston { + facing: BlockFace, + extended: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct PistonHead { + facing: BlockFace, + piston_type: PistonType, + short: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct RedstoneRail { + powered: bool, + rail_shape: RailShape, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct RedstoneWallTorch { + facing: BlockFace, + lit: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct RedstoneWire { + power: u8, + north: bool, + east: bool, + south: bool, + west: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Repeater { + facing: BlockFace, + powered: bool, + delay: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct RespawnAnchor { + charges: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Sapling { + stage: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Scaffolding { + waterlogged: bool, + bottom: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct SeaPickle { + waterlogged: bool, + pickles: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Sign { + rotation: BlockFace, + waterlogged: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Slab { + waterlogged: bool, + slab_type: SlabType, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Snow { + layers: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Stairs { + half: BlockHalf, + facing: BlockFace, + waterlogged: bool, + stair_shape: StairShape, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct StructureBlock { + structure_block_mode: StructureBlockMode, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Switch { + facing: BlockFace, + attached_face: AttachedFace, + powered: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct TechnicalPiston { + facing: BlockFace, + piston_type: PistonType, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Tnt { + unstable: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct TrapDoor { + half: BlockHalf, + facing: BlockFace, + open: bool, + powered: bool, + waterlogged: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Tripwire { + attached: bool, + powered: bool, + down: bool, + east: bool, + north: bool, + south: bool, + west: bool, + up: bool, + disarmed: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct TripwireHook { + attached: bool, + facing: BlockFace, + powered: bool, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct TurtleEgg { + hatch: u8, + eggs: u8, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct Wall { + waterlogged: bool, + wall_north: WallConnection, + wall_east: WallConnection, + wall_south: WallConnection, + wall_west: WallConnection, + wall_up: WallConnection, + valid_properties: &'static ValidProperties, +} + +#[derive(Debug, BlockData)] +pub struct WallSign { + facing: BlockFace, + waterlogged: bool, + valid_properties: &'static ValidProperties, +} + +// https://hub.spigotmc.org/javadocs/spigot/org/bukkit/block/data/BlockData.html diff --git a/libcraft/blocks/src/data.rs b/libcraft/blocks/src/data.rs new file mode 100644 index 000000000..27e51d73d --- /dev/null +++ b/libcraft/blocks/src/data.rs @@ -0,0 +1,415 @@ +use std::{collections::HashMap, str::FromStr}; + +use crate::BlockKind; +use libcraft_core::block::{ + AttachedFace, Axis, BambooLeaves, BedPart, BellAttachment, BlockFace, BlockHalf, ChestType, + ComparatorMode, DoorHinge, Instrument, Orientation, PistonType, RailShape, RedstoneConnection, + SlabType, StairHalf, StairShape, StructureBlockMode, WallConnection, +}; +use serde::{Deserialize, Serialize}; + +/// Defines all possible data associated with a block state. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct RawBlockState { + /// Block state ID + pub id: u16, + pub kind: BlockKind, + /// Whether this is the default state for this block kind + pub default: bool, + pub properties: RawBlockStateProperties, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct RawBlockStateProperties { + pub facing: Option<BlockFace>, + pub bamboo_leaves: Option<BambooLeaves>, + pub age: Option<u8>, + pub stage: Option<u8>, + pub rotation: Option<BlockFace>, + pub open: Option<bool>, + pub occupied: Option<bool>, + pub part: Option<BedPart>, + pub honey_level: Option<u8>, + pub bell_attachment: Option<BellAttachment>, + pub powered: Option<bool>, + pub lit: Option<bool>, + pub axis: Option<Axis>, + pub has_bottle_0: Option<bool>, + pub has_bottle_1: Option<bool>, + pub has_bottle_2: Option<bool>, + pub drag: Option<u8>, + pub attached_face: Option<AttachedFace>, + pub signal_fire: Option<bool>, + pub waterlogged: Option<bool>, + pub bites: Option<u8>, + pub level: Option<u8>, + pub chest_type: Option<ChestType>, + pub down: Option<bool>, + pub east: Option<bool>, + pub north: Option<bool>, + pub south: Option<bool>, + pub up: Option<bool>, + pub west: Option<bool>, + pub conditional: Option<bool>, + pub inverted: Option<bool>, + pub power: Option<u8>, + pub triggered: Option<bool>, + pub hinge: Option<DoorHinge>, + pub half: Option<BlockHalf>, + pub eye: Option<bool>, + pub moisture: Option<u8>, + pub in_wall: Option<bool>, + pub snowy: Option<bool>, + pub enabled: Option<bool>, + pub orientation: Option<Orientation>, + pub has_record: Option<bool>, + pub hanging: Option<bool>, + pub distance: Option<u8>, + pub persistent: Option<bool>, + pub has_book: Option<bool>, + pub instrument: Option<Instrument>, + pub note: Option<u8>, + pub extended: Option<bool>, + pub piston_type: Option<PistonType>, + pub short: Option<bool>, + pub rail_shape: Option<RailShape>, + pub comparator_mode: Option<ComparatorMode>, + pub dust_east: Option<RedstoneConnection>, + pub dust_north: Option<RedstoneConnection>, + pub dust_south: Option<RedstoneConnection>, + pub dust_west: Option<RedstoneConnection>, + pub delay: Option<u8>, + pub locked: Option<bool>, + pub charges: Option<u8>, + pub bottom: Option<bool>, + pub pickles: Option<u8>, + pub slab_type: Option<SlabType>, + pub layers: Option<u8>, + pub stair_half: Option<StairHalf>, + pub stair_shape: Option<StairShape>, + pub structure_block_mode: Option<StructureBlockMode>, + pub unstable: Option<bool>, + pub attached: Option<bool>, + pub disarmed: Option<bool>, + pub eggs: Option<u8>, + pub hatch: Option<u8>, + pub wall_east: Option<WallConnection>, + pub wall_north: Option<WallConnection>, + pub wall_south: Option<WallConnection>, + pub wall_up: Option<WallConnection>, + pub wall_west: Option<WallConnection>, +} + +/// The Minecraft data report read from +/// `blocks.json`. +#[derive(Debug, Serialize, Deserialize)] +pub struct BlockReport { + #[serde(flatten)] + pub blocks: HashMap<String, BlockReportEntry>, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct BlockReportEntry { + pub states: Vec<BlockReportState>, + #[serde(default)] + pub properties: HashMap<String, Vec<String>>, +} + +impl BlockReportEntry { + fn properties<T: FromStr>(&self, name: &str) -> Vec<T> + where + <T as FromStr>::Err: std::fmt::Debug, + { + if let Some(vec) = self.properties.get(name) { + vec.iter().filter_map(|s| T::from_str(s).ok()).collect() + } else { + Vec::new() + } + } + pub fn to_raw_properties(&self, block_kind: BlockKind) -> RawBlockProperties { + RawBlockProperties { + kind: block_kind, + valid_properties: ValidProperties { + facing: self.properties("facing"), + bamboo_leaves: self.properties("leaves"), + age: self.properties("age"), + stage: self.properties("stage"), + rotation: self.properties("rotation"), + open: self.properties("open"), + occupied: self.properties("occupied"), + part: self.properties("part"), + honey_level: self.properties("honey_level"), + bell_attachment: self.properties("attachment"), + powered: self.properties("powered"), + lit: self.properties("lit"), + axis: self.properties("axis"), + has_bottle_0: self.properties("has_bottle_0"), + has_bottle_1: self.properties("has_bottle_1"), + has_bottle_2: self.properties("has_bottle_2"), + drag: self.properties("drag"), + attached_face: self.properties("face"), + signal_fire: self.properties("signal_fire"), + waterlogged: self.properties("waterlogged"), + bites: self.properties("bites"), + level: self.properties("level"), + chest_type: self.properties("type"), + down: self.properties("down"), + east: self.properties("east"), + north: self.properties("north"), + south: self.properties("south"), + up: self.properties("up"), + west: self.properties("west"), + conditional: self.properties("conditional"), + inverted: self.properties("inverted"), + power: self.properties("power"), + triggered: self.properties("triggered"), + hinge: self.properties("hinge"), + half: self.properties("half"), + eye: self.properties("eye"), + moisture: self.properties("moisture"), + in_wall: self.properties("in_wall"), + snowy: self.properties("snowy"), + enabled: self.properties("enabled"), + orientation: self.properties("orientation"), + has_record: self.properties("has_record"), + hanging: self.properties("hanging"), + distance: self.properties("distance"), + persistent: self.properties("persistent"), + has_book: self.properties("has_book"), + instrument: self.properties("instrument"), + note: self.properties("note"), + extended: self.properties("extended"), + piston_type: self.properties("type"), + short: self.properties("short"), + rail_shape: self.properties("shape"), + comparator_mode: self.properties("mode"), + dust_east: self.properties("east"), + dust_north: self.properties("north"), + dust_south: self.properties("south"), + dust_west: self.properties("west"), + delay: self.properties("delay"), + locked: self.properties("locked"), + charges: self.properties("charges"), + bottom: self.properties("bottom"), + pickles: self.properties("pickles"), + slab_type: self.properties("type"), + layers: self.properties("layers"), + stair_half: self.properties("half"), + stair_shape: self.properties("shape"), + structure_block_mode: self.properties("mode"), + unstable: self.properties("unstable"), + attached: self.properties("attached"), + disarmed: self.properties("disarmed"), + eggs: self.properties("eggs"), + hatch: self.properties("hatch"), + wall_east: self.properties("east"), + wall_north: self.properties("north"), + wall_south: self.properties("south"), + wall_up: self.properties("up"), + wall_west: self.properties("west"), + }, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct BlockReportState { + #[serde(default)] + pub properties: HashMap<String, String>, + pub id: u16, + #[serde(default)] + pub default: bool, +} + +impl BlockReportState { + fn property<T: FromStr>(&self, name: &str) -> Option<T> { + let s = self.properties.get(name)?; + T::from_str(s).ok() + } + + pub fn to_raw_state(&self, block_kind: BlockKind) -> RawBlockState { + RawBlockState { + id: self.id, + kind: block_kind, + default: self.default, + properties: RawBlockStateProperties { + facing: self.property("facing"), + bamboo_leaves: self.property("leaves"), + age: self.property("age"), + stage: self.property("stage"), + rotation: self.property("rotation"), + open: self.property("open"), + occupied: self.property("occupied"), + part: self.property("part"), + honey_level: self.property("honey_level"), + bell_attachment: self.property("attachment"), + powered: self.property("powered"), + lit: self.property("lit"), + axis: self.property("axis"), + has_bottle_0: self.property("has_bottle_0"), + has_bottle_1: self.property("has_bottle_1"), + has_bottle_2: self.property("has_bottle_2"), + drag: self.property("drag"), + attached_face: self.property("face"), + signal_fire: self.property("signal_fire"), + waterlogged: self.property("waterlogged"), + bites: self.property("bites"), + level: self.property("level"), + chest_type: self.property("type"), + down: self.property("down"), + east: self.property("east"), + north: self.property("north"), + south: self.property("south"), + up: self.property("up"), + west: self.property("west"), + conditional: self.property("conditional"), + inverted: self.property("inverted"), + power: self.property("power"), + triggered: self.property("triggered"), + hinge: self.property("hinge"), + half: self.property("half"), + eye: self.property("eye"), + moisture: self.property("moisture"), + in_wall: self.property("in_wall"), + snowy: self.property("snowy"), + enabled: self.property("enabled"), + orientation: self.property("orientation"), + has_record: self.property("has_record"), + hanging: self.property("hanging"), + distance: self.property("distance"), + persistent: self.property("persistent"), + has_book: self.property("has_book"), + instrument: self.property("instrument"), + note: self.property("note"), + extended: self.property("extended"), + piston_type: self.property("type"), + short: self.property("short"), + rail_shape: self.property("shape"), + comparator_mode: self.property("mode"), + dust_east: self.property("east"), + dust_north: self.property("north"), + dust_south: self.property("south"), + dust_west: self.property("west"), + delay: self.property("delay"), + locked: self.property("locked"), + charges: self.property("charges"), + bottom: self.property("bottom"), + pickles: self.property("pickles"), + slab_type: self.property("type"), + layers: self.property("layers"), + stair_half: self.property("half"), + stair_shape: self.property("shape"), + structure_block_mode: self.property("mode"), + unstable: self.property("unstable"), + attached: self.property("attached"), + disarmed: self.property("disarmed"), + eggs: self.property("eggs"), + hatch: self.property("hatch"), + wall_east: self.property("east"), + wall_north: self.property("north"), + wall_south: self.property("south"), + wall_up: self.property("up"), + wall_west: self.property("west"), + }, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct RawBlockProperties { + pub kind: BlockKind, + pub valid_properties: ValidProperties, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct ValidProperties { + pub facing: Vec<BlockFace>, + pub bamboo_leaves: Vec<BambooLeaves>, + pub age: Vec<u8>, + pub stage: Vec<u8>, + pub rotation: Vec<BlockFace>, + pub open: Vec<bool>, + pub occupied: Vec<bool>, + pub part: Vec<BedPart>, + pub honey_level: Vec<u8>, + pub bell_attachment: Vec<BellAttachment>, + pub powered: Vec<bool>, + pub lit: Vec<bool>, + pub axis: Vec<Axis>, + pub has_bottle_0: Vec<bool>, + pub has_bottle_1: Vec<bool>, + pub has_bottle_2: Vec<bool>, + pub drag: Vec<u8>, + pub attached_face: Vec<AttachedFace>, + pub signal_fire: Vec<bool>, + pub waterlogged: Vec<bool>, + pub bites: Vec<u8>, + pub level: Vec<u8>, + pub chest_type: Vec<ChestType>, + pub down: Vec<bool>, + pub east: Vec<bool>, + pub north: Vec<bool>, + pub south: Vec<bool>, + pub up: Vec<bool>, + pub west: Vec<bool>, + pub conditional: Vec<bool>, + pub inverted: Vec<bool>, + pub power: Vec<u8>, + pub triggered: Vec<bool>, + pub hinge: Vec<DoorHinge>, + pub half: Vec<BlockHalf>, + pub eye: Vec<bool>, + pub moisture: Vec<u8>, + pub in_wall: Vec<bool>, + pub snowy: Vec<bool>, + pub enabled: Vec<bool>, + pub orientation: Vec<Orientation>, + pub has_record: Vec<bool>, + pub hanging: Vec<bool>, + pub distance: Vec<u8>, + pub persistent: Vec<bool>, + pub has_book: Vec<bool>, + pub instrument: Vec<Instrument>, + pub note: Vec<u8>, + pub extended: Vec<bool>, + pub piston_type: Vec<PistonType>, + pub short: Vec<bool>, + pub rail_shape: Vec<RailShape>, + pub comparator_mode: Vec<ComparatorMode>, + pub dust_east: Vec<RedstoneConnection>, + pub dust_north: Vec<RedstoneConnection>, + pub dust_south: Vec<RedstoneConnection>, + pub dust_west: Vec<RedstoneConnection>, + pub delay: Vec<u8>, + pub locked: Vec<bool>, + pub charges: Vec<u8>, + pub bottom: Vec<bool>, + pub pickles: Vec<u8>, + pub slab_type: Vec<SlabType>, + pub layers: Vec<u8>, + pub stair_half: Vec<StairHalf>, + pub stair_shape: Vec<StairShape>, + pub structure_block_mode: Vec<StructureBlockMode>, + pub unstable: Vec<bool>, + pub attached: Vec<bool>, + pub disarmed: Vec<bool>, + pub eggs: Vec<u8>, + pub hatch: Vec<u8>, + pub wall_east: Vec<WallConnection>, + pub wall_north: Vec<WallConnection>, + pub wall_south: Vec<WallConnection>, + pub wall_up: Vec<WallConnection>, + pub wall_west: Vec<WallConnection>, +} + +#[cfg(test)] +mod tests { + use std::mem::size_of; + + use super::*; + + #[test] + fn block_sizes() { + println!("Raw block state size: {} bytes", size_of::<RawBlockState>()); + } +} diff --git a/libcraft/blocks/src/lib.rs b/libcraft/blocks/src/lib.rs new file mode 100644 index 000000000..39fcb6c2b --- /dev/null +++ b/libcraft/blocks/src/lib.rs @@ -0,0 +1,10 @@ +mod block; +mod block_data; +pub mod data; +mod registry; +mod simplified_block; + +pub use block::BlockKind; +pub use block_data::*; +pub use registry::BlockState; +pub use simplified_block::SimplifiedBlockKind; diff --git a/libcraft/blocks/src/registry.rs b/libcraft/blocks/src/registry.rs new file mode 100644 index 000000000..106e57c74 --- /dev/null +++ b/libcraft/blocks/src/registry.rs @@ -0,0 +1,158 @@ +use crate::data::{RawBlockProperties, RawBlockState, RawBlockStateProperties, ValidProperties}; +use crate::{BlockData, BlockKind}; + +use ahash::AHashMap; +use bytemuck::{Pod, Zeroable}; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; + +use std::io::Cursor; + +/// A block state. +/// +/// A block state is composed of: +/// * A _kind_, represented by the [`BlockKind`](crate::BlockKind) +/// enum. Each block kind corresponds to a Minecraft block, like "red wool" +/// or "chest." +/// * _Data_, or properties, represented by structs implementing the [`BlockData`](crate::BlockData) +/// trait. For example, a chest has a "type" property in its block data +/// that determines whether the chest is single or double. +#[derive( + Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, Zeroable, Pod, +)] +#[repr(transparent)] +pub struct BlockState { + id: u16, +} + +impl BlockState { + /// Gets this block as a struct implementing the [`BlockData`](crate::BlockData) + /// interface. + /// + /// If this block is not an instance of `T`, then returns `None`. + /// + /// # Warning + /// The returned `BlockData` is not linked with this `BlockState` instance. + /// You need to call [`BlockState::set_data`] to apply any changes made to the block data. + pub fn data_as<T: BlockData>(self) -> Option<T> { + T::from_raw(&self.raw().properties, self.get_valid_properties()) + } + + /// Applies the given `BlockData` to this block state. + /// + /// All property values in `data` override existing properties + /// in `self`. + pub fn set_data<T: BlockData>(&mut self, data: T) { + let mut raw = self.raw().properties.clone(); + data.apply(&mut raw); + if let Some(new_block) = Self::from_raw(&raw) { + *self = new_block; + } + } + + /// Returns whether this is the default block state for + /// the block kind. + pub fn is_default(self) -> bool { + self.raw().default + } + + /// Gets the ID of this block state. + /// + /// Block state IDs are not stable between Minecraft versions. + pub fn id(self) -> u16 { + self.id + } + + /// Creates a block state from an ID. + /// Returns `None` if the ID is invalid. + /// + /// Block state IDs are not stable between Minecraft versions. + pub fn from_id(id: u16) -> Option<Self> { + let _state = REGISTRY.raw_state(id)?; + Some(Self { id }) + } + + /// Determines whether this block state is valid. + pub fn is_valid(self) -> bool { + REGISTRY.raw_state(self.id).is_some() + } + + pub fn get_valid_properties(&self) -> &'static ValidProperties { + REGISTRY.valid_properties.get(&self.raw().kind).unwrap() + } + + /// Gets the raw block state for this block state. + pub(crate) fn raw(&self) -> &RawBlockState { + REGISTRY.raw_state(self.id).expect("bad block") + } + + /// Creates a block state from its raw properties. + pub(crate) fn from_raw(raw: &RawBlockStateProperties) -> Option<Self> { + let id = REGISTRY.id_for_state(raw)?; + Some(Self { id }) + } +} + +static REGISTRY: Lazy<BlockRegistry> = Lazy::new(BlockRegistry::new); + +struct BlockRegistry { + states: Vec<RawBlockState>, + id_mapping: AHashMap<RawBlockStateProperties, u16>, + valid_properties: AHashMap<BlockKind, ValidProperties>, +} + +impl BlockRegistry { + fn new() -> Self { + const STATE_DATA: &[u8] = include_bytes!("../assets/raw_block_states.bc.gz"); + let state_reader = flate2::bufread::GzDecoder::new(Cursor::new(STATE_DATA)); + let states: Vec<RawBlockState> = + bincode::deserialize_from(state_reader).expect("malformed block state data"); + + const PROPERTY_DATA: &[u8] = include_bytes!("../assets/raw_block_properties.bc.gz"); + let property_reader = flate2::bufread::GzDecoder::new(Cursor::new(PROPERTY_DATA)); + let properties: Vec<RawBlockProperties> = + bincode::deserialize_from(property_reader).expect("malformed block properties"); + + // Ensure that indexes match IDs. + #[cfg(debug_assertions)] + { + for (index, state) in states.iter().enumerate() { + assert_eq!(index, state.id as usize); + } + } + + let id_mapping = states + .iter() + .map(|state| (state.properties.clone(), state.id)) + .collect(); + + let valid_properties = properties + .iter() + .map(|properties| (properties.kind, properties.valid_properties.clone())) + .collect(); + + Self { + states, + id_mapping, + valid_properties, + } + } + + fn raw_state(&self, id: u16) -> Option<&RawBlockState> { + self.states.get(id as usize) + } + + fn id_for_state(&self, state: &RawBlockStateProperties) -> Option<u16> { + self.id_mapping.get(state).copied() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn block_registry_creates_successfully() { + let _ = BlockRegistry::new(); + } +} diff --git a/libcraft/blocks/src/simplified_block.rs b/libcraft/blocks/src/simplified_block.rs new file mode 100644 index 000000000..2ad8b9c8d --- /dev/null +++ b/libcraft/blocks/src/simplified_block.rs @@ -0,0 +1,1146 @@ +// This file is @generated. Please do not edit. +use crate::BlockKind; +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum SimplifiedBlockKind { + Air, + Planks, + Sapling, + Log, + Leaves, + Bed, + Wool, + Flower, + WoodenPressurePlate, + StainedGlass, + WoodenTrapdoor, + WoodenButton, + Anvil, + GlazedTeracotta, + Teracotta, + StainedGlassPane, + Carpet, + WallBanner, + Banner, + Slab, + Stairs, + FenceGate, + Fence, + WoodenDoor, + ShulkerBox, + Concrete, + ConcretePowder, + Coral, + CoralBlock, + CoralFan, + CoralWallFan, + Mushroom, + WallSign, + Sign, + Stone, + Granite, + PolishedGranite, + Diorite, + PolishedDiorite, + Andesite, + PolishedAndesite, + GrassBlock, + Dirt, + CoarseDirt, + Podzol, + Cobblestone, + Bedrock, + Water, + Lava, + Sand, + RedSand, + Gravel, + GoldOre, + IronOre, + CoalOre, + NetherGoldOre, + Sponge, + WetSponge, + Glass, + LapisOre, + LapisBlock, + Dispenser, + Sandstone, + ChiseledSandstone, + CutSandstone, + NoteBlock, + PoweredRail, + DetectorRail, + StickyPiston, + Cobweb, + Grass, + Fern, + DeadBush, + Seagrass, + TallSeagrass, + Piston, + PistonHead, + MovingPiston, + Cornflower, + WitherRose, + LilyOfTheValley, + GoldBlock, + IronBlock, + Bricks, + Tnt, + Bookshelf, + MossyCobblestone, + Obsidian, + Torch, + WallTorch, + Fire, + SoulFire, + Spawner, + Chest, + RedstoneWire, + DiamondOre, + DiamondBlock, + CraftingTable, + Wheat, + Farmland, + Furnace, + Ladder, + Rail, + Lever, + StonePressurePlate, + IronDoor, + RedstoneOre, + RedstoneTorch, + RedstoneWallTorch, + StoneButton, + Snow, + Ice, + SnowBlock, + Cactus, + Clay, + SugarCane, + Jukebox, + Pumpkin, + Netherrack, + SoulSand, + SoulSoil, + Basalt, + PolishedBasalt, + SoulTorch, + SoulWallTorch, + Glowstone, + NetherPortal, + CarvedPumpkin, + JackOLantern, + Cake, + Repeater, + StoneBricks, + MossyStoneBricks, + CrackedStoneBricks, + ChiseledStoneBricks, + InfestedStone, + InfestedCobblestone, + InfestedStoneBricks, + InfestedMossyStoneBricks, + InfestedCrackedStoneBricks, + InfestedChiseledStoneBricks, + BrownMushroomBlock, + RedMushroomBlock, + MushroomStem, + IronBars, + Chain, + GlassPane, + Melon, + AttachedPumpkinStem, + AttachedMelonStem, + PumpkinStem, + MelonStem, + Vine, + Mycelium, + LilyPad, + NetherBricks, + NetherWart, + EnchantingTable, + BrewingStand, + Cauldron, + EndPortal, + EndPortalFrame, + EndStone, + DragonEgg, + RedstoneLamp, + Cocoa, + EmeraldOre, + EnderChest, + TripwireHook, + Tripwire, + EmeraldBlock, + CommandBlock, + Beacon, + CobblestoneWall, + MossyCobblestoneWall, + FlowerPot, + PottedFern, + PottedDandelion, + PottedPoppy, + PottedAllium, + PottedCornflower, + PottedLilyOfTheValley, + PottedWitherRose, + PottedDeadBush, + PottedCactus, + Carrots, + Potatoes, + SkeletonSkull, + SkeletonWallSkull, + WitherSkeletonSkull, + WitherSkeletonWallSkull, + ZombieHead, + ZombieWallHead, + PlayerHead, + PlayerWallHead, + CreeperHead, + CreeperWallHead, + DragonHead, + DragonWallHead, + TrappedChest, + LightWeightedPressurePlate, + HeavyWeightedPressurePlate, + Comparator, + DaylightDetector, + RedstoneBlock, + NetherQuartzOre, + Hopper, + QuartzBlock, + ChiseledQuartzBlock, + QuartzPillar, + ActivatorRail, + Dropper, + SlimeBlock, + Barrier, + IronTrapdoor, + Prismarine, + PrismarineBricks, + DarkPrismarine, + SeaLantern, + HayBlock, + CoalBlock, + PackedIce, + Sunflower, + Lilac, + RoseBush, + Peony, + TallGrass, + LargeFern, + RedSandstone, + ChiseledRedSandstone, + CutRedSandstone, + SmoothStone, + SmoothSandstone, + SmoothQuartz, + SmoothRedSandstone, + EndRod, + ChorusPlant, + ChorusFlower, + PurpurBlock, + PurpurPillar, + EndStoneBricks, + Beetroots, + GrassPath, + EndGateway, + RepeatingCommandBlock, + ChainCommandBlock, + FrostedIce, + MagmaBlock, + NetherWartBlock, + RedNetherBricks, + BoneBlock, + StructureVoid, + Observer, + Kelp, + KelpPlant, + DriedKelpBlock, + TurtleEgg, + SeaPickle, + BlueIce, + Conduit, + Bamboo, + PottedBamboo, + BubbleColumn, + BrickWall, + PrismarineWall, + RedSandstoneWall, + MossyStoneBrickWall, + GraniteWall, + StoneBrickWall, + NetherBrickWall, + AndesiteWall, + RedNetherBrickWall, + SandstoneWall, + EndStoneBrickWall, + DioriteWall, + Scaffolding, + Loom, + Barrel, + Smoker, + BlastFurnace, + CartographyTable, + FletchingTable, + Grindstone, + Lectern, + SmithingTable, + Stonecutter, + Bell, + Lantern, + SoulLantern, + Campfire, + SoulCampfire, + SweetBerryBush, + WarpedStem, + StrippedWarpedStem, + WarpedHyphae, + StrippedWarpedHyphae, + WarpedNylium, + WarpedFungus, + WarpedWartBlock, + WarpedRoots, + NetherSprouts, + CrimsonStem, + StrippedCrimsonStem, + CrimsonHyphae, + StrippedCrimsonHyphae, + CrimsonNylium, + CrimsonFungus, + Shroomlight, + WeepingVines, + WeepingVinesPlant, + TwistingVines, + TwistingVinesPlant, + CrimsonRoots, + CrimsonPressurePlate, + WarpedPressurePlate, + CrimsonTrapdoor, + WarpedTrapdoor, + CrimsonButton, + WarpedButton, + CrimsonDoor, + WarpedDoor, + StructureBlock, + Jigsaw, + Composter, + Target, + BeeNest, + Beehive, + HoneyBlock, + HoneycombBlock, + NetheriteBlock, + AncientDebris, + CryingObsidian, + RespawnAnchor, + PottedCrimsonFungus, + PottedWarpedFungus, + PottedCrimsonRoots, + PottedWarpedRoots, + Lodestone, + Blackstone, + BlackstoneWall, + PolishedBlackstone, + PolishedBlackstoneBricks, + CrackedPolishedBlackstoneBricks, + ChiseledPolishedBlackstone, + PolishedBlackstoneBrickWall, + GildedBlackstone, + PolishedBlackstonePressurePlate, + PolishedBlackstoneButton, + PolishedBlackstoneWall, + ChiseledNetherBricks, + CrackedNetherBricks, + QuartzBricks, +} + +#[allow(warnings)] +#[allow(clippy::all)] +impl BlockKind { + /// Returns the `simplified_kind` property of this `BlockKind`. + pub fn simplified_kind(&self) -> SimplifiedBlockKind { + match self { + BlockKind::Air => SimplifiedBlockKind::Air, + BlockKind::Stone => SimplifiedBlockKind::Stone, + BlockKind::Granite => SimplifiedBlockKind::Granite, + BlockKind::PolishedGranite => SimplifiedBlockKind::PolishedGranite, + BlockKind::Diorite => SimplifiedBlockKind::Diorite, + BlockKind::PolishedDiorite => SimplifiedBlockKind::PolishedDiorite, + BlockKind::Andesite => SimplifiedBlockKind::Andesite, + BlockKind::PolishedAndesite => SimplifiedBlockKind::PolishedAndesite, + BlockKind::GrassBlock => SimplifiedBlockKind::GrassBlock, + BlockKind::Dirt => SimplifiedBlockKind::Dirt, + BlockKind::CoarseDirt => SimplifiedBlockKind::CoarseDirt, + BlockKind::Podzol => SimplifiedBlockKind::Podzol, + BlockKind::Cobblestone => SimplifiedBlockKind::Cobblestone, + BlockKind::OakPlanks => SimplifiedBlockKind::Planks, + BlockKind::SprucePlanks => SimplifiedBlockKind::Planks, + BlockKind::BirchPlanks => SimplifiedBlockKind::Planks, + BlockKind::JunglePlanks => SimplifiedBlockKind::Planks, + BlockKind::AcaciaPlanks => SimplifiedBlockKind::Planks, + BlockKind::DarkOakPlanks => SimplifiedBlockKind::Planks, + BlockKind::OakSapling => SimplifiedBlockKind::Sapling, + BlockKind::SpruceSapling => SimplifiedBlockKind::Sapling, + BlockKind::BirchSapling => SimplifiedBlockKind::Sapling, + BlockKind::JungleSapling => SimplifiedBlockKind::Sapling, + BlockKind::AcaciaSapling => SimplifiedBlockKind::Sapling, + BlockKind::DarkOakSapling => SimplifiedBlockKind::Sapling, + BlockKind::Bedrock => SimplifiedBlockKind::Bedrock, + BlockKind::Water => SimplifiedBlockKind::Water, + BlockKind::Lava => SimplifiedBlockKind::Lava, + BlockKind::Sand => SimplifiedBlockKind::Sand, + BlockKind::RedSand => SimplifiedBlockKind::RedSand, + BlockKind::Gravel => SimplifiedBlockKind::Gravel, + BlockKind::GoldOre => SimplifiedBlockKind::GoldOre, + BlockKind::IronOre => SimplifiedBlockKind::IronOre, + BlockKind::CoalOre => SimplifiedBlockKind::CoalOre, + BlockKind::NetherGoldOre => SimplifiedBlockKind::NetherGoldOre, + BlockKind::OakLog => SimplifiedBlockKind::Log, + BlockKind::SpruceLog => SimplifiedBlockKind::Log, + BlockKind::BirchLog => SimplifiedBlockKind::Log, + BlockKind::JungleLog => SimplifiedBlockKind::Log, + BlockKind::AcaciaLog => SimplifiedBlockKind::Log, + BlockKind::DarkOakLog => SimplifiedBlockKind::Log, + BlockKind::StrippedSpruceLog => SimplifiedBlockKind::Log, + BlockKind::StrippedBirchLog => SimplifiedBlockKind::Log, + BlockKind::StrippedJungleLog => SimplifiedBlockKind::Log, + BlockKind::StrippedAcaciaLog => SimplifiedBlockKind::Log, + BlockKind::StrippedDarkOakLog => SimplifiedBlockKind::Log, + BlockKind::StrippedOakLog => SimplifiedBlockKind::Log, + BlockKind::OakWood => SimplifiedBlockKind::Log, + BlockKind::SpruceWood => SimplifiedBlockKind::Log, + BlockKind::BirchWood => SimplifiedBlockKind::Log, + BlockKind::JungleWood => SimplifiedBlockKind::Log, + BlockKind::AcaciaWood => SimplifiedBlockKind::Log, + BlockKind::DarkOakWood => SimplifiedBlockKind::Log, + BlockKind::StrippedOakWood => SimplifiedBlockKind::Log, + BlockKind::StrippedSpruceWood => SimplifiedBlockKind::Log, + BlockKind::StrippedBirchWood => SimplifiedBlockKind::Log, + BlockKind::StrippedJungleWood => SimplifiedBlockKind::Log, + BlockKind::StrippedAcaciaWood => SimplifiedBlockKind::Log, + BlockKind::StrippedDarkOakWood => SimplifiedBlockKind::Log, + BlockKind::OakLeaves => SimplifiedBlockKind::Leaves, + BlockKind::SpruceLeaves => SimplifiedBlockKind::Leaves, + BlockKind::BirchLeaves => SimplifiedBlockKind::Leaves, + BlockKind::JungleLeaves => SimplifiedBlockKind::Leaves, + BlockKind::AcaciaLeaves => SimplifiedBlockKind::Leaves, + BlockKind::DarkOakLeaves => SimplifiedBlockKind::Leaves, + BlockKind::Sponge => SimplifiedBlockKind::Sponge, + BlockKind::WetSponge => SimplifiedBlockKind::WetSponge, + BlockKind::Glass => SimplifiedBlockKind::Glass, + BlockKind::LapisOre => SimplifiedBlockKind::LapisOre, + BlockKind::LapisBlock => SimplifiedBlockKind::LapisBlock, + BlockKind::Dispenser => SimplifiedBlockKind::Dispenser, + BlockKind::Sandstone => SimplifiedBlockKind::Sandstone, + BlockKind::ChiseledSandstone => SimplifiedBlockKind::ChiseledSandstone, + BlockKind::CutSandstone => SimplifiedBlockKind::CutSandstone, + BlockKind::NoteBlock => SimplifiedBlockKind::NoteBlock, + BlockKind::WhiteBed => SimplifiedBlockKind::Bed, + BlockKind::OrangeBed => SimplifiedBlockKind::Bed, + BlockKind::MagentaBed => SimplifiedBlockKind::Bed, + BlockKind::LightBlueBed => SimplifiedBlockKind::Bed, + BlockKind::YellowBed => SimplifiedBlockKind::Bed, + BlockKind::LimeBed => SimplifiedBlockKind::Bed, + BlockKind::PinkBed => SimplifiedBlockKind::Bed, + BlockKind::GrayBed => SimplifiedBlockKind::Bed, + BlockKind::LightGrayBed => SimplifiedBlockKind::Bed, + BlockKind::CyanBed => SimplifiedBlockKind::Bed, + BlockKind::PurpleBed => SimplifiedBlockKind::Bed, + BlockKind::BlueBed => SimplifiedBlockKind::Bed, + BlockKind::BrownBed => SimplifiedBlockKind::Bed, + BlockKind::GreenBed => SimplifiedBlockKind::Bed, + BlockKind::RedBed => SimplifiedBlockKind::Bed, + BlockKind::BlackBed => SimplifiedBlockKind::Bed, + BlockKind::PoweredRail => SimplifiedBlockKind::PoweredRail, + BlockKind::DetectorRail => SimplifiedBlockKind::DetectorRail, + BlockKind::StickyPiston => SimplifiedBlockKind::StickyPiston, + BlockKind::Cobweb => SimplifiedBlockKind::Cobweb, + BlockKind::Grass => SimplifiedBlockKind::Grass, + BlockKind::Fern => SimplifiedBlockKind::Fern, + BlockKind::DeadBush => SimplifiedBlockKind::DeadBush, + BlockKind::Seagrass => SimplifiedBlockKind::Seagrass, + BlockKind::TallSeagrass => SimplifiedBlockKind::TallSeagrass, + BlockKind::Piston => SimplifiedBlockKind::Piston, + BlockKind::PistonHead => SimplifiedBlockKind::PistonHead, + BlockKind::WhiteWool => SimplifiedBlockKind::Wool, + BlockKind::OrangeWool => SimplifiedBlockKind::Wool, + BlockKind::MagentaWool => SimplifiedBlockKind::Wool, + BlockKind::LightBlueWool => SimplifiedBlockKind::Wool, + BlockKind::YellowWool => SimplifiedBlockKind::Wool, + BlockKind::LimeWool => SimplifiedBlockKind::Wool, + BlockKind::PinkWool => SimplifiedBlockKind::Wool, + BlockKind::GrayWool => SimplifiedBlockKind::Wool, + BlockKind::LightGrayWool => SimplifiedBlockKind::Wool, + BlockKind::CyanWool => SimplifiedBlockKind::Wool, + BlockKind::PurpleWool => SimplifiedBlockKind::Wool, + BlockKind::BlueWool => SimplifiedBlockKind::Wool, + BlockKind::BrownWool => SimplifiedBlockKind::Wool, + BlockKind::GreenWool => SimplifiedBlockKind::Wool, + BlockKind::RedWool => SimplifiedBlockKind::Wool, + BlockKind::BlackWool => SimplifiedBlockKind::Wool, + BlockKind::MovingPiston => SimplifiedBlockKind::MovingPiston, + BlockKind::Dandelion => SimplifiedBlockKind::Flower, + BlockKind::Poppy => SimplifiedBlockKind::Flower, + BlockKind::BlueOrchid => SimplifiedBlockKind::Flower, + BlockKind::Allium => SimplifiedBlockKind::Flower, + BlockKind::AzureBluet => SimplifiedBlockKind::Flower, + BlockKind::RedTulip => SimplifiedBlockKind::Flower, + BlockKind::OrangeTulip => SimplifiedBlockKind::Flower, + BlockKind::WhiteTulip => SimplifiedBlockKind::Flower, + BlockKind::PinkTulip => SimplifiedBlockKind::Flower, + BlockKind::OxeyeDaisy => SimplifiedBlockKind::Flower, + BlockKind::Cornflower => SimplifiedBlockKind::Cornflower, + BlockKind::WitherRose => SimplifiedBlockKind::WitherRose, + BlockKind::LilyOfTheValley => SimplifiedBlockKind::LilyOfTheValley, + BlockKind::BrownMushroom => SimplifiedBlockKind::Mushroom, + BlockKind::RedMushroom => SimplifiedBlockKind::Mushroom, + BlockKind::GoldBlock => SimplifiedBlockKind::GoldBlock, + BlockKind::IronBlock => SimplifiedBlockKind::IronBlock, + BlockKind::Bricks => SimplifiedBlockKind::Bricks, + BlockKind::Tnt => SimplifiedBlockKind::Tnt, + BlockKind::Bookshelf => SimplifiedBlockKind::Bookshelf, + BlockKind::MossyCobblestone => SimplifiedBlockKind::MossyCobblestone, + BlockKind::Obsidian => SimplifiedBlockKind::Obsidian, + BlockKind::Torch => SimplifiedBlockKind::Torch, + BlockKind::WallTorch => SimplifiedBlockKind::WallTorch, + BlockKind::Fire => SimplifiedBlockKind::Fire, + BlockKind::SoulFire => SimplifiedBlockKind::SoulFire, + BlockKind::Spawner => SimplifiedBlockKind::Spawner, + BlockKind::OakStairs => SimplifiedBlockKind::Stairs, + BlockKind::Chest => SimplifiedBlockKind::Chest, + BlockKind::RedstoneWire => SimplifiedBlockKind::RedstoneWire, + BlockKind::DiamondOre => SimplifiedBlockKind::DiamondOre, + BlockKind::DiamondBlock => SimplifiedBlockKind::DiamondBlock, + BlockKind::CraftingTable => SimplifiedBlockKind::CraftingTable, + BlockKind::Wheat => SimplifiedBlockKind::Wheat, + BlockKind::Farmland => SimplifiedBlockKind::Farmland, + BlockKind::Furnace => SimplifiedBlockKind::Furnace, + BlockKind::OakSign => SimplifiedBlockKind::Sign, + BlockKind::SpruceSign => SimplifiedBlockKind::Sign, + BlockKind::BirchSign => SimplifiedBlockKind::Sign, + BlockKind::AcaciaSign => SimplifiedBlockKind::Sign, + BlockKind::JungleSign => SimplifiedBlockKind::Sign, + BlockKind::DarkOakSign => SimplifiedBlockKind::Sign, + BlockKind::OakDoor => SimplifiedBlockKind::WoodenDoor, + BlockKind::Ladder => SimplifiedBlockKind::Ladder, + BlockKind::Rail => SimplifiedBlockKind::Rail, + BlockKind::CobblestoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::OakWallSign => SimplifiedBlockKind::WallSign, + BlockKind::SpruceWallSign => SimplifiedBlockKind::WallSign, + BlockKind::BirchWallSign => SimplifiedBlockKind::WallSign, + BlockKind::AcaciaWallSign => SimplifiedBlockKind::WallSign, + BlockKind::JungleWallSign => SimplifiedBlockKind::WallSign, + BlockKind::DarkOakWallSign => SimplifiedBlockKind::WallSign, + BlockKind::Lever => SimplifiedBlockKind::Lever, + BlockKind::StonePressurePlate => SimplifiedBlockKind::StonePressurePlate, + BlockKind::IronDoor => SimplifiedBlockKind::IronDoor, + BlockKind::OakPressurePlate => SimplifiedBlockKind::WoodenPressurePlate, + BlockKind::SprucePressurePlate => SimplifiedBlockKind::WoodenPressurePlate, + BlockKind::BirchPressurePlate => SimplifiedBlockKind::WoodenPressurePlate, + BlockKind::JunglePressurePlate => SimplifiedBlockKind::WoodenPressurePlate, + BlockKind::AcaciaPressurePlate => SimplifiedBlockKind::WoodenPressurePlate, + BlockKind::DarkOakPressurePlate => SimplifiedBlockKind::WoodenPressurePlate, + BlockKind::RedstoneOre => SimplifiedBlockKind::RedstoneOre, + BlockKind::RedstoneTorch => SimplifiedBlockKind::RedstoneTorch, + BlockKind::RedstoneWallTorch => SimplifiedBlockKind::RedstoneWallTorch, + BlockKind::StoneButton => SimplifiedBlockKind::StoneButton, + BlockKind::Snow => SimplifiedBlockKind::Snow, + BlockKind::Ice => SimplifiedBlockKind::Ice, + BlockKind::SnowBlock => SimplifiedBlockKind::SnowBlock, + BlockKind::Cactus => SimplifiedBlockKind::Cactus, + BlockKind::Clay => SimplifiedBlockKind::Clay, + BlockKind::SugarCane => SimplifiedBlockKind::SugarCane, + BlockKind::Jukebox => SimplifiedBlockKind::Jukebox, + BlockKind::OakFence => SimplifiedBlockKind::Fence, + BlockKind::Pumpkin => SimplifiedBlockKind::Pumpkin, + BlockKind::Netherrack => SimplifiedBlockKind::Netherrack, + BlockKind::SoulSand => SimplifiedBlockKind::SoulSand, + BlockKind::SoulSoil => SimplifiedBlockKind::SoulSoil, + BlockKind::Basalt => SimplifiedBlockKind::Basalt, + BlockKind::PolishedBasalt => SimplifiedBlockKind::PolishedBasalt, + BlockKind::SoulTorch => SimplifiedBlockKind::SoulTorch, + BlockKind::SoulWallTorch => SimplifiedBlockKind::SoulWallTorch, + BlockKind::Glowstone => SimplifiedBlockKind::Glowstone, + BlockKind::NetherPortal => SimplifiedBlockKind::NetherPortal, + BlockKind::CarvedPumpkin => SimplifiedBlockKind::CarvedPumpkin, + BlockKind::JackOLantern => SimplifiedBlockKind::JackOLantern, + BlockKind::Cake => SimplifiedBlockKind::Cake, + BlockKind::Repeater => SimplifiedBlockKind::Repeater, + BlockKind::WhiteStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::OrangeStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::MagentaStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::LightBlueStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::YellowStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::LimeStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::PinkStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::GrayStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::LightGrayStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::CyanStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::PurpleStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::BlueStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::BrownStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::GreenStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::RedStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::BlackStainedGlass => SimplifiedBlockKind::StainedGlass, + BlockKind::OakTrapdoor => SimplifiedBlockKind::WoodenTrapdoor, + BlockKind::SpruceTrapdoor => SimplifiedBlockKind::WoodenTrapdoor, + BlockKind::BirchTrapdoor => SimplifiedBlockKind::WoodenTrapdoor, + BlockKind::JungleTrapdoor => SimplifiedBlockKind::WoodenTrapdoor, + BlockKind::AcaciaTrapdoor => SimplifiedBlockKind::WoodenTrapdoor, + BlockKind::DarkOakTrapdoor => SimplifiedBlockKind::WoodenTrapdoor, + BlockKind::StoneBricks => SimplifiedBlockKind::StoneBricks, + BlockKind::MossyStoneBricks => SimplifiedBlockKind::MossyStoneBricks, + BlockKind::CrackedStoneBricks => SimplifiedBlockKind::CrackedStoneBricks, + BlockKind::ChiseledStoneBricks => SimplifiedBlockKind::ChiseledStoneBricks, + BlockKind::InfestedStone => SimplifiedBlockKind::InfestedStone, + BlockKind::InfestedCobblestone => SimplifiedBlockKind::InfestedCobblestone, + BlockKind::InfestedStoneBricks => SimplifiedBlockKind::InfestedStoneBricks, + BlockKind::InfestedMossyStoneBricks => SimplifiedBlockKind::InfestedMossyStoneBricks, + BlockKind::InfestedCrackedStoneBricks => { + SimplifiedBlockKind::InfestedCrackedStoneBricks + } + BlockKind::InfestedChiseledStoneBricks => { + SimplifiedBlockKind::InfestedChiseledStoneBricks + } + BlockKind::BrownMushroomBlock => SimplifiedBlockKind::BrownMushroomBlock, + BlockKind::RedMushroomBlock => SimplifiedBlockKind::RedMushroomBlock, + BlockKind::MushroomStem => SimplifiedBlockKind::MushroomStem, + BlockKind::IronBars => SimplifiedBlockKind::IronBars, + BlockKind::Chain => SimplifiedBlockKind::Chain, + BlockKind::GlassPane => SimplifiedBlockKind::GlassPane, + BlockKind::Melon => SimplifiedBlockKind::Melon, + BlockKind::AttachedPumpkinStem => SimplifiedBlockKind::AttachedPumpkinStem, + BlockKind::AttachedMelonStem => SimplifiedBlockKind::AttachedMelonStem, + BlockKind::PumpkinStem => SimplifiedBlockKind::PumpkinStem, + BlockKind::MelonStem => SimplifiedBlockKind::MelonStem, + BlockKind::Vine => SimplifiedBlockKind::Vine, + BlockKind::OakFenceGate => SimplifiedBlockKind::FenceGate, + BlockKind::BrickStairs => SimplifiedBlockKind::Stairs, + BlockKind::StoneBrickStairs => SimplifiedBlockKind::Stairs, + BlockKind::Mycelium => SimplifiedBlockKind::Mycelium, + BlockKind::LilyPad => SimplifiedBlockKind::LilyPad, + BlockKind::NetherBricks => SimplifiedBlockKind::NetherBricks, + BlockKind::NetherBrickFence => SimplifiedBlockKind::Fence, + BlockKind::NetherBrickStairs => SimplifiedBlockKind::Stairs, + BlockKind::NetherWart => SimplifiedBlockKind::NetherWart, + BlockKind::EnchantingTable => SimplifiedBlockKind::EnchantingTable, + BlockKind::BrewingStand => SimplifiedBlockKind::BrewingStand, + BlockKind::Cauldron => SimplifiedBlockKind::Cauldron, + BlockKind::EndPortal => SimplifiedBlockKind::EndPortal, + BlockKind::EndPortalFrame => SimplifiedBlockKind::EndPortalFrame, + BlockKind::EndStone => SimplifiedBlockKind::EndStone, + BlockKind::DragonEgg => SimplifiedBlockKind::DragonEgg, + BlockKind::RedstoneLamp => SimplifiedBlockKind::RedstoneLamp, + BlockKind::Cocoa => SimplifiedBlockKind::Cocoa, + BlockKind::SandstoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::EmeraldOre => SimplifiedBlockKind::EmeraldOre, + BlockKind::EnderChest => SimplifiedBlockKind::EnderChest, + BlockKind::TripwireHook => SimplifiedBlockKind::TripwireHook, + BlockKind::Tripwire => SimplifiedBlockKind::Tripwire, + BlockKind::EmeraldBlock => SimplifiedBlockKind::EmeraldBlock, + BlockKind::SpruceStairs => SimplifiedBlockKind::Stairs, + BlockKind::BirchStairs => SimplifiedBlockKind::Stairs, + BlockKind::JungleStairs => SimplifiedBlockKind::Stairs, + BlockKind::CommandBlock => SimplifiedBlockKind::CommandBlock, + BlockKind::Beacon => SimplifiedBlockKind::Beacon, + BlockKind::CobblestoneWall => SimplifiedBlockKind::CobblestoneWall, + BlockKind::MossyCobblestoneWall => SimplifiedBlockKind::MossyCobblestoneWall, + BlockKind::FlowerPot => SimplifiedBlockKind::FlowerPot, + BlockKind::PottedOakSapling => SimplifiedBlockKind::Sapling, + BlockKind::PottedSpruceSapling => SimplifiedBlockKind::Sapling, + BlockKind::PottedBirchSapling => SimplifiedBlockKind::Sapling, + BlockKind::PottedJungleSapling => SimplifiedBlockKind::Sapling, + BlockKind::PottedAcaciaSapling => SimplifiedBlockKind::Sapling, + BlockKind::PottedDarkOakSapling => SimplifiedBlockKind::Sapling, + BlockKind::PottedFern => SimplifiedBlockKind::PottedFern, + BlockKind::PottedDandelion => SimplifiedBlockKind::PottedDandelion, + BlockKind::PottedPoppy => SimplifiedBlockKind::PottedPoppy, + BlockKind::PottedBlueOrchid => SimplifiedBlockKind::Flower, + BlockKind::PottedAllium => SimplifiedBlockKind::PottedAllium, + BlockKind::PottedAzureBluet => SimplifiedBlockKind::Flower, + BlockKind::PottedRedTulip => SimplifiedBlockKind::Flower, + BlockKind::PottedOrangeTulip => SimplifiedBlockKind::Flower, + BlockKind::PottedWhiteTulip => SimplifiedBlockKind::Flower, + BlockKind::PottedPinkTulip => SimplifiedBlockKind::Flower, + BlockKind::PottedOxeyeDaisy => SimplifiedBlockKind::Flower, + BlockKind::PottedCornflower => SimplifiedBlockKind::PottedCornflower, + BlockKind::PottedLilyOfTheValley => SimplifiedBlockKind::PottedLilyOfTheValley, + BlockKind::PottedWitherRose => SimplifiedBlockKind::PottedWitherRose, + BlockKind::PottedRedMushroom => SimplifiedBlockKind::Mushroom, + BlockKind::PottedBrownMushroom => SimplifiedBlockKind::Mushroom, + BlockKind::PottedDeadBush => SimplifiedBlockKind::PottedDeadBush, + BlockKind::PottedCactus => SimplifiedBlockKind::PottedCactus, + BlockKind::Carrots => SimplifiedBlockKind::Carrots, + BlockKind::Potatoes => SimplifiedBlockKind::Potatoes, + BlockKind::OakButton => SimplifiedBlockKind::WoodenButton, + BlockKind::SpruceButton => SimplifiedBlockKind::WoodenButton, + BlockKind::BirchButton => SimplifiedBlockKind::WoodenButton, + BlockKind::JungleButton => SimplifiedBlockKind::WoodenButton, + BlockKind::AcaciaButton => SimplifiedBlockKind::WoodenButton, + BlockKind::DarkOakButton => SimplifiedBlockKind::WoodenButton, + BlockKind::SkeletonSkull => SimplifiedBlockKind::SkeletonSkull, + BlockKind::SkeletonWallSkull => SimplifiedBlockKind::SkeletonWallSkull, + BlockKind::WitherSkeletonSkull => SimplifiedBlockKind::WitherSkeletonSkull, + BlockKind::WitherSkeletonWallSkull => SimplifiedBlockKind::WitherSkeletonWallSkull, + BlockKind::ZombieHead => SimplifiedBlockKind::ZombieHead, + BlockKind::ZombieWallHead => SimplifiedBlockKind::ZombieWallHead, + BlockKind::PlayerHead => SimplifiedBlockKind::PlayerHead, + BlockKind::PlayerWallHead => SimplifiedBlockKind::PlayerWallHead, + BlockKind::CreeperHead => SimplifiedBlockKind::CreeperHead, + BlockKind::CreeperWallHead => SimplifiedBlockKind::CreeperWallHead, + BlockKind::DragonHead => SimplifiedBlockKind::DragonHead, + BlockKind::DragonWallHead => SimplifiedBlockKind::DragonWallHead, + BlockKind::Anvil => SimplifiedBlockKind::Anvil, + BlockKind::ChippedAnvil => SimplifiedBlockKind::Anvil, + BlockKind::DamagedAnvil => SimplifiedBlockKind::Anvil, + BlockKind::TrappedChest => SimplifiedBlockKind::TrappedChest, + BlockKind::LightWeightedPressurePlate => { + SimplifiedBlockKind::LightWeightedPressurePlate + } + BlockKind::HeavyWeightedPressurePlate => { + SimplifiedBlockKind::HeavyWeightedPressurePlate + } + BlockKind::Comparator => SimplifiedBlockKind::Comparator, + BlockKind::DaylightDetector => SimplifiedBlockKind::DaylightDetector, + BlockKind::RedstoneBlock => SimplifiedBlockKind::RedstoneBlock, + BlockKind::NetherQuartzOre => SimplifiedBlockKind::NetherQuartzOre, + BlockKind::Hopper => SimplifiedBlockKind::Hopper, + BlockKind::QuartzBlock => SimplifiedBlockKind::QuartzBlock, + BlockKind::ChiseledQuartzBlock => SimplifiedBlockKind::ChiseledQuartzBlock, + BlockKind::QuartzPillar => SimplifiedBlockKind::QuartzPillar, + BlockKind::QuartzStairs => SimplifiedBlockKind::Stairs, + BlockKind::ActivatorRail => SimplifiedBlockKind::ActivatorRail, + BlockKind::Dropper => SimplifiedBlockKind::Dropper, + BlockKind::WhiteTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::OrangeTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::MagentaTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::LightBlueTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::YellowTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::LimeTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::PinkTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::GrayTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::LightGrayTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::CyanTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::PurpleTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::BlueTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::BrownTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::GreenTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::RedTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::BlackTerracotta => SimplifiedBlockKind::Teracotta, + BlockKind::WhiteStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::OrangeStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::MagentaStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::LightBlueStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::YellowStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::LimeStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::PinkStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::GrayStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::LightGrayStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::CyanStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::PurpleStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::BlueStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::BrownStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::GreenStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::RedStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::BlackStainedGlassPane => SimplifiedBlockKind::StainedGlassPane, + BlockKind::AcaciaStairs => SimplifiedBlockKind::Stairs, + BlockKind::DarkOakStairs => SimplifiedBlockKind::Stairs, + BlockKind::SlimeBlock => SimplifiedBlockKind::SlimeBlock, + BlockKind::Barrier => SimplifiedBlockKind::Barrier, + BlockKind::IronTrapdoor => SimplifiedBlockKind::IronTrapdoor, + BlockKind::Prismarine => SimplifiedBlockKind::Prismarine, + BlockKind::PrismarineBricks => SimplifiedBlockKind::PrismarineBricks, + BlockKind::DarkPrismarine => SimplifiedBlockKind::DarkPrismarine, + BlockKind::PrismarineStairs => SimplifiedBlockKind::Stairs, + BlockKind::PrismarineBrickStairs => SimplifiedBlockKind::Stairs, + BlockKind::DarkPrismarineStairs => SimplifiedBlockKind::Stairs, + BlockKind::PrismarineSlab => SimplifiedBlockKind::Slab, + BlockKind::PrismarineBrickSlab => SimplifiedBlockKind::Slab, + BlockKind::DarkPrismarineSlab => SimplifiedBlockKind::Slab, + BlockKind::SeaLantern => SimplifiedBlockKind::SeaLantern, + BlockKind::HayBlock => SimplifiedBlockKind::HayBlock, + BlockKind::WhiteCarpet => SimplifiedBlockKind::Carpet, + BlockKind::OrangeCarpet => SimplifiedBlockKind::Carpet, + BlockKind::MagentaCarpet => SimplifiedBlockKind::Carpet, + BlockKind::LightBlueCarpet => SimplifiedBlockKind::Carpet, + BlockKind::YellowCarpet => SimplifiedBlockKind::Carpet, + BlockKind::LimeCarpet => SimplifiedBlockKind::Carpet, + BlockKind::PinkCarpet => SimplifiedBlockKind::Carpet, + BlockKind::GrayCarpet => SimplifiedBlockKind::Carpet, + BlockKind::LightGrayCarpet => SimplifiedBlockKind::Carpet, + BlockKind::CyanCarpet => SimplifiedBlockKind::Carpet, + BlockKind::PurpleCarpet => SimplifiedBlockKind::Carpet, + BlockKind::BlueCarpet => SimplifiedBlockKind::Carpet, + BlockKind::BrownCarpet => SimplifiedBlockKind::Carpet, + BlockKind::GreenCarpet => SimplifiedBlockKind::Carpet, + BlockKind::RedCarpet => SimplifiedBlockKind::Carpet, + BlockKind::BlackCarpet => SimplifiedBlockKind::Carpet, + BlockKind::Terracotta => SimplifiedBlockKind::Teracotta, + BlockKind::CoalBlock => SimplifiedBlockKind::CoalBlock, + BlockKind::PackedIce => SimplifiedBlockKind::PackedIce, + BlockKind::Sunflower => SimplifiedBlockKind::Sunflower, + BlockKind::Lilac => SimplifiedBlockKind::Lilac, + BlockKind::RoseBush => SimplifiedBlockKind::RoseBush, + BlockKind::Peony => SimplifiedBlockKind::Peony, + BlockKind::TallGrass => SimplifiedBlockKind::TallGrass, + BlockKind::LargeFern => SimplifiedBlockKind::LargeFern, + BlockKind::WhiteBanner => SimplifiedBlockKind::Banner, + BlockKind::OrangeBanner => SimplifiedBlockKind::Banner, + BlockKind::MagentaBanner => SimplifiedBlockKind::Banner, + BlockKind::LightBlueBanner => SimplifiedBlockKind::Banner, + BlockKind::YellowBanner => SimplifiedBlockKind::Banner, + BlockKind::LimeBanner => SimplifiedBlockKind::Banner, + BlockKind::PinkBanner => SimplifiedBlockKind::Banner, + BlockKind::GrayBanner => SimplifiedBlockKind::Banner, + BlockKind::LightGrayBanner => SimplifiedBlockKind::Banner, + BlockKind::CyanBanner => SimplifiedBlockKind::Banner, + BlockKind::PurpleBanner => SimplifiedBlockKind::Banner, + BlockKind::BlueBanner => SimplifiedBlockKind::Banner, + BlockKind::BrownBanner => SimplifiedBlockKind::Banner, + BlockKind::GreenBanner => SimplifiedBlockKind::Banner, + BlockKind::RedBanner => SimplifiedBlockKind::Banner, + BlockKind::BlackBanner => SimplifiedBlockKind::Banner, + BlockKind::WhiteWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::OrangeWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::MagentaWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::LightBlueWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::YellowWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::LimeWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::PinkWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::GrayWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::LightGrayWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::CyanWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::PurpleWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::BlueWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::BrownWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::GreenWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::RedWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::BlackWallBanner => SimplifiedBlockKind::WallBanner, + BlockKind::RedSandstone => SimplifiedBlockKind::RedSandstone, + BlockKind::ChiseledRedSandstone => SimplifiedBlockKind::ChiseledRedSandstone, + BlockKind::CutRedSandstone => SimplifiedBlockKind::CutRedSandstone, + BlockKind::RedSandstoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::OakSlab => SimplifiedBlockKind::Slab, + BlockKind::SpruceSlab => SimplifiedBlockKind::Slab, + BlockKind::BirchSlab => SimplifiedBlockKind::Slab, + BlockKind::JungleSlab => SimplifiedBlockKind::Slab, + BlockKind::AcaciaSlab => SimplifiedBlockKind::Slab, + BlockKind::DarkOakSlab => SimplifiedBlockKind::Slab, + BlockKind::StoneSlab => SimplifiedBlockKind::Slab, + BlockKind::SmoothStoneSlab => SimplifiedBlockKind::Slab, + BlockKind::SandstoneSlab => SimplifiedBlockKind::Slab, + BlockKind::CutSandstoneSlab => SimplifiedBlockKind::Slab, + BlockKind::PetrifiedOakSlab => SimplifiedBlockKind::Slab, + BlockKind::CobblestoneSlab => SimplifiedBlockKind::Slab, + BlockKind::BrickSlab => SimplifiedBlockKind::Slab, + BlockKind::StoneBrickSlab => SimplifiedBlockKind::Slab, + BlockKind::NetherBrickSlab => SimplifiedBlockKind::Slab, + BlockKind::QuartzSlab => SimplifiedBlockKind::Slab, + BlockKind::RedSandstoneSlab => SimplifiedBlockKind::Slab, + BlockKind::CutRedSandstoneSlab => SimplifiedBlockKind::Slab, + BlockKind::PurpurSlab => SimplifiedBlockKind::Slab, + BlockKind::SmoothStone => SimplifiedBlockKind::SmoothStone, + BlockKind::SmoothSandstone => SimplifiedBlockKind::SmoothSandstone, + BlockKind::SmoothQuartz => SimplifiedBlockKind::SmoothQuartz, + BlockKind::SmoothRedSandstone => SimplifiedBlockKind::SmoothRedSandstone, + BlockKind::SpruceFenceGate => SimplifiedBlockKind::FenceGate, + BlockKind::BirchFenceGate => SimplifiedBlockKind::FenceGate, + BlockKind::JungleFenceGate => SimplifiedBlockKind::FenceGate, + BlockKind::AcaciaFenceGate => SimplifiedBlockKind::FenceGate, + BlockKind::DarkOakFenceGate => SimplifiedBlockKind::FenceGate, + BlockKind::SpruceFence => SimplifiedBlockKind::Fence, + BlockKind::BirchFence => SimplifiedBlockKind::Fence, + BlockKind::JungleFence => SimplifiedBlockKind::Fence, + BlockKind::AcaciaFence => SimplifiedBlockKind::Fence, + BlockKind::DarkOakFence => SimplifiedBlockKind::Fence, + BlockKind::SpruceDoor => SimplifiedBlockKind::WoodenDoor, + BlockKind::BirchDoor => SimplifiedBlockKind::WoodenDoor, + BlockKind::JungleDoor => SimplifiedBlockKind::WoodenDoor, + BlockKind::AcaciaDoor => SimplifiedBlockKind::WoodenDoor, + BlockKind::DarkOakDoor => SimplifiedBlockKind::WoodenDoor, + BlockKind::EndRod => SimplifiedBlockKind::EndRod, + BlockKind::ChorusPlant => SimplifiedBlockKind::ChorusPlant, + BlockKind::ChorusFlower => SimplifiedBlockKind::ChorusFlower, + BlockKind::PurpurBlock => SimplifiedBlockKind::PurpurBlock, + BlockKind::PurpurPillar => SimplifiedBlockKind::PurpurPillar, + BlockKind::PurpurStairs => SimplifiedBlockKind::Stairs, + BlockKind::EndStoneBricks => SimplifiedBlockKind::EndStoneBricks, + BlockKind::Beetroots => SimplifiedBlockKind::Beetroots, + BlockKind::GrassPath => SimplifiedBlockKind::GrassPath, + BlockKind::EndGateway => SimplifiedBlockKind::EndGateway, + BlockKind::RepeatingCommandBlock => SimplifiedBlockKind::RepeatingCommandBlock, + BlockKind::ChainCommandBlock => SimplifiedBlockKind::ChainCommandBlock, + BlockKind::FrostedIce => SimplifiedBlockKind::FrostedIce, + BlockKind::MagmaBlock => SimplifiedBlockKind::MagmaBlock, + BlockKind::NetherWartBlock => SimplifiedBlockKind::NetherWartBlock, + BlockKind::RedNetherBricks => SimplifiedBlockKind::RedNetherBricks, + BlockKind::BoneBlock => SimplifiedBlockKind::BoneBlock, + BlockKind::StructureVoid => SimplifiedBlockKind::StructureVoid, + BlockKind::Observer => SimplifiedBlockKind::Observer, + BlockKind::ShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::WhiteShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::OrangeShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::MagentaShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::LightBlueShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::YellowShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::LimeShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::PinkShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::GrayShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::LightGrayShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::CyanShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::PurpleShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::BlueShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::BrownShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::GreenShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::RedShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::BlackShulkerBox => SimplifiedBlockKind::ShulkerBox, + BlockKind::WhiteGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::OrangeGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::MagentaGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::LightBlueGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::YellowGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::LimeGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::PinkGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::GrayGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::LightGrayGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::CyanGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::PurpleGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::BlueGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::BrownGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::GreenGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::RedGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::BlackGlazedTerracotta => SimplifiedBlockKind::GlazedTeracotta, + BlockKind::WhiteConcrete => SimplifiedBlockKind::Concrete, + BlockKind::OrangeConcrete => SimplifiedBlockKind::Concrete, + BlockKind::MagentaConcrete => SimplifiedBlockKind::Concrete, + BlockKind::LightBlueConcrete => SimplifiedBlockKind::Concrete, + BlockKind::YellowConcrete => SimplifiedBlockKind::Concrete, + BlockKind::LimeConcrete => SimplifiedBlockKind::Concrete, + BlockKind::PinkConcrete => SimplifiedBlockKind::Concrete, + BlockKind::GrayConcrete => SimplifiedBlockKind::Concrete, + BlockKind::LightGrayConcrete => SimplifiedBlockKind::Concrete, + BlockKind::CyanConcrete => SimplifiedBlockKind::Concrete, + BlockKind::PurpleConcrete => SimplifiedBlockKind::Concrete, + BlockKind::BlueConcrete => SimplifiedBlockKind::Concrete, + BlockKind::BrownConcrete => SimplifiedBlockKind::Concrete, + BlockKind::GreenConcrete => SimplifiedBlockKind::Concrete, + BlockKind::RedConcrete => SimplifiedBlockKind::Concrete, + BlockKind::BlackConcrete => SimplifiedBlockKind::Concrete, + BlockKind::WhiteConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::OrangeConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::MagentaConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::LightBlueConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::YellowConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::LimeConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::PinkConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::GrayConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::LightGrayConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::CyanConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::PurpleConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::BlueConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::BrownConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::GreenConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::RedConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::BlackConcretePowder => SimplifiedBlockKind::ConcretePowder, + BlockKind::Kelp => SimplifiedBlockKind::Kelp, + BlockKind::KelpPlant => SimplifiedBlockKind::KelpPlant, + BlockKind::DriedKelpBlock => SimplifiedBlockKind::DriedKelpBlock, + BlockKind::TurtleEgg => SimplifiedBlockKind::TurtleEgg, + BlockKind::DeadTubeCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::DeadBrainCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::DeadBubbleCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::DeadFireCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::DeadHornCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::TubeCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::BrainCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::BubbleCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::FireCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::HornCoralBlock => SimplifiedBlockKind::CoralBlock, + BlockKind::DeadTubeCoral => SimplifiedBlockKind::Coral, + BlockKind::DeadBrainCoral => SimplifiedBlockKind::Coral, + BlockKind::DeadBubbleCoral => SimplifiedBlockKind::Coral, + BlockKind::DeadFireCoral => SimplifiedBlockKind::Coral, + BlockKind::DeadHornCoral => SimplifiedBlockKind::Coral, + BlockKind::TubeCoral => SimplifiedBlockKind::Coral, + BlockKind::BrainCoral => SimplifiedBlockKind::Coral, + BlockKind::BubbleCoral => SimplifiedBlockKind::Coral, + BlockKind::FireCoral => SimplifiedBlockKind::Coral, + BlockKind::HornCoral => SimplifiedBlockKind::Coral, + BlockKind::DeadTubeCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::DeadBrainCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::DeadBubbleCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::DeadFireCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::DeadHornCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::TubeCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::BrainCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::BubbleCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::FireCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::HornCoralFan => SimplifiedBlockKind::CoralFan, + BlockKind::DeadTubeCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::DeadBrainCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::DeadBubbleCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::DeadFireCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::DeadHornCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::TubeCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::BrainCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::BubbleCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::FireCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::HornCoralWallFan => SimplifiedBlockKind::CoralWallFan, + BlockKind::SeaPickle => SimplifiedBlockKind::SeaPickle, + BlockKind::BlueIce => SimplifiedBlockKind::BlueIce, + BlockKind::Conduit => SimplifiedBlockKind::Conduit, + BlockKind::BambooSapling => SimplifiedBlockKind::Sapling, + BlockKind::Bamboo => SimplifiedBlockKind::Bamboo, + BlockKind::PottedBamboo => SimplifiedBlockKind::PottedBamboo, + BlockKind::VoidAir => SimplifiedBlockKind::Air, + BlockKind::CaveAir => SimplifiedBlockKind::Air, + BlockKind::BubbleColumn => SimplifiedBlockKind::BubbleColumn, + BlockKind::PolishedGraniteStairs => SimplifiedBlockKind::Stairs, + BlockKind::SmoothRedSandstoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::MossyStoneBrickStairs => SimplifiedBlockKind::Stairs, + BlockKind::PolishedDioriteStairs => SimplifiedBlockKind::Stairs, + BlockKind::MossyCobblestoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::EndStoneBrickStairs => SimplifiedBlockKind::Stairs, + BlockKind::StoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::SmoothSandstoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::SmoothQuartzStairs => SimplifiedBlockKind::Stairs, + BlockKind::GraniteStairs => SimplifiedBlockKind::Stairs, + BlockKind::AndesiteStairs => SimplifiedBlockKind::Stairs, + BlockKind::RedNetherBrickStairs => SimplifiedBlockKind::Stairs, + BlockKind::PolishedAndesiteStairs => SimplifiedBlockKind::Stairs, + BlockKind::DioriteStairs => SimplifiedBlockKind::Stairs, + BlockKind::PolishedGraniteSlab => SimplifiedBlockKind::Slab, + BlockKind::SmoothRedSandstoneSlab => SimplifiedBlockKind::Slab, + BlockKind::MossyStoneBrickSlab => SimplifiedBlockKind::Slab, + BlockKind::PolishedDioriteSlab => SimplifiedBlockKind::Slab, + BlockKind::MossyCobblestoneSlab => SimplifiedBlockKind::Slab, + BlockKind::EndStoneBrickSlab => SimplifiedBlockKind::Slab, + BlockKind::SmoothSandstoneSlab => SimplifiedBlockKind::Slab, + BlockKind::SmoothQuartzSlab => SimplifiedBlockKind::Slab, + BlockKind::GraniteSlab => SimplifiedBlockKind::Slab, + BlockKind::AndesiteSlab => SimplifiedBlockKind::Slab, + BlockKind::RedNetherBrickSlab => SimplifiedBlockKind::Slab, + BlockKind::PolishedAndesiteSlab => SimplifiedBlockKind::Slab, + BlockKind::DioriteSlab => SimplifiedBlockKind::Slab, + BlockKind::BrickWall => SimplifiedBlockKind::BrickWall, + BlockKind::PrismarineWall => SimplifiedBlockKind::PrismarineWall, + BlockKind::RedSandstoneWall => SimplifiedBlockKind::RedSandstoneWall, + BlockKind::MossyStoneBrickWall => SimplifiedBlockKind::MossyStoneBrickWall, + BlockKind::GraniteWall => SimplifiedBlockKind::GraniteWall, + BlockKind::StoneBrickWall => SimplifiedBlockKind::StoneBrickWall, + BlockKind::NetherBrickWall => SimplifiedBlockKind::NetherBrickWall, + BlockKind::AndesiteWall => SimplifiedBlockKind::AndesiteWall, + BlockKind::RedNetherBrickWall => SimplifiedBlockKind::RedNetherBrickWall, + BlockKind::SandstoneWall => SimplifiedBlockKind::SandstoneWall, + BlockKind::EndStoneBrickWall => SimplifiedBlockKind::EndStoneBrickWall, + BlockKind::DioriteWall => SimplifiedBlockKind::DioriteWall, + BlockKind::Scaffolding => SimplifiedBlockKind::Scaffolding, + BlockKind::Loom => SimplifiedBlockKind::Loom, + BlockKind::Barrel => SimplifiedBlockKind::Barrel, + BlockKind::Smoker => SimplifiedBlockKind::Smoker, + BlockKind::BlastFurnace => SimplifiedBlockKind::BlastFurnace, + BlockKind::CartographyTable => SimplifiedBlockKind::CartographyTable, + BlockKind::FletchingTable => SimplifiedBlockKind::FletchingTable, + BlockKind::Grindstone => SimplifiedBlockKind::Grindstone, + BlockKind::Lectern => SimplifiedBlockKind::Lectern, + BlockKind::SmithingTable => SimplifiedBlockKind::SmithingTable, + BlockKind::Stonecutter => SimplifiedBlockKind::Stonecutter, + BlockKind::Bell => SimplifiedBlockKind::Bell, + BlockKind::Lantern => SimplifiedBlockKind::Lantern, + BlockKind::SoulLantern => SimplifiedBlockKind::SoulLantern, + BlockKind::Campfire => SimplifiedBlockKind::Campfire, + BlockKind::SoulCampfire => SimplifiedBlockKind::SoulCampfire, + BlockKind::SweetBerryBush => SimplifiedBlockKind::SweetBerryBush, + BlockKind::WarpedStem => SimplifiedBlockKind::WarpedStem, + BlockKind::StrippedWarpedStem => SimplifiedBlockKind::StrippedWarpedStem, + BlockKind::WarpedHyphae => SimplifiedBlockKind::WarpedHyphae, + BlockKind::StrippedWarpedHyphae => SimplifiedBlockKind::StrippedWarpedHyphae, + BlockKind::WarpedNylium => SimplifiedBlockKind::WarpedNylium, + BlockKind::WarpedFungus => SimplifiedBlockKind::WarpedFungus, + BlockKind::WarpedWartBlock => SimplifiedBlockKind::WarpedWartBlock, + BlockKind::WarpedRoots => SimplifiedBlockKind::WarpedRoots, + BlockKind::NetherSprouts => SimplifiedBlockKind::NetherSprouts, + BlockKind::CrimsonStem => SimplifiedBlockKind::CrimsonStem, + BlockKind::StrippedCrimsonStem => SimplifiedBlockKind::StrippedCrimsonStem, + BlockKind::CrimsonHyphae => SimplifiedBlockKind::CrimsonHyphae, + BlockKind::StrippedCrimsonHyphae => SimplifiedBlockKind::StrippedCrimsonHyphae, + BlockKind::CrimsonNylium => SimplifiedBlockKind::CrimsonNylium, + BlockKind::CrimsonFungus => SimplifiedBlockKind::CrimsonFungus, + BlockKind::Shroomlight => SimplifiedBlockKind::Shroomlight, + BlockKind::WeepingVines => SimplifiedBlockKind::WeepingVines, + BlockKind::WeepingVinesPlant => SimplifiedBlockKind::WeepingVinesPlant, + BlockKind::TwistingVines => SimplifiedBlockKind::TwistingVines, + BlockKind::TwistingVinesPlant => SimplifiedBlockKind::TwistingVinesPlant, + BlockKind::CrimsonRoots => SimplifiedBlockKind::CrimsonRoots, + BlockKind::CrimsonPlanks => SimplifiedBlockKind::Planks, + BlockKind::WarpedPlanks => SimplifiedBlockKind::Planks, + BlockKind::CrimsonSlab => SimplifiedBlockKind::Slab, + BlockKind::WarpedSlab => SimplifiedBlockKind::Slab, + BlockKind::CrimsonPressurePlate => SimplifiedBlockKind::CrimsonPressurePlate, + BlockKind::WarpedPressurePlate => SimplifiedBlockKind::WarpedPressurePlate, + BlockKind::CrimsonFence => SimplifiedBlockKind::Fence, + BlockKind::WarpedFence => SimplifiedBlockKind::Fence, + BlockKind::CrimsonTrapdoor => SimplifiedBlockKind::CrimsonTrapdoor, + BlockKind::WarpedTrapdoor => SimplifiedBlockKind::WarpedTrapdoor, + BlockKind::CrimsonFenceGate => SimplifiedBlockKind::FenceGate, + BlockKind::WarpedFenceGate => SimplifiedBlockKind::FenceGate, + BlockKind::CrimsonStairs => SimplifiedBlockKind::Stairs, + BlockKind::WarpedStairs => SimplifiedBlockKind::Stairs, + BlockKind::CrimsonButton => SimplifiedBlockKind::CrimsonButton, + BlockKind::WarpedButton => SimplifiedBlockKind::WarpedButton, + BlockKind::CrimsonDoor => SimplifiedBlockKind::CrimsonDoor, + BlockKind::WarpedDoor => SimplifiedBlockKind::WarpedDoor, + BlockKind::CrimsonSign => SimplifiedBlockKind::Sign, + BlockKind::WarpedSign => SimplifiedBlockKind::Sign, + BlockKind::CrimsonWallSign => SimplifiedBlockKind::WallSign, + BlockKind::WarpedWallSign => SimplifiedBlockKind::WallSign, + BlockKind::StructureBlock => SimplifiedBlockKind::StructureBlock, + BlockKind::Jigsaw => SimplifiedBlockKind::Jigsaw, + BlockKind::Composter => SimplifiedBlockKind::Composter, + BlockKind::Target => SimplifiedBlockKind::Target, + BlockKind::BeeNest => SimplifiedBlockKind::BeeNest, + BlockKind::Beehive => SimplifiedBlockKind::Beehive, + BlockKind::HoneyBlock => SimplifiedBlockKind::HoneyBlock, + BlockKind::HoneycombBlock => SimplifiedBlockKind::HoneycombBlock, + BlockKind::NetheriteBlock => SimplifiedBlockKind::NetheriteBlock, + BlockKind::AncientDebris => SimplifiedBlockKind::AncientDebris, + BlockKind::CryingObsidian => SimplifiedBlockKind::CryingObsidian, + BlockKind::RespawnAnchor => SimplifiedBlockKind::RespawnAnchor, + BlockKind::PottedCrimsonFungus => SimplifiedBlockKind::PottedCrimsonFungus, + BlockKind::PottedWarpedFungus => SimplifiedBlockKind::PottedWarpedFungus, + BlockKind::PottedCrimsonRoots => SimplifiedBlockKind::PottedCrimsonRoots, + BlockKind::PottedWarpedRoots => SimplifiedBlockKind::PottedWarpedRoots, + BlockKind::Lodestone => SimplifiedBlockKind::Lodestone, + BlockKind::Blackstone => SimplifiedBlockKind::Blackstone, + BlockKind::BlackstoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::BlackstoneWall => SimplifiedBlockKind::BlackstoneWall, + BlockKind::BlackstoneSlab => SimplifiedBlockKind::Slab, + BlockKind::PolishedBlackstone => SimplifiedBlockKind::PolishedBlackstone, + BlockKind::PolishedBlackstoneBricks => SimplifiedBlockKind::PolishedBlackstoneBricks, + BlockKind::CrackedPolishedBlackstoneBricks => { + SimplifiedBlockKind::CrackedPolishedBlackstoneBricks + } + BlockKind::ChiseledPolishedBlackstone => { + SimplifiedBlockKind::ChiseledPolishedBlackstone + } + BlockKind::PolishedBlackstoneBrickSlab => SimplifiedBlockKind::Slab, + BlockKind::PolishedBlackstoneBrickStairs => SimplifiedBlockKind::Stairs, + BlockKind::PolishedBlackstoneBrickWall => { + SimplifiedBlockKind::PolishedBlackstoneBrickWall + } + BlockKind::GildedBlackstone => SimplifiedBlockKind::GildedBlackstone, + BlockKind::PolishedBlackstoneStairs => SimplifiedBlockKind::Stairs, + BlockKind::PolishedBlackstoneSlab => SimplifiedBlockKind::Slab, + BlockKind::PolishedBlackstonePressurePlate => { + SimplifiedBlockKind::PolishedBlackstonePressurePlate + } + BlockKind::PolishedBlackstoneButton => SimplifiedBlockKind::PolishedBlackstoneButton, + BlockKind::PolishedBlackstoneWall => SimplifiedBlockKind::PolishedBlackstoneWall, + BlockKind::ChiseledNetherBricks => SimplifiedBlockKind::ChiseledNetherBricks, + BlockKind::CrackedNetherBricks => SimplifiedBlockKind::CrackedNetherBricks, + BlockKind::QuartzBricks => SimplifiedBlockKind::QuartzBricks, + } + } +} diff --git a/libcraft/blocks/tests/blocks.rs b/libcraft/blocks/tests/blocks.rs new file mode 100644 index 000000000..b9ff9108f --- /dev/null +++ b/libcraft/blocks/tests/blocks.rs @@ -0,0 +1,53 @@ +use std::time::Instant; + +use libcraft_blocks::{Ageable, BlockState}; + +#[test] +fn update_block_data() { + let start = Instant::now(); + + let mut block = BlockState::from_id(1485).unwrap(); + let mut fire = block.data_as::<Ageable>().unwrap(); + assert_eq!(fire.age(), 1); + fire.set_age(3); + block.set_data(fire); + assert_eq!(block.data_as::<Ageable>().unwrap().age(), 3); + + println!("{:?}", start.elapsed()); +} + +#[test] +fn set_only_valid_values() { + let mut block = BlockState::from_id(1485).unwrap(); + let mut fire = block.data_as::<Ageable>().unwrap(); + assert_eq!(fire.age(), 1); + fire.set_age(20); + block.set_data(fire); + fire = block.data_as::<Ageable>().unwrap(); + assert_eq!(fire.age(), 1); + fire.set_age(15); + block.set_data(fire); + assert_eq!(block.data_as::<Ageable>().unwrap().age(), 15); +} + +#[test] +fn block_data_valid_properties() { + let block = BlockState::from_id(1485).unwrap(); + let fire = block.data_as::<Ageable>().unwrap(); + assert_eq!( + fire.valid_age(), + vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + ) +} + +#[test] +fn block_state_valid_properties() { + let block = BlockState::from_id(1485).unwrap(); + + assert_eq!( + block.get_valid_properties().age, + vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + ); + assert_eq!(block.get_valid_properties().up, vec![true, false]); + assert_eq!(block.get_valid_properties().waterlogged, Vec::new()) +} diff --git a/libcraft/core/Cargo.toml b/libcraft/core/Cargo.toml new file mode 100644 index 000000000..e4897a0b8 --- /dev/null +++ b/libcraft/core/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "libcraft-core" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +bytemuck = { version = "1", features = ["derive"] } +num-derive = "0.3" +num-traits = "0.2" +serde = { version = "1", features = ["derive"] } +strum = "0.21" +strum_macros = "0.21" +vek = "0.14" \ No newline at end of file diff --git a/libcraft/core/src/biome.rs b/libcraft/core/src/biome.rs new file mode 100644 index 000000000..2b81c3bc5 --- /dev/null +++ b/libcraft/core/src/biome.rs @@ -0,0 +1,783 @@ +// This file is @generated. Please do not edit. + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Biome { + Ocean, + Plains, + Desert, + Mountains, + Forest, + Taiga, + Swamp, + River, + NetherWastes, + TheEnd, + FrozenOcean, + FrozenRiver, + SnowyTundra, + SnowyMountains, + MushroomFields, + MushroomFieldShore, + Beach, + DesertHills, + WoodedHills, + TaigaHills, + MountainEdge, + Jungle, + JungleHills, + JungleEdge, + DeepOcean, + StoneShore, + SnowyBeach, + BirchForest, + BirchForestHills, + DarkForest, + SnowyTaiga, + SnowyTaigaHills, + GiantTreeTaiga, + GiantTreeTaigaHills, + WoodedMountains, + Savanna, + SavannaPlateau, + Badlands, + WoodedBadlandsPlateau, + BadlandsPlateau, + SmallEndIslands, + EndMidlands, + EndHighlands, + EndBarrens, + WarmOcean, + LukewarmOcean, + ColdOcean, + DeepWarmOcean, + DeepLukewarmOcean, + DeepColdOcean, + DeepFrozenOcean, + TheVoid, + SunflowerPlains, + DesertLakes, + GravellyMountains, + FlowerForest, + TaigaMountains, + SwampHills, + IceSpikes, + ModifiedJungle, + ModifiedJungleEdge, + TallBirchForest, + TallBirchHills, + DarkForestHills, + SnowyTaigaMountains, + GiantSpruceTaiga, + GiantSpruceTaigaHills, + ModifiedGravellyMountains, + ShatteredSavanna, + ShatteredSavannaPlateau, + ErodedBadlands, + ModifiedWoodedBadlandsPlateau, + ModifiedBadlandsPlateau, + BambooJungle, + BambooJungleHills, + SoulSandValley, + CrimsonForest, + WarpedForest, + BasaltDeltas, +} + +#[allow(warnings)] +#[allow(clippy::all)] +impl Biome { + /// Returns the `id` property of this `Biome`. + pub fn id(&self) -> u32 { + match self { + Biome::Ocean => 0, + Biome::Plains => 1, + Biome::Desert => 2, + Biome::Mountains => 3, + Biome::Forest => 4, + Biome::Taiga => 5, + Biome::Swamp => 6, + Biome::River => 7, + Biome::NetherWastes => 8, + Biome::TheEnd => 9, + Biome::FrozenOcean => 10, + Biome::FrozenRiver => 11, + Biome::SnowyTundra => 12, + Biome::SnowyMountains => 13, + Biome::MushroomFields => 14, + Biome::MushroomFieldShore => 15, + Biome::Beach => 16, + Biome::DesertHills => 17, + Biome::WoodedHills => 18, + Biome::TaigaHills => 19, + Biome::MountainEdge => 20, + Biome::Jungle => 21, + Biome::JungleHills => 22, + Biome::JungleEdge => 23, + Biome::DeepOcean => 24, + Biome::StoneShore => 25, + Biome::SnowyBeach => 26, + Biome::BirchForest => 27, + Biome::BirchForestHills => 28, + Biome::DarkForest => 29, + Biome::SnowyTaiga => 30, + Biome::SnowyTaigaHills => 31, + Biome::GiantTreeTaiga => 32, + Biome::GiantTreeTaigaHills => 33, + Biome::WoodedMountains => 34, + Biome::Savanna => 35, + Biome::SavannaPlateau => 36, + Biome::Badlands => 37, + Biome::WoodedBadlandsPlateau => 38, + Biome::BadlandsPlateau => 39, + Biome::SmallEndIslands => 40, + Biome::EndMidlands => 41, + Biome::EndHighlands => 42, + Biome::EndBarrens => 43, + Biome::WarmOcean => 44, + Biome::LukewarmOcean => 45, + Biome::ColdOcean => 46, + Biome::DeepWarmOcean => 47, + Biome::DeepLukewarmOcean => 48, + Biome::DeepColdOcean => 49, + Biome::DeepFrozenOcean => 50, + Biome::TheVoid => 127, + Biome::SunflowerPlains => 129, + Biome::DesertLakes => 130, + Biome::GravellyMountains => 131, + Biome::FlowerForest => 132, + Biome::TaigaMountains => 133, + Biome::SwampHills => 134, + Biome::IceSpikes => 140, + Biome::ModifiedJungle => 149, + Biome::ModifiedJungleEdge => 151, + Biome::TallBirchForest => 155, + Biome::TallBirchHills => 156, + Biome::DarkForestHills => 157, + Biome::SnowyTaigaMountains => 158, + Biome::GiantSpruceTaiga => 160, + Biome::GiantSpruceTaigaHills => 161, + Biome::ModifiedGravellyMountains => 162, + Biome::ShatteredSavanna => 163, + Biome::ShatteredSavannaPlateau => 164, + Biome::ErodedBadlands => 165, + Biome::ModifiedWoodedBadlandsPlateau => 166, + Biome::ModifiedBadlandsPlateau => 167, + Biome::BambooJungle => 168, + Biome::BambooJungleHills => 169, + Biome::SoulSandValley => 170, + Biome::CrimsonForest => 171, + Biome::WarpedForest => 172, + Biome::BasaltDeltas => 173, + } + } + + /// Gets a `Biome` by its `id`. + pub fn from_id(id: u32) -> Option<Self> { + match id { + 0 => Some(Biome::Ocean), + 1 => Some(Biome::Plains), + 2 => Some(Biome::Desert), + 3 => Some(Biome::Mountains), + 4 => Some(Biome::Forest), + 5 => Some(Biome::Taiga), + 6 => Some(Biome::Swamp), + 7 => Some(Biome::River), + 8 => Some(Biome::NetherWastes), + 9 => Some(Biome::TheEnd), + 10 => Some(Biome::FrozenOcean), + 11 => Some(Biome::FrozenRiver), + 12 => Some(Biome::SnowyTundra), + 13 => Some(Biome::SnowyMountains), + 14 => Some(Biome::MushroomFields), + 15 => Some(Biome::MushroomFieldShore), + 16 => Some(Biome::Beach), + 17 => Some(Biome::DesertHills), + 18 => Some(Biome::WoodedHills), + 19 => Some(Biome::TaigaHills), + 20 => Some(Biome::MountainEdge), + 21 => Some(Biome::Jungle), + 22 => Some(Biome::JungleHills), + 23 => Some(Biome::JungleEdge), + 24 => Some(Biome::DeepOcean), + 25 => Some(Biome::StoneShore), + 26 => Some(Biome::SnowyBeach), + 27 => Some(Biome::BirchForest), + 28 => Some(Biome::BirchForestHills), + 29 => Some(Biome::DarkForest), + 30 => Some(Biome::SnowyTaiga), + 31 => Some(Biome::SnowyTaigaHills), + 32 => Some(Biome::GiantTreeTaiga), + 33 => Some(Biome::GiantTreeTaigaHills), + 34 => Some(Biome::WoodedMountains), + 35 => Some(Biome::Savanna), + 36 => Some(Biome::SavannaPlateau), + 37 => Some(Biome::Badlands), + 38 => Some(Biome::WoodedBadlandsPlateau), + 39 => Some(Biome::BadlandsPlateau), + 40 => Some(Biome::SmallEndIslands), + 41 => Some(Biome::EndMidlands), + 42 => Some(Biome::EndHighlands), + 43 => Some(Biome::EndBarrens), + 44 => Some(Biome::WarmOcean), + 45 => Some(Biome::LukewarmOcean), + 46 => Some(Biome::ColdOcean), + 47 => Some(Biome::DeepWarmOcean), + 48 => Some(Biome::DeepLukewarmOcean), + 49 => Some(Biome::DeepColdOcean), + 50 => Some(Biome::DeepFrozenOcean), + 127 => Some(Biome::TheVoid), + 129 => Some(Biome::SunflowerPlains), + 130 => Some(Biome::DesertLakes), + 131 => Some(Biome::GravellyMountains), + 132 => Some(Biome::FlowerForest), + 133 => Some(Biome::TaigaMountains), + 134 => Some(Biome::SwampHills), + 140 => Some(Biome::IceSpikes), + 149 => Some(Biome::ModifiedJungle), + 151 => Some(Biome::ModifiedJungleEdge), + 155 => Some(Biome::TallBirchForest), + 156 => Some(Biome::TallBirchHills), + 157 => Some(Biome::DarkForestHills), + 158 => Some(Biome::SnowyTaigaMountains), + 160 => Some(Biome::GiantSpruceTaiga), + 161 => Some(Biome::GiantSpruceTaigaHills), + 162 => Some(Biome::ModifiedGravellyMountains), + 163 => Some(Biome::ShatteredSavanna), + 164 => Some(Biome::ShatteredSavannaPlateau), + 165 => Some(Biome::ErodedBadlands), + 166 => Some(Biome::ModifiedWoodedBadlandsPlateau), + 167 => Some(Biome::ModifiedBadlandsPlateau), + 168 => Some(Biome::BambooJungle), + 169 => Some(Biome::BambooJungleHills), + 170 => Some(Biome::SoulSandValley), + 171 => Some(Biome::CrimsonForest), + 172 => Some(Biome::WarpedForest), + 173 => Some(Biome::BasaltDeltas), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Biome { + /// Returns the `name` property of this `Biome`. + pub fn name(&self) -> &'static str { + match self { + Biome::Ocean => "ocean", + Biome::Plains => "plains", + Biome::Desert => "desert", + Biome::Mountains => "mountains", + Biome::Forest => "forest", + Biome::Taiga => "taiga", + Biome::Swamp => "swamp", + Biome::River => "river", + Biome::NetherWastes => "nether_wastes", + Biome::TheEnd => "the_end", + Biome::FrozenOcean => "frozen_ocean", + Biome::FrozenRiver => "frozen_river", + Biome::SnowyTundra => "snowy_tundra", + Biome::SnowyMountains => "snowy_mountains", + Biome::MushroomFields => "mushroom_fields", + Biome::MushroomFieldShore => "mushroom_field_shore", + Biome::Beach => "beach", + Biome::DesertHills => "desert_hills", + Biome::WoodedHills => "wooded_hills", + Biome::TaigaHills => "taiga_hills", + Biome::MountainEdge => "mountain_edge", + Biome::Jungle => "jungle", + Biome::JungleHills => "jungle_hills", + Biome::JungleEdge => "jungle_edge", + Biome::DeepOcean => "deep_ocean", + Biome::StoneShore => "stone_shore", + Biome::SnowyBeach => "snowy_beach", + Biome::BirchForest => "birch_forest", + Biome::BirchForestHills => "birch_forest_hills", + Biome::DarkForest => "dark_forest", + Biome::SnowyTaiga => "snowy_taiga", + Biome::SnowyTaigaHills => "snowy_taiga_hills", + Biome::GiantTreeTaiga => "giant_tree_taiga", + Biome::GiantTreeTaigaHills => "giant_tree_taiga_hills", + Biome::WoodedMountains => "wooded_mountains", + Biome::Savanna => "savanna", + Biome::SavannaPlateau => "savanna_plateau", + Biome::Badlands => "badlands", + Biome::WoodedBadlandsPlateau => "wooded_badlands_plateau", + Biome::BadlandsPlateau => "badlands_plateau", + Biome::SmallEndIslands => "small_end_islands", + Biome::EndMidlands => "end_midlands", + Biome::EndHighlands => "end_highlands", + Biome::EndBarrens => "end_barrens", + Biome::WarmOcean => "warm_ocean", + Biome::LukewarmOcean => "lukewarm_ocean", + Biome::ColdOcean => "cold_ocean", + Biome::DeepWarmOcean => "deep_warm_ocean", + Biome::DeepLukewarmOcean => "deep_lukewarm_ocean", + Biome::DeepColdOcean => "deep_cold_ocean", + Biome::DeepFrozenOcean => "deep_frozen_ocean", + Biome::TheVoid => "the_void", + Biome::SunflowerPlains => "sunflower_plains", + Biome::DesertLakes => "desert_lakes", + Biome::GravellyMountains => "gravelly_mountains", + Biome::FlowerForest => "flower_forest", + Biome::TaigaMountains => "taiga_mountains", + Biome::SwampHills => "swamp_hills", + Biome::IceSpikes => "ice_spikes", + Biome::ModifiedJungle => "modified_jungle", + Biome::ModifiedJungleEdge => "modified_jungle_edge", + Biome::TallBirchForest => "tall_birch_forest", + Biome::TallBirchHills => "tall_birch_hills", + Biome::DarkForestHills => "dark_forest_hills", + Biome::SnowyTaigaMountains => "snowy_taiga_mountains", + Biome::GiantSpruceTaiga => "giant_spruce_taiga", + Biome::GiantSpruceTaigaHills => "giant_spruce_taiga_hills", + Biome::ModifiedGravellyMountains => "modified_gravelly_mountains", + Biome::ShatteredSavanna => "shattered_savanna", + Biome::ShatteredSavannaPlateau => "shattered_savanna_plateau", + Biome::ErodedBadlands => "eroded_badlands", + Biome::ModifiedWoodedBadlandsPlateau => "modified_wooded_badlands_plateau", + Biome::ModifiedBadlandsPlateau => "modified_badlands_plateau", + Biome::BambooJungle => "bamboo_jungle", + Biome::BambooJungleHills => "bamboo_jungle_hills", + Biome::SoulSandValley => "soul_sand_valley", + Biome::CrimsonForest => "crimson_forest", + Biome::WarpedForest => "warped_forest", + Biome::BasaltDeltas => "basalt_deltas", + } + } + + /// Gets a `Biome` by its `name`. + pub fn from_name(name: &str) -> Option<Self> { + match name { + "ocean" => Some(Biome::Ocean), + "plains" => Some(Biome::Plains), + "desert" => Some(Biome::Desert), + "mountains" => Some(Biome::Mountains), + "forest" => Some(Biome::Forest), + "taiga" => Some(Biome::Taiga), + "swamp" => Some(Biome::Swamp), + "river" => Some(Biome::River), + "nether_wastes" => Some(Biome::NetherWastes), + "the_end" => Some(Biome::TheEnd), + "frozen_ocean" => Some(Biome::FrozenOcean), + "frozen_river" => Some(Biome::FrozenRiver), + "snowy_tundra" => Some(Biome::SnowyTundra), + "snowy_mountains" => Some(Biome::SnowyMountains), + "mushroom_fields" => Some(Biome::MushroomFields), + "mushroom_field_shore" => Some(Biome::MushroomFieldShore), + "beach" => Some(Biome::Beach), + "desert_hills" => Some(Biome::DesertHills), + "wooded_hills" => Some(Biome::WoodedHills), + "taiga_hills" => Some(Biome::TaigaHills), + "mountain_edge" => Some(Biome::MountainEdge), + "jungle" => Some(Biome::Jungle), + "jungle_hills" => Some(Biome::JungleHills), + "jungle_edge" => Some(Biome::JungleEdge), + "deep_ocean" => Some(Biome::DeepOcean), + "stone_shore" => Some(Biome::StoneShore), + "snowy_beach" => Some(Biome::SnowyBeach), + "birch_forest" => Some(Biome::BirchForest), + "birch_forest_hills" => Some(Biome::BirchForestHills), + "dark_forest" => Some(Biome::DarkForest), + "snowy_taiga" => Some(Biome::SnowyTaiga), + "snowy_taiga_hills" => Some(Biome::SnowyTaigaHills), + "giant_tree_taiga" => Some(Biome::GiantTreeTaiga), + "giant_tree_taiga_hills" => Some(Biome::GiantTreeTaigaHills), + "wooded_mountains" => Some(Biome::WoodedMountains), + "savanna" => Some(Biome::Savanna), + "savanna_plateau" => Some(Biome::SavannaPlateau), + "badlands" => Some(Biome::Badlands), + "wooded_badlands_plateau" => Some(Biome::WoodedBadlandsPlateau), + "badlands_plateau" => Some(Biome::BadlandsPlateau), + "small_end_islands" => Some(Biome::SmallEndIslands), + "end_midlands" => Some(Biome::EndMidlands), + "end_highlands" => Some(Biome::EndHighlands), + "end_barrens" => Some(Biome::EndBarrens), + "warm_ocean" => Some(Biome::WarmOcean), + "lukewarm_ocean" => Some(Biome::LukewarmOcean), + "cold_ocean" => Some(Biome::ColdOcean), + "deep_warm_ocean" => Some(Biome::DeepWarmOcean), + "deep_lukewarm_ocean" => Some(Biome::DeepLukewarmOcean), + "deep_cold_ocean" => Some(Biome::DeepColdOcean), + "deep_frozen_ocean" => Some(Biome::DeepFrozenOcean), + "the_void" => Some(Biome::TheVoid), + "sunflower_plains" => Some(Biome::SunflowerPlains), + "desert_lakes" => Some(Biome::DesertLakes), + "gravelly_mountains" => Some(Biome::GravellyMountains), + "flower_forest" => Some(Biome::FlowerForest), + "taiga_mountains" => Some(Biome::TaigaMountains), + "swamp_hills" => Some(Biome::SwampHills), + "ice_spikes" => Some(Biome::IceSpikes), + "modified_jungle" => Some(Biome::ModifiedJungle), + "modified_jungle_edge" => Some(Biome::ModifiedJungleEdge), + "tall_birch_forest" => Some(Biome::TallBirchForest), + "tall_birch_hills" => Some(Biome::TallBirchHills), + "dark_forest_hills" => Some(Biome::DarkForestHills), + "snowy_taiga_mountains" => Some(Biome::SnowyTaigaMountains), + "giant_spruce_taiga" => Some(Biome::GiantSpruceTaiga), + "giant_spruce_taiga_hills" => Some(Biome::GiantSpruceTaigaHills), + "modified_gravelly_mountains" => Some(Biome::ModifiedGravellyMountains), + "shattered_savanna" => Some(Biome::ShatteredSavanna), + "shattered_savanna_plateau" => Some(Biome::ShatteredSavannaPlateau), + "eroded_badlands" => Some(Biome::ErodedBadlands), + "modified_wooded_badlands_plateau" => Some(Biome::ModifiedWoodedBadlandsPlateau), + "modified_badlands_plateau" => Some(Biome::ModifiedBadlandsPlateau), + "bamboo_jungle" => Some(Biome::BambooJungle), + "bamboo_jungle_hills" => Some(Biome::BambooJungleHills), + "soul_sand_valley" => Some(Biome::SoulSandValley), + "crimson_forest" => Some(Biome::CrimsonForest), + "warped_forest" => Some(Biome::WarpedForest), + "basalt_deltas" => Some(Biome::BasaltDeltas), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Biome { + /// Returns the `display_name` property of this `Biome`. + pub fn display_name(&self) -> &'static str { + match self { + Biome::Ocean => "Ocean", + Biome::Plains => "Plains", + Biome::Desert => "Desert", + Biome::Mountains => "Mountains", + Biome::Forest => "Forest", + Biome::Taiga => "Taiga", + Biome::Swamp => "Swamp", + Biome::River => "River", + Biome::NetherWastes => "Nether Wastes", + Biome::TheEnd => "The End", + Biome::FrozenOcean => "Frozen Ocean", + Biome::FrozenRiver => "Frozen River", + Biome::SnowyTundra => "Snowy Tundra", + Biome::SnowyMountains => "Snowy Mountains", + Biome::MushroomFields => "Mushroom Fields", + Biome::MushroomFieldShore => "Mushroom Fields Shore", + Biome::Beach => "Beach", + Biome::DesertHills => "Desert Hills", + Biome::WoodedHills => "Wooded Hills", + Biome::TaigaHills => "Taiga Hills", + Biome::MountainEdge => "Mountain Edge", + Biome::Jungle => "Jungle", + Biome::JungleHills => "Jungle Hills", + Biome::JungleEdge => "Jungle Edge", + Biome::DeepOcean => "Deep Ocean", + Biome::StoneShore => "Stone Shore", + Biome::SnowyBeach => "Snowy Beach", + Biome::BirchForest => "Birch Forest", + Biome::BirchForestHills => "Birch Forest Hills", + Biome::DarkForest => "Dark Forest", + Biome::SnowyTaiga => "Snowy Taiga", + Biome::SnowyTaigaHills => "Snowy Taiga Hills", + Biome::GiantTreeTaiga => "Giant Tree Taiga", + Biome::GiantTreeTaigaHills => "Giant Tree Taiga Hills", + Biome::WoodedMountains => "Wooded Mountains", + Biome::Savanna => "Savanna", + Biome::SavannaPlateau => "Savanna Plateau", + Biome::Badlands => "Badlands", + Biome::WoodedBadlandsPlateau => "Wooded Badlands Plateau", + Biome::BadlandsPlateau => "Badlands Plateau", + Biome::SmallEndIslands => "Small End Islands", + Biome::EndMidlands => "End Midlands", + Biome::EndHighlands => "End Highlands", + Biome::EndBarrens => "End Barrens", + Biome::WarmOcean => "Warm Ocean", + Biome::LukewarmOcean => "Lukewarm Ocean", + Biome::ColdOcean => "Cold Ocean", + Biome::DeepWarmOcean => "Deep Warm Ocean", + Biome::DeepLukewarmOcean => "Deep Lukewarm Ocean", + Biome::DeepColdOcean => "Deep Cold Ocean", + Biome::DeepFrozenOcean => "Deep Frozen Ocean", + Biome::TheVoid => "the_void", + Biome::SunflowerPlains => "Sunflower Plains", + Biome::DesertLakes => "Desert Lakes", + Biome::GravellyMountains => "Gravelly Mountains", + Biome::FlowerForest => "Flower Forest", + Biome::TaigaMountains => "Taiga Mountains", + Biome::SwampHills => "Swamp Hills", + Biome::IceSpikes => "Ice Spikes", + Biome::ModifiedJungle => "Modified Jungle", + Biome::ModifiedJungleEdge => "Modified Jungle Edge", + Biome::TallBirchForest => "Tall Birch Forest", + Biome::TallBirchHills => "Tall Birch Hills", + Biome::DarkForestHills => "Dark Forest Hills", + Biome::SnowyTaigaMountains => "Snowy Taiga Mountains", + Biome::GiantSpruceTaiga => "Giant Spruce Taiga", + Biome::GiantSpruceTaigaHills => "Giant Spruce Taiga Hills", + Biome::ModifiedGravellyMountains => "Gravelly Mountains+", + Biome::ShatteredSavanna => "Shattered Savanna", + Biome::ShatteredSavannaPlateau => "Shattered Savanna Plateau", + Biome::ErodedBadlands => "Eroded Badlands", + Biome::ModifiedWoodedBadlandsPlateau => "Modified Wooded Badlands Plateau", + Biome::ModifiedBadlandsPlateau => "Modified Badlands Plateau", + Biome::BambooJungle => "Bamboo Jungle", + Biome::BambooJungleHills => "Bamboo Jungle Hills", + Biome::SoulSandValley => "Soul Sand Valley", + Biome::CrimsonForest => "Crimson Forest", + Biome::WarpedForest => "Warped Forest", + Biome::BasaltDeltas => "Basalt Deltas", + } + } + + /// Gets a `Biome` by its `display_name`. + pub fn from_display_name(display_name: &str) -> Option<Self> { + match display_name { + "Ocean" => Some(Biome::Ocean), + "Plains" => Some(Biome::Plains), + "Desert" => Some(Biome::Desert), + "Mountains" => Some(Biome::Mountains), + "Forest" => Some(Biome::Forest), + "Taiga" => Some(Biome::Taiga), + "Swamp" => Some(Biome::Swamp), + "River" => Some(Biome::River), + "Nether Wastes" => Some(Biome::NetherWastes), + "The End" => Some(Biome::TheEnd), + "Frozen Ocean" => Some(Biome::FrozenOcean), + "Frozen River" => Some(Biome::FrozenRiver), + "Snowy Tundra" => Some(Biome::SnowyTundra), + "Snowy Mountains" => Some(Biome::SnowyMountains), + "Mushroom Fields" => Some(Biome::MushroomFields), + "Mushroom Fields Shore" => Some(Biome::MushroomFieldShore), + "Beach" => Some(Biome::Beach), + "Desert Hills" => Some(Biome::DesertHills), + "Wooded Hills" => Some(Biome::WoodedHills), + "Taiga Hills" => Some(Biome::TaigaHills), + "Mountain Edge" => Some(Biome::MountainEdge), + "Jungle" => Some(Biome::Jungle), + "Jungle Hills" => Some(Biome::JungleHills), + "Jungle Edge" => Some(Biome::JungleEdge), + "Deep Ocean" => Some(Biome::DeepOcean), + "Stone Shore" => Some(Biome::StoneShore), + "Snowy Beach" => Some(Biome::SnowyBeach), + "Birch Forest" => Some(Biome::BirchForest), + "Birch Forest Hills" => Some(Biome::BirchForestHills), + "Dark Forest" => Some(Biome::DarkForest), + "Snowy Taiga" => Some(Biome::SnowyTaiga), + "Snowy Taiga Hills" => Some(Biome::SnowyTaigaHills), + "Giant Tree Taiga" => Some(Biome::GiantTreeTaiga), + "Giant Tree Taiga Hills" => Some(Biome::GiantTreeTaigaHills), + "Wooded Mountains" => Some(Biome::WoodedMountains), + "Savanna" => Some(Biome::Savanna), + "Savanna Plateau" => Some(Biome::SavannaPlateau), + "Badlands" => Some(Biome::Badlands), + "Wooded Badlands Plateau" => Some(Biome::WoodedBadlandsPlateau), + "Badlands Plateau" => Some(Biome::BadlandsPlateau), + "Small End Islands" => Some(Biome::SmallEndIslands), + "End Midlands" => Some(Biome::EndMidlands), + "End Highlands" => Some(Biome::EndHighlands), + "End Barrens" => Some(Biome::EndBarrens), + "Warm Ocean" => Some(Biome::WarmOcean), + "Lukewarm Ocean" => Some(Biome::LukewarmOcean), + "Cold Ocean" => Some(Biome::ColdOcean), + "Deep Warm Ocean" => Some(Biome::DeepWarmOcean), + "Deep Lukewarm Ocean" => Some(Biome::DeepLukewarmOcean), + "Deep Cold Ocean" => Some(Biome::DeepColdOcean), + "Deep Frozen Ocean" => Some(Biome::DeepFrozenOcean), + "the_void" => Some(Biome::TheVoid), + "Sunflower Plains" => Some(Biome::SunflowerPlains), + "Desert Lakes" => Some(Biome::DesertLakes), + "Gravelly Mountains" => Some(Biome::GravellyMountains), + "Flower Forest" => Some(Biome::FlowerForest), + "Taiga Mountains" => Some(Biome::TaigaMountains), + "Swamp Hills" => Some(Biome::SwampHills), + "Ice Spikes" => Some(Biome::IceSpikes), + "Modified Jungle" => Some(Biome::ModifiedJungle), + "Modified Jungle Edge" => Some(Biome::ModifiedJungleEdge), + "Tall Birch Forest" => Some(Biome::TallBirchForest), + "Tall Birch Hills" => Some(Biome::TallBirchHills), + "Dark Forest Hills" => Some(Biome::DarkForestHills), + "Snowy Taiga Mountains" => Some(Biome::SnowyTaigaMountains), + "Giant Spruce Taiga" => Some(Biome::GiantSpruceTaiga), + "Giant Spruce Taiga Hills" => Some(Biome::GiantSpruceTaigaHills), + "Gravelly Mountains+" => Some(Biome::ModifiedGravellyMountains), + "Shattered Savanna" => Some(Biome::ShatteredSavanna), + "Shattered Savanna Plateau" => Some(Biome::ShatteredSavannaPlateau), + "Eroded Badlands" => Some(Biome::ErodedBadlands), + "Modified Wooded Badlands Plateau" => Some(Biome::ModifiedWoodedBadlandsPlateau), + "Modified Badlands Plateau" => Some(Biome::ModifiedBadlandsPlateau), + "Bamboo Jungle" => Some(Biome::BambooJungle), + "Bamboo Jungle Hills" => Some(Biome::BambooJungleHills), + "Soul Sand Valley" => Some(Biome::SoulSandValley), + "Crimson Forest" => Some(Biome::CrimsonForest), + "Warped Forest" => Some(Biome::WarpedForest), + "Basalt Deltas" => Some(Biome::BasaltDeltas), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Biome { + /// Returns the `rainfall` property of this `Biome`. + pub fn rainfall(&self) -> f32 { + match self { + Biome::Ocean => 0.5 as f32, + Biome::Plains => 0.4 as f32, + Biome::Desert => 0 as f32, + Biome::Mountains => 0.3 as f32, + Biome::Forest => 0.8 as f32, + Biome::Taiga => 0.8 as f32, + Biome::Swamp => 0.9 as f32, + Biome::River => 0.5 as f32, + Biome::NetherWastes => 0 as f32, + Biome::TheEnd => 0.5 as f32, + Biome::FrozenOcean => 0.5 as f32, + Biome::FrozenRiver => 0.5 as f32, + Biome::SnowyTundra => 0.5 as f32, + Biome::SnowyMountains => 0.5 as f32, + Biome::MushroomFields => 1 as f32, + Biome::MushroomFieldShore => 1 as f32, + Biome::Beach => 0.4 as f32, + Biome::DesertHills => 0 as f32, + Biome::WoodedHills => 0.8 as f32, + Biome::TaigaHills => 0.8 as f32, + Biome::MountainEdge => 0.3 as f32, + Biome::Jungle => 0.9 as f32, + Biome::JungleHills => 0.9 as f32, + Biome::JungleEdge => 0.8 as f32, + Biome::DeepOcean => 0.5 as f32, + Biome::StoneShore => 0.3 as f32, + Biome::SnowyBeach => 0.3 as f32, + Biome::BirchForest => 0.6 as f32, + Biome::BirchForestHills => 0.6 as f32, + Biome::DarkForest => 0.8 as f32, + Biome::SnowyTaiga => 0.4 as f32, + Biome::SnowyTaigaHills => 0.4 as f32, + Biome::GiantTreeTaiga => 0.8 as f32, + Biome::GiantTreeTaigaHills => 0.8 as f32, + Biome::WoodedMountains => 0.3 as f32, + Biome::Savanna => 0 as f32, + Biome::SavannaPlateau => 0 as f32, + Biome::Badlands => 0 as f32, + Biome::WoodedBadlandsPlateau => 0 as f32, + Biome::BadlandsPlateau => 0 as f32, + Biome::SmallEndIslands => 0.5 as f32, + Biome::EndMidlands => 0.5 as f32, + Biome::EndHighlands => 0.5 as f32, + Biome::EndBarrens => 0.5 as f32, + Biome::WarmOcean => 0.5 as f32, + Biome::LukewarmOcean => 0.5 as f32, + Biome::ColdOcean => 0.5 as f32, + Biome::DeepWarmOcean => 0.5 as f32, + Biome::DeepLukewarmOcean => 0.5 as f32, + Biome::DeepColdOcean => 0.5 as f32, + Biome::DeepFrozenOcean => 0.5 as f32, + Biome::TheVoid => 0.5 as f32, + Biome::SunflowerPlains => 0.4 as f32, + Biome::DesertLakes => 0 as f32, + Biome::GravellyMountains => 0.3 as f32, + Biome::FlowerForest => 0.8 as f32, + Biome::TaigaMountains => 0.8 as f32, + Biome::SwampHills => 0.9 as f32, + Biome::IceSpikes => 0.5 as f32, + Biome::ModifiedJungle => 0.9 as f32, + Biome::ModifiedJungleEdge => 0.8 as f32, + Biome::TallBirchForest => 0.6 as f32, + Biome::TallBirchHills => 0.6 as f32, + Biome::DarkForestHills => 0.8 as f32, + Biome::SnowyTaigaMountains => 0.4 as f32, + Biome::GiantSpruceTaiga => 0.8 as f32, + Biome::GiantSpruceTaigaHills => 0.8 as f32, + Biome::ModifiedGravellyMountains => 0.3 as f32, + Biome::ShatteredSavanna => 0 as f32, + Biome::ShatteredSavannaPlateau => 0 as f32, + Biome::ErodedBadlands => 0 as f32, + Biome::ModifiedWoodedBadlandsPlateau => 0 as f32, + Biome::ModifiedBadlandsPlateau => 0 as f32, + Biome::BambooJungle => 0.9 as f32, + Biome::BambooJungleHills => 0.9 as f32, + Biome::SoulSandValley => 0 as f32, + Biome::CrimsonForest => 0 as f32, + Biome::WarpedForest => 0 as f32, + Biome::BasaltDeltas => 0 as f32, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Biome { + /// Returns the `temperature` property of this `Biome`. + pub fn temperature(&self) -> f32 { + match self { + Biome::Ocean => 0.5 as f32, + Biome::Plains => 0.8 as f32, + Biome::Desert => 2 as f32, + Biome::Mountains => 0.2 as f32, + Biome::Forest => 0.7 as f32, + Biome::Taiga => 0.25 as f32, + Biome::Swamp => 0.8 as f32, + Biome::River => 0.5 as f32, + Biome::NetherWastes => 2 as f32, + Biome::TheEnd => 0.5 as f32, + Biome::FrozenOcean => 0 as f32, + Biome::FrozenRiver => 0 as f32, + Biome::SnowyTundra => 0 as f32, + Biome::SnowyMountains => 0 as f32, + Biome::MushroomFields => 0.9 as f32, + Biome::MushroomFieldShore => 0.9 as f32, + Biome::Beach => 0.8 as f32, + Biome::DesertHills => 2 as f32, + Biome::WoodedHills => 0.7 as f32, + Biome::TaigaHills => 0.25 as f32, + Biome::MountainEdge => 0.2 as f32, + Biome::Jungle => 0.95 as f32, + Biome::JungleHills => 0.95 as f32, + Biome::JungleEdge => 0.95 as f32, + Biome::DeepOcean => 0.5 as f32, + Biome::StoneShore => 0.2 as f32, + Biome::SnowyBeach => 0.05 as f32, + Biome::BirchForest => 0.6 as f32, + Biome::BirchForestHills => 0.6 as f32, + Biome::DarkForest => 0.7 as f32, + Biome::SnowyTaiga => -0.5 as f32, + Biome::SnowyTaigaHills => -0.5 as f32, + Biome::GiantTreeTaiga => 0.3 as f32, + Biome::GiantTreeTaigaHills => 0.3 as f32, + Biome::WoodedMountains => 0.2 as f32, + Biome::Savanna => 1.2 as f32, + Biome::SavannaPlateau => 1 as f32, + Biome::Badlands => 2 as f32, + Biome::WoodedBadlandsPlateau => 2 as f32, + Biome::BadlandsPlateau => 2 as f32, + Biome::SmallEndIslands => 0.5 as f32, + Biome::EndMidlands => 0.5 as f32, + Biome::EndHighlands => 0.5 as f32, + Biome::EndBarrens => 0.5 as f32, + Biome::WarmOcean => 0.5 as f32, + Biome::LukewarmOcean => 0.5 as f32, + Biome::ColdOcean => 0.5 as f32, + Biome::DeepWarmOcean => 0.5 as f32, + Biome::DeepLukewarmOcean => 0.5 as f32, + Biome::DeepColdOcean => 0.5 as f32, + Biome::DeepFrozenOcean => 0.5 as f32, + Biome::TheVoid => 0.5 as f32, + Biome::SunflowerPlains => 0.8 as f32, + Biome::DesertLakes => 2 as f32, + Biome::GravellyMountains => 0.2 as f32, + Biome::FlowerForest => 0.7 as f32, + Biome::TaigaMountains => 0.25 as f32, + Biome::SwampHills => 0.8 as f32, + Biome::IceSpikes => 0 as f32, + Biome::ModifiedJungle => 0.95 as f32, + Biome::ModifiedJungleEdge => 0.95 as f32, + Biome::TallBirchForest => 0.6 as f32, + Biome::TallBirchHills => 0.6 as f32, + Biome::DarkForestHills => 0.7 as f32, + Biome::SnowyTaigaMountains => -0.5 as f32, + Biome::GiantSpruceTaiga => 0.25 as f32, + Biome::GiantSpruceTaigaHills => 0.25 as f32, + Biome::ModifiedGravellyMountains => 0.2 as f32, + Biome::ShatteredSavanna => 1.1 as f32, + Biome::ShatteredSavannaPlateau => 1 as f32, + Biome::ErodedBadlands => 2 as f32, + Biome::ModifiedWoodedBadlandsPlateau => 2 as f32, + Biome::ModifiedBadlandsPlateau => 2 as f32, + Biome::BambooJungle => 0.95 as f32, + Biome::BambooJungleHills => 0.95 as f32, + Biome::SoulSandValley => 2 as f32, + Biome::CrimsonForest => 2 as f32, + Biome::WarpedForest => 2 as f32, + Biome::BasaltDeltas => 2 as f32, + } + } +} diff --git a/libcraft/core/src/block.rs b/libcraft/core/src/block.rs new file mode 100644 index 000000000..8051da9fb --- /dev/null +++ b/libcraft/core/src/block.rs @@ -0,0 +1,230 @@ +//! Various block state values. +//! See the `libcraft-blocks` crate +//! for actual block definitions. + +use serde::{Deserialize, Serialize}; +use strum_macros::EnumString; + +/// Direction a block is facing in. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +#[repr(u8)] +pub enum BlockFace { + South, + SouthSouthwest, + Southwest, + WestSouthwest, + West, + WestNorthwest, + Northwest, + NorthNorthwest, + North, + NorthNortheast, + Northeast, + EastNortheast, + East, + EastSoutheast, + Southeast, + SouthSoutheast, +} + +/// Size of bamboo leaves. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum BambooLeaves { + None, + Small, + Large, +} + +/// Part of a bed. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum BedPart { + Foot, + Head, +} + +/// How a bell is attached. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum BellAttachment { + Ceiling, + Floor, + SingleWall, + DoubleWall, +} + +/// An axis. Used for bone blocks, +/// portal blocks, chains, etc. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum Axis { + X, + Y, + Z, +} + +/// Block face a button or grindstone is attached to. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum AttachedFace { + Ceiling, + Floor, + Wall, +} + +/// Type of a chest. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum ChestType { + Single, + /// Double chest; this block is on the left side. + Left, + /// Double chest; this block is on the right side. + Right, +} + +/// Which half of a door or flower block is. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum BlockHalf { + Lower, + Upper, +} + +/// Which half of stairs. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum StairHalf { + Bottom, + Top, +} + +/// To which side a door's hinge is. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum DoorHinge { + Left, + Right, +} + +/// Orientation of a jigsaw block. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum Orientation { + DownEast, + DownNorth, + DownSouth, + DownWest, + EastUp, + NorthUp, + SouthUp, + UpEast, + UpNorth, + UpSouth, + UpWest, + WestUp, +} + +/// A note block instrument. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum Instrument { + Banjo, + Basedrum, + Bass, + Bell, + Bit, + Chime, + CowBell, + Didgeridoo, + Flute, + Guitar, + Harp, + Hat, + IronXylophone, + Pling, + Snare, + Xylophone, +} + +/// Type of a slab block. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum SlabType { + Bottom, + Top, + Double, +} + +/// Type of a moving piston or piston head. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum PistonType { + Normal, + Sticky, +} + +/// Shape of a rail block. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum RailShape { + EastWest, + NorthEast, + NorthSouth, + NorthWest, + SouthEast, + SouthWest, + AscendingEast, + AscendingNorth, + AscendingSouth, + AscendingWest, +} + +/// Mode of a redstone comparator. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum ComparatorMode { + Compare, + Subtract, +} + +/// How a redstone dust connects to a given side. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum RedstoneConnection { + None, + Side, + Up, +} + +/// Shape of a stairs block. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum StairShape { + InnerLeft, + InnerRight, + OuterLeft, + OuterRight, + Straight, +} + +/// Mode of a structure block. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum StructureBlockMode { + Corner, + Data, + Load, + Save, +} + +/// How a wall connects to a given direction. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum WallConnection { + None, + Low, + Tall, +} diff --git a/libcraft/core/src/consts.rs b/libcraft/core/src/consts.rs new file mode 100644 index 000000000..e3ee4c9a6 --- /dev/null +++ b/libcraft/core/src/consts.rs @@ -0,0 +1,4 @@ +/// Width, in blocks, of a chunk. +pub const CHUNK_WIDTH: usize = 16; +/// Height, in blocks, of a chunk. +pub const CHUNK_HEIGHT: usize = 256; diff --git a/libcraft/core/src/dimension.rs b/libcraft/core/src/dimension.rs new file mode 100644 index 000000000..4b9a4d035 --- /dev/null +++ b/libcraft/core/src/dimension.rs @@ -0,0 +1,70 @@ +use serde::{Deserialize, Serialize}; +use std::convert::TryFrom; + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(try_from = "String", into = "&'static str")] +pub enum Dimension { + Overworld, + TheNether, + TheEnd, +} + +impl Dimension { + pub fn id(&self) -> i32 { + match self { + Self::Overworld => 0, + Self::TheNether => -1, + Self::TheEnd => 1, + } + } + + pub fn from_id(id: i32) -> Option<Self> { + match id { + 0 => Some(Self::Overworld), + -1 => Some(Self::TheNether), + 1 => Some(Self::TheEnd), + _ => None, + } + } + + pub fn namespaced_id(&self) -> &'static str { + match self { + Self::Overworld => "minecraft:overworld", + Self::TheNether => "minecraft:the_nether", + Self::TheEnd => "minecraft:the_end", + } + } + + pub fn from_namespaced_id(id: &str) -> Option<Self> { + match id { + "minecraft:overworld" => Some(Self::Overworld), + "minecraft:the_nether" => Some(Self::TheNether), + "minecraft:the_end" => Some(Self::TheEnd), + _ => None, + } + } +} + +impl TryFrom<String> for Dimension { + type Error = &'static str; + + fn try_from(namespaced_value: String) -> Result<Self, Self::Error> { + if let Some(val) = Self::from_namespaced_id(namespaced_value.as_str()) { + Ok(val) + } else { + Err("Unknown dimension namespaced_id.") + } + } +} + +impl From<Dimension> for &'static str { + fn from(value: Dimension) -> Self { + value.namespaced_id() + } +} + +impl From<Dimension> for i32 { + fn from(value: Dimension) -> Self { + value.id() + } +} diff --git a/libcraft/core/src/entity.rs b/libcraft/core/src/entity.rs new file mode 100644 index 000000000..0f16ee4ce --- /dev/null +++ b/libcraft/core/src/entity.rs @@ -0,0 +1,1483 @@ +// This file is @generated. Please do not edit. + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum EntityKind { + AreaEffectCloud, + ArmorStand, + Arrow, + Bat, + Bee, + Blaze, + Boat, + Cat, + CaveSpider, + Chicken, + Cod, + Cow, + Creeper, + Dolphin, + Donkey, + DragonFireball, + Drowned, + ElderGuardian, + EndCrystal, + EnderDragon, + Enderman, + Endermite, + Evoker, + EvokerFangs, + ExperienceOrb, + EyeOfEnder, + FallingBlock, + FireworkRocket, + Fox, + Ghast, + Giant, + Guardian, + Hoglin, + Horse, + Husk, + Illusioner, + IronGolem, + Item, + ItemFrame, + Fireball, + LeashKnot, + LightningBolt, + Llama, + LlamaSpit, + MagmaCube, + Minecart, + ChestMinecart, + CommandBlockMinecart, + FurnaceMinecart, + HopperMinecart, + SpawnerMinecart, + TntMinecart, + Mule, + Mooshroom, + Ocelot, + Painting, + Panda, + Parrot, + Phantom, + Pig, + Piglin, + PiglinBrute, + Pillager, + PolarBear, + Tnt, + Pufferfish, + Rabbit, + Ravager, + Salmon, + Sheep, + Shulker, + ShulkerBullet, + Silverfish, + Skeleton, + SkeletonHorse, + Slime, + SmallFireball, + SnowGolem, + Snowball, + SpectralArrow, + Spider, + Squid, + Stray, + Strider, + Egg, + EnderPearl, + ExperienceBottle, + Potion, + Trident, + TraderLlama, + TropicalFish, + Turtle, + Vex, + Villager, + Vindicator, + WanderingTrader, + Witch, + Wither, + WitherSkeleton, + WitherSkull, + Wolf, + Zoglin, + Zombie, + ZombieHorse, + ZombieVillager, + ZombifiedPiglin, + Player, + FishingBobber, +} + +#[allow(warnings)] +#[allow(clippy::all)] +impl EntityKind { + /// Returns the `id` property of this `EntityKind`. + pub fn id(&self) -> u32 { + match self { + EntityKind::AreaEffectCloud => 0, + EntityKind::ArmorStand => 1, + EntityKind::Arrow => 2, + EntityKind::Bat => 3, + EntityKind::Bee => 4, + EntityKind::Blaze => 5, + EntityKind::Boat => 6, + EntityKind::Cat => 7, + EntityKind::CaveSpider => 8, + EntityKind::Chicken => 9, + EntityKind::Cod => 10, + EntityKind::Cow => 11, + EntityKind::Creeper => 12, + EntityKind::Dolphin => 13, + EntityKind::Donkey => 14, + EntityKind::DragonFireball => 15, + EntityKind::Drowned => 16, + EntityKind::ElderGuardian => 17, + EntityKind::EndCrystal => 18, + EntityKind::EnderDragon => 19, + EntityKind::Enderman => 20, + EntityKind::Endermite => 21, + EntityKind::Evoker => 22, + EntityKind::EvokerFangs => 23, + EntityKind::ExperienceOrb => 24, + EntityKind::EyeOfEnder => 25, + EntityKind::FallingBlock => 26, + EntityKind::FireworkRocket => 27, + EntityKind::Fox => 28, + EntityKind::Ghast => 29, + EntityKind::Giant => 30, + EntityKind::Guardian => 31, + EntityKind::Hoglin => 32, + EntityKind::Horse => 33, + EntityKind::Husk => 34, + EntityKind::Illusioner => 35, + EntityKind::IronGolem => 36, + EntityKind::Item => 37, + EntityKind::ItemFrame => 38, + EntityKind::Fireball => 39, + EntityKind::LeashKnot => 40, + EntityKind::LightningBolt => 41, + EntityKind::Llama => 42, + EntityKind::LlamaSpit => 43, + EntityKind::MagmaCube => 44, + EntityKind::Minecart => 45, + EntityKind::ChestMinecart => 46, + EntityKind::CommandBlockMinecart => 47, + EntityKind::FurnaceMinecart => 48, + EntityKind::HopperMinecart => 49, + EntityKind::SpawnerMinecart => 50, + EntityKind::TntMinecart => 51, + EntityKind::Mule => 52, + EntityKind::Mooshroom => 53, + EntityKind::Ocelot => 54, + EntityKind::Painting => 55, + EntityKind::Panda => 56, + EntityKind::Parrot => 57, + EntityKind::Phantom => 58, + EntityKind::Pig => 59, + EntityKind::Piglin => 60, + EntityKind::PiglinBrute => 61, + EntityKind::Pillager => 62, + EntityKind::PolarBear => 63, + EntityKind::Tnt => 64, + EntityKind::Pufferfish => 65, + EntityKind::Rabbit => 66, + EntityKind::Ravager => 67, + EntityKind::Salmon => 68, + EntityKind::Sheep => 69, + EntityKind::Shulker => 70, + EntityKind::ShulkerBullet => 71, + EntityKind::Silverfish => 72, + EntityKind::Skeleton => 73, + EntityKind::SkeletonHorse => 74, + EntityKind::Slime => 75, + EntityKind::SmallFireball => 76, + EntityKind::SnowGolem => 77, + EntityKind::Snowball => 78, + EntityKind::SpectralArrow => 79, + EntityKind::Spider => 80, + EntityKind::Squid => 81, + EntityKind::Stray => 82, + EntityKind::Strider => 83, + EntityKind::Egg => 84, + EntityKind::EnderPearl => 85, + EntityKind::ExperienceBottle => 86, + EntityKind::Potion => 87, + EntityKind::Trident => 88, + EntityKind::TraderLlama => 89, + EntityKind::TropicalFish => 90, + EntityKind::Turtle => 91, + EntityKind::Vex => 92, + EntityKind::Villager => 93, + EntityKind::Vindicator => 94, + EntityKind::WanderingTrader => 95, + EntityKind::Witch => 96, + EntityKind::Wither => 97, + EntityKind::WitherSkeleton => 98, + EntityKind::WitherSkull => 99, + EntityKind::Wolf => 100, + EntityKind::Zoglin => 101, + EntityKind::Zombie => 102, + EntityKind::ZombieHorse => 103, + EntityKind::ZombieVillager => 104, + EntityKind::ZombifiedPiglin => 105, + EntityKind::Player => 106, + EntityKind::FishingBobber => 107, + } + } + + /// Gets a `EntityKind` by its `id`. + pub fn from_id(id: u32) -> Option<Self> { + match id { + 0 => Some(EntityKind::AreaEffectCloud), + 1 => Some(EntityKind::ArmorStand), + 2 => Some(EntityKind::Arrow), + 3 => Some(EntityKind::Bat), + 4 => Some(EntityKind::Bee), + 5 => Some(EntityKind::Blaze), + 6 => Some(EntityKind::Boat), + 7 => Some(EntityKind::Cat), + 8 => Some(EntityKind::CaveSpider), + 9 => Some(EntityKind::Chicken), + 10 => Some(EntityKind::Cod), + 11 => Some(EntityKind::Cow), + 12 => Some(EntityKind::Creeper), + 13 => Some(EntityKind::Dolphin), + 14 => Some(EntityKind::Donkey), + 15 => Some(EntityKind::DragonFireball), + 16 => Some(EntityKind::Drowned), + 17 => Some(EntityKind::ElderGuardian), + 18 => Some(EntityKind::EndCrystal), + 19 => Some(EntityKind::EnderDragon), + 20 => Some(EntityKind::Enderman), + 21 => Some(EntityKind::Endermite), + 22 => Some(EntityKind::Evoker), + 23 => Some(EntityKind::EvokerFangs), + 24 => Some(EntityKind::ExperienceOrb), + 25 => Some(EntityKind::EyeOfEnder), + 26 => Some(EntityKind::FallingBlock), + 27 => Some(EntityKind::FireworkRocket), + 28 => Some(EntityKind::Fox), + 29 => Some(EntityKind::Ghast), + 30 => Some(EntityKind::Giant), + 31 => Some(EntityKind::Guardian), + 32 => Some(EntityKind::Hoglin), + 33 => Some(EntityKind::Horse), + 34 => Some(EntityKind::Husk), + 35 => Some(EntityKind::Illusioner), + 36 => Some(EntityKind::IronGolem), + 37 => Some(EntityKind::Item), + 38 => Some(EntityKind::ItemFrame), + 39 => Some(EntityKind::Fireball), + 40 => Some(EntityKind::LeashKnot), + 41 => Some(EntityKind::LightningBolt), + 42 => Some(EntityKind::Llama), + 43 => Some(EntityKind::LlamaSpit), + 44 => Some(EntityKind::MagmaCube), + 45 => Some(EntityKind::Minecart), + 46 => Some(EntityKind::ChestMinecart), + 47 => Some(EntityKind::CommandBlockMinecart), + 48 => Some(EntityKind::FurnaceMinecart), + 49 => Some(EntityKind::HopperMinecart), + 50 => Some(EntityKind::SpawnerMinecart), + 51 => Some(EntityKind::TntMinecart), + 52 => Some(EntityKind::Mule), + 53 => Some(EntityKind::Mooshroom), + 54 => Some(EntityKind::Ocelot), + 55 => Some(EntityKind::Painting), + 56 => Some(EntityKind::Panda), + 57 => Some(EntityKind::Parrot), + 58 => Some(EntityKind::Phantom), + 59 => Some(EntityKind::Pig), + 60 => Some(EntityKind::Piglin), + 61 => Some(EntityKind::PiglinBrute), + 62 => Some(EntityKind::Pillager), + 63 => Some(EntityKind::PolarBear), + 64 => Some(EntityKind::Tnt), + 65 => Some(EntityKind::Pufferfish), + 66 => Some(EntityKind::Rabbit), + 67 => Some(EntityKind::Ravager), + 68 => Some(EntityKind::Salmon), + 69 => Some(EntityKind::Sheep), + 70 => Some(EntityKind::Shulker), + 71 => Some(EntityKind::ShulkerBullet), + 72 => Some(EntityKind::Silverfish), + 73 => Some(EntityKind::Skeleton), + 74 => Some(EntityKind::SkeletonHorse), + 75 => Some(EntityKind::Slime), + 76 => Some(EntityKind::SmallFireball), + 77 => Some(EntityKind::SnowGolem), + 78 => Some(EntityKind::Snowball), + 79 => Some(EntityKind::SpectralArrow), + 80 => Some(EntityKind::Spider), + 81 => Some(EntityKind::Squid), + 82 => Some(EntityKind::Stray), + 83 => Some(EntityKind::Strider), + 84 => Some(EntityKind::Egg), + 85 => Some(EntityKind::EnderPearl), + 86 => Some(EntityKind::ExperienceBottle), + 87 => Some(EntityKind::Potion), + 88 => Some(EntityKind::Trident), + 89 => Some(EntityKind::TraderLlama), + 90 => Some(EntityKind::TropicalFish), + 91 => Some(EntityKind::Turtle), + 92 => Some(EntityKind::Vex), + 93 => Some(EntityKind::Villager), + 94 => Some(EntityKind::Vindicator), + 95 => Some(EntityKind::WanderingTrader), + 96 => Some(EntityKind::Witch), + 97 => Some(EntityKind::Wither), + 98 => Some(EntityKind::WitherSkeleton), + 99 => Some(EntityKind::WitherSkull), + 100 => Some(EntityKind::Wolf), + 101 => Some(EntityKind::Zoglin), + 102 => Some(EntityKind::Zombie), + 103 => Some(EntityKind::ZombieHorse), + 104 => Some(EntityKind::ZombieVillager), + 105 => Some(EntityKind::ZombifiedPiglin), + 106 => Some(EntityKind::Player), + 107 => Some(EntityKind::FishingBobber), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl EntityKind { + /// Returns the `internal_id` property of this `EntityKind`. + pub fn internal_id(&self) -> u32 { + match self { + EntityKind::AreaEffectCloud => 0, + EntityKind::ArmorStand => 1, + EntityKind::Arrow => 2, + EntityKind::Bat => 3, + EntityKind::Bee => 4, + EntityKind::Blaze => 5, + EntityKind::Boat => 6, + EntityKind::Cat => 7, + EntityKind::CaveSpider => 8, + EntityKind::Chicken => 9, + EntityKind::Cod => 10, + EntityKind::Cow => 11, + EntityKind::Creeper => 12, + EntityKind::Dolphin => 13, + EntityKind::Donkey => 14, + EntityKind::DragonFireball => 15, + EntityKind::Drowned => 16, + EntityKind::ElderGuardian => 17, + EntityKind::EndCrystal => 18, + EntityKind::EnderDragon => 19, + EntityKind::Enderman => 20, + EntityKind::Endermite => 21, + EntityKind::Evoker => 22, + EntityKind::EvokerFangs => 23, + EntityKind::ExperienceOrb => 24, + EntityKind::EyeOfEnder => 25, + EntityKind::FallingBlock => 26, + EntityKind::FireworkRocket => 27, + EntityKind::Fox => 28, + EntityKind::Ghast => 29, + EntityKind::Giant => 30, + EntityKind::Guardian => 31, + EntityKind::Hoglin => 32, + EntityKind::Horse => 33, + EntityKind::Husk => 34, + EntityKind::Illusioner => 35, + EntityKind::IronGolem => 36, + EntityKind::Item => 37, + EntityKind::ItemFrame => 38, + EntityKind::Fireball => 39, + EntityKind::LeashKnot => 40, + EntityKind::LightningBolt => 41, + EntityKind::Llama => 42, + EntityKind::LlamaSpit => 43, + EntityKind::MagmaCube => 44, + EntityKind::Minecart => 45, + EntityKind::ChestMinecart => 46, + EntityKind::CommandBlockMinecart => 47, + EntityKind::FurnaceMinecart => 48, + EntityKind::HopperMinecart => 49, + EntityKind::SpawnerMinecart => 50, + EntityKind::TntMinecart => 51, + EntityKind::Mule => 52, + EntityKind::Mooshroom => 53, + EntityKind::Ocelot => 54, + EntityKind::Painting => 55, + EntityKind::Panda => 56, + EntityKind::Parrot => 57, + EntityKind::Phantom => 58, + EntityKind::Pig => 59, + EntityKind::Piglin => 60, + EntityKind::PiglinBrute => 61, + EntityKind::Pillager => 62, + EntityKind::PolarBear => 63, + EntityKind::Tnt => 64, + EntityKind::Pufferfish => 65, + EntityKind::Rabbit => 66, + EntityKind::Ravager => 67, + EntityKind::Salmon => 68, + EntityKind::Sheep => 69, + EntityKind::Shulker => 70, + EntityKind::ShulkerBullet => 71, + EntityKind::Silverfish => 72, + EntityKind::Skeleton => 73, + EntityKind::SkeletonHorse => 74, + EntityKind::Slime => 75, + EntityKind::SmallFireball => 76, + EntityKind::SnowGolem => 77, + EntityKind::Snowball => 78, + EntityKind::SpectralArrow => 79, + EntityKind::Spider => 80, + EntityKind::Squid => 81, + EntityKind::Stray => 82, + EntityKind::Strider => 83, + EntityKind::Egg => 84, + EntityKind::EnderPearl => 85, + EntityKind::ExperienceBottle => 86, + EntityKind::Potion => 87, + EntityKind::Trident => 88, + EntityKind::TraderLlama => 89, + EntityKind::TropicalFish => 90, + EntityKind::Turtle => 91, + EntityKind::Vex => 92, + EntityKind::Villager => 93, + EntityKind::Vindicator => 94, + EntityKind::WanderingTrader => 95, + EntityKind::Witch => 96, + EntityKind::Wither => 97, + EntityKind::WitherSkeleton => 98, + EntityKind::WitherSkull => 99, + EntityKind::Wolf => 100, + EntityKind::Zoglin => 101, + EntityKind::Zombie => 102, + EntityKind::ZombieHorse => 103, + EntityKind::ZombieVillager => 104, + EntityKind::ZombifiedPiglin => 105, + EntityKind::Player => 106, + EntityKind::FishingBobber => 107, + } + } + + /// Gets a `EntityKind` by its `internal_id`. + pub fn from_internal_id(internal_id: u32) -> Option<Self> { + match internal_id { + 0 => Some(EntityKind::AreaEffectCloud), + 1 => Some(EntityKind::ArmorStand), + 2 => Some(EntityKind::Arrow), + 3 => Some(EntityKind::Bat), + 4 => Some(EntityKind::Bee), + 5 => Some(EntityKind::Blaze), + 6 => Some(EntityKind::Boat), + 7 => Some(EntityKind::Cat), + 8 => Some(EntityKind::CaveSpider), + 9 => Some(EntityKind::Chicken), + 10 => Some(EntityKind::Cod), + 11 => Some(EntityKind::Cow), + 12 => Some(EntityKind::Creeper), + 13 => Some(EntityKind::Dolphin), + 14 => Some(EntityKind::Donkey), + 15 => Some(EntityKind::DragonFireball), + 16 => Some(EntityKind::Drowned), + 17 => Some(EntityKind::ElderGuardian), + 18 => Some(EntityKind::EndCrystal), + 19 => Some(EntityKind::EnderDragon), + 20 => Some(EntityKind::Enderman), + 21 => Some(EntityKind::Endermite), + 22 => Some(EntityKind::Evoker), + 23 => Some(EntityKind::EvokerFangs), + 24 => Some(EntityKind::ExperienceOrb), + 25 => Some(EntityKind::EyeOfEnder), + 26 => Some(EntityKind::FallingBlock), + 27 => Some(EntityKind::FireworkRocket), + 28 => Some(EntityKind::Fox), + 29 => Some(EntityKind::Ghast), + 30 => Some(EntityKind::Giant), + 31 => Some(EntityKind::Guardian), + 32 => Some(EntityKind::Hoglin), + 33 => Some(EntityKind::Horse), + 34 => Some(EntityKind::Husk), + 35 => Some(EntityKind::Illusioner), + 36 => Some(EntityKind::IronGolem), + 37 => Some(EntityKind::Item), + 38 => Some(EntityKind::ItemFrame), + 39 => Some(EntityKind::Fireball), + 40 => Some(EntityKind::LeashKnot), + 41 => Some(EntityKind::LightningBolt), + 42 => Some(EntityKind::Llama), + 43 => Some(EntityKind::LlamaSpit), + 44 => Some(EntityKind::MagmaCube), + 45 => Some(EntityKind::Minecart), + 46 => Some(EntityKind::ChestMinecart), + 47 => Some(EntityKind::CommandBlockMinecart), + 48 => Some(EntityKind::FurnaceMinecart), + 49 => Some(EntityKind::HopperMinecart), + 50 => Some(EntityKind::SpawnerMinecart), + 51 => Some(EntityKind::TntMinecart), + 52 => Some(EntityKind::Mule), + 53 => Some(EntityKind::Mooshroom), + 54 => Some(EntityKind::Ocelot), + 55 => Some(EntityKind::Painting), + 56 => Some(EntityKind::Panda), + 57 => Some(EntityKind::Parrot), + 58 => Some(EntityKind::Phantom), + 59 => Some(EntityKind::Pig), + 60 => Some(EntityKind::Piglin), + 61 => Some(EntityKind::PiglinBrute), + 62 => Some(EntityKind::Pillager), + 63 => Some(EntityKind::PolarBear), + 64 => Some(EntityKind::Tnt), + 65 => Some(EntityKind::Pufferfish), + 66 => Some(EntityKind::Rabbit), + 67 => Some(EntityKind::Ravager), + 68 => Some(EntityKind::Salmon), + 69 => Some(EntityKind::Sheep), + 70 => Some(EntityKind::Shulker), + 71 => Some(EntityKind::ShulkerBullet), + 72 => Some(EntityKind::Silverfish), + 73 => Some(EntityKind::Skeleton), + 74 => Some(EntityKind::SkeletonHorse), + 75 => Some(EntityKind::Slime), + 76 => Some(EntityKind::SmallFireball), + 77 => Some(EntityKind::SnowGolem), + 78 => Some(EntityKind::Snowball), + 79 => Some(EntityKind::SpectralArrow), + 80 => Some(EntityKind::Spider), + 81 => Some(EntityKind::Squid), + 82 => Some(EntityKind::Stray), + 83 => Some(EntityKind::Strider), + 84 => Some(EntityKind::Egg), + 85 => Some(EntityKind::EnderPearl), + 86 => Some(EntityKind::ExperienceBottle), + 87 => Some(EntityKind::Potion), + 88 => Some(EntityKind::Trident), + 89 => Some(EntityKind::TraderLlama), + 90 => Some(EntityKind::TropicalFish), + 91 => Some(EntityKind::Turtle), + 92 => Some(EntityKind::Vex), + 93 => Some(EntityKind::Villager), + 94 => Some(EntityKind::Vindicator), + 95 => Some(EntityKind::WanderingTrader), + 96 => Some(EntityKind::Witch), + 97 => Some(EntityKind::Wither), + 98 => Some(EntityKind::WitherSkeleton), + 99 => Some(EntityKind::WitherSkull), + 100 => Some(EntityKind::Wolf), + 101 => Some(EntityKind::Zoglin), + 102 => Some(EntityKind::Zombie), + 103 => Some(EntityKind::ZombieHorse), + 104 => Some(EntityKind::ZombieVillager), + 105 => Some(EntityKind::ZombifiedPiglin), + 106 => Some(EntityKind::Player), + 107 => Some(EntityKind::FishingBobber), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl EntityKind { + /// Returns the `name` property of this `EntityKind`. + pub fn name(&self) -> &'static str { + match self { + EntityKind::AreaEffectCloud => "area_effect_cloud", + EntityKind::ArmorStand => "armor_stand", + EntityKind::Arrow => "arrow", + EntityKind::Bat => "bat", + EntityKind::Bee => "bee", + EntityKind::Blaze => "blaze", + EntityKind::Boat => "boat", + EntityKind::Cat => "cat", + EntityKind::CaveSpider => "cave_spider", + EntityKind::Chicken => "chicken", + EntityKind::Cod => "cod", + EntityKind::Cow => "cow", + EntityKind::Creeper => "creeper", + EntityKind::Dolphin => "dolphin", + EntityKind::Donkey => "donkey", + EntityKind::DragonFireball => "dragon_fireball", + EntityKind::Drowned => "drowned", + EntityKind::ElderGuardian => "elder_guardian", + EntityKind::EndCrystal => "end_crystal", + EntityKind::EnderDragon => "ender_dragon", + EntityKind::Enderman => "enderman", + EntityKind::Endermite => "endermite", + EntityKind::Evoker => "evoker", + EntityKind::EvokerFangs => "evoker_fangs", + EntityKind::ExperienceOrb => "experience_orb", + EntityKind::EyeOfEnder => "eye_of_ender", + EntityKind::FallingBlock => "falling_block", + EntityKind::FireworkRocket => "firework_rocket", + EntityKind::Fox => "fox", + EntityKind::Ghast => "ghast", + EntityKind::Giant => "giant", + EntityKind::Guardian => "guardian", + EntityKind::Hoglin => "hoglin", + EntityKind::Horse => "horse", + EntityKind::Husk => "husk", + EntityKind::Illusioner => "illusioner", + EntityKind::IronGolem => "iron_golem", + EntityKind::Item => "item", + EntityKind::ItemFrame => "item_frame", + EntityKind::Fireball => "fireball", + EntityKind::LeashKnot => "leash_knot", + EntityKind::LightningBolt => "lightning_bolt", + EntityKind::Llama => "llama", + EntityKind::LlamaSpit => "llama_spit", + EntityKind::MagmaCube => "magma_cube", + EntityKind::Minecart => "minecart", + EntityKind::ChestMinecart => "chest_minecart", + EntityKind::CommandBlockMinecart => "command_block_minecart", + EntityKind::FurnaceMinecart => "furnace_minecart", + EntityKind::HopperMinecart => "hopper_minecart", + EntityKind::SpawnerMinecart => "spawner_minecart", + EntityKind::TntMinecart => "tnt_minecart", + EntityKind::Mule => "mule", + EntityKind::Mooshroom => "mooshroom", + EntityKind::Ocelot => "ocelot", + EntityKind::Painting => "painting", + EntityKind::Panda => "panda", + EntityKind::Parrot => "parrot", + EntityKind::Phantom => "phantom", + EntityKind::Pig => "pig", + EntityKind::Piglin => "piglin", + EntityKind::PiglinBrute => "piglin_brute", + EntityKind::Pillager => "pillager", + EntityKind::PolarBear => "polar_bear", + EntityKind::Tnt => "tnt", + EntityKind::Pufferfish => "pufferfish", + EntityKind::Rabbit => "rabbit", + EntityKind::Ravager => "ravager", + EntityKind::Salmon => "salmon", + EntityKind::Sheep => "sheep", + EntityKind::Shulker => "shulker", + EntityKind::ShulkerBullet => "shulker_bullet", + EntityKind::Silverfish => "silverfish", + EntityKind::Skeleton => "skeleton", + EntityKind::SkeletonHorse => "skeleton_horse", + EntityKind::Slime => "slime", + EntityKind::SmallFireball => "small_fireball", + EntityKind::SnowGolem => "snow_golem", + EntityKind::Snowball => "snowball", + EntityKind::SpectralArrow => "spectral_arrow", + EntityKind::Spider => "spider", + EntityKind::Squid => "squid", + EntityKind::Stray => "stray", + EntityKind::Strider => "strider", + EntityKind::Egg => "egg", + EntityKind::EnderPearl => "ender_pearl", + EntityKind::ExperienceBottle => "experience_bottle", + EntityKind::Potion => "potion", + EntityKind::Trident => "trident", + EntityKind::TraderLlama => "trader_llama", + EntityKind::TropicalFish => "tropical_fish", + EntityKind::Turtle => "turtle", + EntityKind::Vex => "vex", + EntityKind::Villager => "villager", + EntityKind::Vindicator => "vindicator", + EntityKind::WanderingTrader => "wandering_trader", + EntityKind::Witch => "witch", + EntityKind::Wither => "wither", + EntityKind::WitherSkeleton => "wither_skeleton", + EntityKind::WitherSkull => "wither_skull", + EntityKind::Wolf => "wolf", + EntityKind::Zoglin => "zoglin", + EntityKind::Zombie => "zombie", + EntityKind::ZombieHorse => "zombie_horse", + EntityKind::ZombieVillager => "zombie_villager", + EntityKind::ZombifiedPiglin => "zombified_piglin", + EntityKind::Player => "player", + EntityKind::FishingBobber => "fishing_bobber", + } + } + + /// Gets a `EntityKind` by its `name`. + pub fn from_name(name: &str) -> Option<Self> { + match name { + "area_effect_cloud" => Some(EntityKind::AreaEffectCloud), + "armor_stand" => Some(EntityKind::ArmorStand), + "arrow" => Some(EntityKind::Arrow), + "bat" => Some(EntityKind::Bat), + "bee" => Some(EntityKind::Bee), + "blaze" => Some(EntityKind::Blaze), + "boat" => Some(EntityKind::Boat), + "cat" => Some(EntityKind::Cat), + "cave_spider" => Some(EntityKind::CaveSpider), + "chicken" => Some(EntityKind::Chicken), + "cod" => Some(EntityKind::Cod), + "cow" => Some(EntityKind::Cow), + "creeper" => Some(EntityKind::Creeper), + "dolphin" => Some(EntityKind::Dolphin), + "donkey" => Some(EntityKind::Donkey), + "dragon_fireball" => Some(EntityKind::DragonFireball), + "drowned" => Some(EntityKind::Drowned), + "elder_guardian" => Some(EntityKind::ElderGuardian), + "end_crystal" => Some(EntityKind::EndCrystal), + "ender_dragon" => Some(EntityKind::EnderDragon), + "enderman" => Some(EntityKind::Enderman), + "endermite" => Some(EntityKind::Endermite), + "evoker" => Some(EntityKind::Evoker), + "evoker_fangs" => Some(EntityKind::EvokerFangs), + "experience_orb" => Some(EntityKind::ExperienceOrb), + "eye_of_ender" => Some(EntityKind::EyeOfEnder), + "falling_block" => Some(EntityKind::FallingBlock), + "firework_rocket" => Some(EntityKind::FireworkRocket), + "fox" => Some(EntityKind::Fox), + "ghast" => Some(EntityKind::Ghast), + "giant" => Some(EntityKind::Giant), + "guardian" => Some(EntityKind::Guardian), + "hoglin" => Some(EntityKind::Hoglin), + "horse" => Some(EntityKind::Horse), + "husk" => Some(EntityKind::Husk), + "illusioner" => Some(EntityKind::Illusioner), + "iron_golem" => Some(EntityKind::IronGolem), + "item" => Some(EntityKind::Item), + "item_frame" => Some(EntityKind::ItemFrame), + "fireball" => Some(EntityKind::Fireball), + "leash_knot" => Some(EntityKind::LeashKnot), + "lightning_bolt" => Some(EntityKind::LightningBolt), + "llama" => Some(EntityKind::Llama), + "llama_spit" => Some(EntityKind::LlamaSpit), + "magma_cube" => Some(EntityKind::MagmaCube), + "minecart" => Some(EntityKind::Minecart), + "chest_minecart" => Some(EntityKind::ChestMinecart), + "command_block_minecart" => Some(EntityKind::CommandBlockMinecart), + "furnace_minecart" => Some(EntityKind::FurnaceMinecart), + "hopper_minecart" => Some(EntityKind::HopperMinecart), + "spawner_minecart" => Some(EntityKind::SpawnerMinecart), + "tnt_minecart" => Some(EntityKind::TntMinecart), + "mule" => Some(EntityKind::Mule), + "mooshroom" => Some(EntityKind::Mooshroom), + "ocelot" => Some(EntityKind::Ocelot), + "painting" => Some(EntityKind::Painting), + "panda" => Some(EntityKind::Panda), + "parrot" => Some(EntityKind::Parrot), + "phantom" => Some(EntityKind::Phantom), + "pig" => Some(EntityKind::Pig), + "piglin" => Some(EntityKind::Piglin), + "piglin_brute" => Some(EntityKind::PiglinBrute), + "pillager" => Some(EntityKind::Pillager), + "polar_bear" => Some(EntityKind::PolarBear), + "tnt" => Some(EntityKind::Tnt), + "pufferfish" => Some(EntityKind::Pufferfish), + "rabbit" => Some(EntityKind::Rabbit), + "ravager" => Some(EntityKind::Ravager), + "salmon" => Some(EntityKind::Salmon), + "sheep" => Some(EntityKind::Sheep), + "shulker" => Some(EntityKind::Shulker), + "shulker_bullet" => Some(EntityKind::ShulkerBullet), + "silverfish" => Some(EntityKind::Silverfish), + "skeleton" => Some(EntityKind::Skeleton), + "skeleton_horse" => Some(EntityKind::SkeletonHorse), + "slime" => Some(EntityKind::Slime), + "small_fireball" => Some(EntityKind::SmallFireball), + "snow_golem" => Some(EntityKind::SnowGolem), + "snowball" => Some(EntityKind::Snowball), + "spectral_arrow" => Some(EntityKind::SpectralArrow), + "spider" => Some(EntityKind::Spider), + "squid" => Some(EntityKind::Squid), + "stray" => Some(EntityKind::Stray), + "strider" => Some(EntityKind::Strider), + "egg" => Some(EntityKind::Egg), + "ender_pearl" => Some(EntityKind::EnderPearl), + "experience_bottle" => Some(EntityKind::ExperienceBottle), + "potion" => Some(EntityKind::Potion), + "trident" => Some(EntityKind::Trident), + "trader_llama" => Some(EntityKind::TraderLlama), + "tropical_fish" => Some(EntityKind::TropicalFish), + "turtle" => Some(EntityKind::Turtle), + "vex" => Some(EntityKind::Vex), + "villager" => Some(EntityKind::Villager), + "vindicator" => Some(EntityKind::Vindicator), + "wandering_trader" => Some(EntityKind::WanderingTrader), + "witch" => Some(EntityKind::Witch), + "wither" => Some(EntityKind::Wither), + "wither_skeleton" => Some(EntityKind::WitherSkeleton), + "wither_skull" => Some(EntityKind::WitherSkull), + "wolf" => Some(EntityKind::Wolf), + "zoglin" => Some(EntityKind::Zoglin), + "zombie" => Some(EntityKind::Zombie), + "zombie_horse" => Some(EntityKind::ZombieHorse), + "zombie_villager" => Some(EntityKind::ZombieVillager), + "zombified_piglin" => Some(EntityKind::ZombifiedPiglin), + "player" => Some(EntityKind::Player), + "fishing_bobber" => Some(EntityKind::FishingBobber), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl EntityKind { + /// Returns the `display_name` property of this `EntityKind`. + pub fn display_name(&self) -> &'static str { + match self { + EntityKind::AreaEffectCloud => "Area Effect Cloud", + EntityKind::ArmorStand => "Armor Stand", + EntityKind::Arrow => "Arrow", + EntityKind::Bat => "Bat", + EntityKind::Bee => "Bee", + EntityKind::Blaze => "Blaze", + EntityKind::Boat => "Boat", + EntityKind::Cat => "Cat", + EntityKind::CaveSpider => "Cave Spider", + EntityKind::Chicken => "Chicken", + EntityKind::Cod => "Cod", + EntityKind::Cow => "Cow", + EntityKind::Creeper => "Creeper", + EntityKind::Dolphin => "Dolphin", + EntityKind::Donkey => "Donkey", + EntityKind::DragonFireball => "Dragon Fireball", + EntityKind::Drowned => "Drowned", + EntityKind::ElderGuardian => "Elder Guardian", + EntityKind::EndCrystal => "End Crystal", + EntityKind::EnderDragon => "Ender Dragon", + EntityKind::Enderman => "Enderman", + EntityKind::Endermite => "Endermite", + EntityKind::Evoker => "Evoker", + EntityKind::EvokerFangs => "Evoker Fangs", + EntityKind::ExperienceOrb => "Experience Orb", + EntityKind::EyeOfEnder => "Eye of Ender", + EntityKind::FallingBlock => "Falling Block", + EntityKind::FireworkRocket => "Firework Rocket", + EntityKind::Fox => "Fox", + EntityKind::Ghast => "Ghast", + EntityKind::Giant => "Giant", + EntityKind::Guardian => "Guardian", + EntityKind::Hoglin => "Hoglin", + EntityKind::Horse => "Horse", + EntityKind::Husk => "Husk", + EntityKind::Illusioner => "Illusioner", + EntityKind::IronGolem => "Iron Golem", + EntityKind::Item => "Item", + EntityKind::ItemFrame => "Item Frame", + EntityKind::Fireball => "Fireball", + EntityKind::LeashKnot => "Leash Knot", + EntityKind::LightningBolt => "Lightning Bolt", + EntityKind::Llama => "Llama", + EntityKind::LlamaSpit => "Llama Spit", + EntityKind::MagmaCube => "Magma Cube", + EntityKind::Minecart => "Minecart", + EntityKind::ChestMinecart => "Minecart with Chest", + EntityKind::CommandBlockMinecart => "Minecart with Command Block", + EntityKind::FurnaceMinecart => "Minecart with Furnace", + EntityKind::HopperMinecart => "Minecart with Hopper", + EntityKind::SpawnerMinecart => "Minecart with Spawner", + EntityKind::TntMinecart => "Minecart with TNT", + EntityKind::Mule => "Mule", + EntityKind::Mooshroom => "Mooshroom", + EntityKind::Ocelot => "Ocelot", + EntityKind::Painting => "Painting", + EntityKind::Panda => "Panda", + EntityKind::Parrot => "Parrot", + EntityKind::Phantom => "Phantom", + EntityKind::Pig => "Pig", + EntityKind::Piglin => "Piglin", + EntityKind::PiglinBrute => "Piglin Brute", + EntityKind::Pillager => "Pillager", + EntityKind::PolarBear => "Polar Bear", + EntityKind::Tnt => "Primed TNT", + EntityKind::Pufferfish => "Pufferfish", + EntityKind::Rabbit => "Rabbit", + EntityKind::Ravager => "Ravager", + EntityKind::Salmon => "Salmon", + EntityKind::Sheep => "Sheep", + EntityKind::Shulker => "Shulker", + EntityKind::ShulkerBullet => "Shulker Bullet", + EntityKind::Silverfish => "Silverfish", + EntityKind::Skeleton => "Skeleton", + EntityKind::SkeletonHorse => "Skeleton Horse", + EntityKind::Slime => "Slime", + EntityKind::SmallFireball => "Small Fireball", + EntityKind::SnowGolem => "Snow Golem", + EntityKind::Snowball => "Snowball", + EntityKind::SpectralArrow => "Spectral Arrow", + EntityKind::Spider => "Spider", + EntityKind::Squid => "Squid", + EntityKind::Stray => "Stray", + EntityKind::Strider => "Strider", + EntityKind::Egg => "Thrown Egg", + EntityKind::EnderPearl => "Thrown Ender Pearl", + EntityKind::ExperienceBottle => "Thrown Bottle o' Enchanting", + EntityKind::Potion => "Potion", + EntityKind::Trident => "Trident", + EntityKind::TraderLlama => "Trader Llama", + EntityKind::TropicalFish => "Tropical Fish", + EntityKind::Turtle => "Turtle", + EntityKind::Vex => "Vex", + EntityKind::Villager => "Villager", + EntityKind::Vindicator => "Vindicator", + EntityKind::WanderingTrader => "Wandering Trader", + EntityKind::Witch => "Witch", + EntityKind::Wither => "Wither", + EntityKind::WitherSkeleton => "Wither Skeleton", + EntityKind::WitherSkull => "Wither Skull", + EntityKind::Wolf => "Wolf", + EntityKind::Zoglin => "Zoglin", + EntityKind::Zombie => "Zombie", + EntityKind::ZombieHorse => "Zombie Horse", + EntityKind::ZombieVillager => "Zombie Villager", + EntityKind::ZombifiedPiglin => "Zombified Piglin", + EntityKind::Player => "Player", + EntityKind::FishingBobber => "Fishing Bobber", + } + } + + /// Gets a `EntityKind` by its `display_name`. + pub fn from_display_name(display_name: &str) -> Option<Self> { + match display_name { + "Area Effect Cloud" => Some(EntityKind::AreaEffectCloud), + "Armor Stand" => Some(EntityKind::ArmorStand), + "Arrow" => Some(EntityKind::Arrow), + "Bat" => Some(EntityKind::Bat), + "Bee" => Some(EntityKind::Bee), + "Blaze" => Some(EntityKind::Blaze), + "Boat" => Some(EntityKind::Boat), + "Cat" => Some(EntityKind::Cat), + "Cave Spider" => Some(EntityKind::CaveSpider), + "Chicken" => Some(EntityKind::Chicken), + "Cod" => Some(EntityKind::Cod), + "Cow" => Some(EntityKind::Cow), + "Creeper" => Some(EntityKind::Creeper), + "Dolphin" => Some(EntityKind::Dolphin), + "Donkey" => Some(EntityKind::Donkey), + "Dragon Fireball" => Some(EntityKind::DragonFireball), + "Drowned" => Some(EntityKind::Drowned), + "Elder Guardian" => Some(EntityKind::ElderGuardian), + "End Crystal" => Some(EntityKind::EndCrystal), + "Ender Dragon" => Some(EntityKind::EnderDragon), + "Enderman" => Some(EntityKind::Enderman), + "Endermite" => Some(EntityKind::Endermite), + "Evoker" => Some(EntityKind::Evoker), + "Evoker Fangs" => Some(EntityKind::EvokerFangs), + "Experience Orb" => Some(EntityKind::ExperienceOrb), + "Eye of Ender" => Some(EntityKind::EyeOfEnder), + "Falling Block" => Some(EntityKind::FallingBlock), + "Firework Rocket" => Some(EntityKind::FireworkRocket), + "Fox" => Some(EntityKind::Fox), + "Ghast" => Some(EntityKind::Ghast), + "Giant" => Some(EntityKind::Giant), + "Guardian" => Some(EntityKind::Guardian), + "Hoglin" => Some(EntityKind::Hoglin), + "Horse" => Some(EntityKind::Horse), + "Husk" => Some(EntityKind::Husk), + "Illusioner" => Some(EntityKind::Illusioner), + "Iron Golem" => Some(EntityKind::IronGolem), + "Item" => Some(EntityKind::Item), + "Item Frame" => Some(EntityKind::ItemFrame), + "Fireball" => Some(EntityKind::Fireball), + "Leash Knot" => Some(EntityKind::LeashKnot), + "Lightning Bolt" => Some(EntityKind::LightningBolt), + "Llama" => Some(EntityKind::Llama), + "Llama Spit" => Some(EntityKind::LlamaSpit), + "Magma Cube" => Some(EntityKind::MagmaCube), + "Minecart" => Some(EntityKind::Minecart), + "Minecart with Chest" => Some(EntityKind::ChestMinecart), + "Minecart with Command Block" => Some(EntityKind::CommandBlockMinecart), + "Minecart with Furnace" => Some(EntityKind::FurnaceMinecart), + "Minecart with Hopper" => Some(EntityKind::HopperMinecart), + "Minecart with Spawner" => Some(EntityKind::SpawnerMinecart), + "Minecart with TNT" => Some(EntityKind::TntMinecart), + "Mule" => Some(EntityKind::Mule), + "Mooshroom" => Some(EntityKind::Mooshroom), + "Ocelot" => Some(EntityKind::Ocelot), + "Painting" => Some(EntityKind::Painting), + "Panda" => Some(EntityKind::Panda), + "Parrot" => Some(EntityKind::Parrot), + "Phantom" => Some(EntityKind::Phantom), + "Pig" => Some(EntityKind::Pig), + "Piglin" => Some(EntityKind::Piglin), + "Piglin Brute" => Some(EntityKind::PiglinBrute), + "Pillager" => Some(EntityKind::Pillager), + "Polar Bear" => Some(EntityKind::PolarBear), + "Primed TNT" => Some(EntityKind::Tnt), + "Pufferfish" => Some(EntityKind::Pufferfish), + "Rabbit" => Some(EntityKind::Rabbit), + "Ravager" => Some(EntityKind::Ravager), + "Salmon" => Some(EntityKind::Salmon), + "Sheep" => Some(EntityKind::Sheep), + "Shulker" => Some(EntityKind::Shulker), + "Shulker Bullet" => Some(EntityKind::ShulkerBullet), + "Silverfish" => Some(EntityKind::Silverfish), + "Skeleton" => Some(EntityKind::Skeleton), + "Skeleton Horse" => Some(EntityKind::SkeletonHorse), + "Slime" => Some(EntityKind::Slime), + "Small Fireball" => Some(EntityKind::SmallFireball), + "Snow Golem" => Some(EntityKind::SnowGolem), + "Snowball" => Some(EntityKind::Snowball), + "Spectral Arrow" => Some(EntityKind::SpectralArrow), + "Spider" => Some(EntityKind::Spider), + "Squid" => Some(EntityKind::Squid), + "Stray" => Some(EntityKind::Stray), + "Strider" => Some(EntityKind::Strider), + "Thrown Egg" => Some(EntityKind::Egg), + "Thrown Ender Pearl" => Some(EntityKind::EnderPearl), + "Thrown Bottle o' Enchanting" => Some(EntityKind::ExperienceBottle), + "Potion" => Some(EntityKind::Potion), + "Trident" => Some(EntityKind::Trident), + "Trader Llama" => Some(EntityKind::TraderLlama), + "Tropical Fish" => Some(EntityKind::TropicalFish), + "Turtle" => Some(EntityKind::Turtle), + "Vex" => Some(EntityKind::Vex), + "Villager" => Some(EntityKind::Villager), + "Vindicator" => Some(EntityKind::Vindicator), + "Wandering Trader" => Some(EntityKind::WanderingTrader), + "Witch" => Some(EntityKind::Witch), + "Wither" => Some(EntityKind::Wither), + "Wither Skeleton" => Some(EntityKind::WitherSkeleton), + "Wither Skull" => Some(EntityKind::WitherSkull), + "Wolf" => Some(EntityKind::Wolf), + "Zoglin" => Some(EntityKind::Zoglin), + "Zombie" => Some(EntityKind::Zombie), + "Zombie Horse" => Some(EntityKind::ZombieHorse), + "Zombie Villager" => Some(EntityKind::ZombieVillager), + "Zombified Piglin" => Some(EntityKind::ZombifiedPiglin), + "Player" => Some(EntityKind::Player), + "Fishing Bobber" => Some(EntityKind::FishingBobber), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl EntityKind { + /// Returns the `bounding_box` property of this `EntityKind`. + pub fn bounding_box(&self) -> vek::Aabb<f64> { + match self { + EntityKind::AreaEffectCloud => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(6 as f64, 0.5 as f64, 6 as f64), + }, + EntityKind::ArmorStand => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 1.975 as f64, 0.5 as f64), + }, + EntityKind::Arrow => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.5 as f64, 0.5 as f64), + }, + EntityKind::Bat => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.9 as f64, 0.5 as f64), + }, + EntityKind::Bee => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.7 as f64, 0.6 as f64, 0.7 as f64), + }, + EntityKind::Blaze => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.8 as f64, 0.6 as f64), + }, + EntityKind::Boat => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.375 as f64, 0.5625 as f64, 1.375 as f64), + }, + EntityKind::Cat => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 0.7 as f64, 0.6 as f64), + }, + EntityKind::CaveSpider => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.7 as f64, 0.5 as f64, 0.7 as f64), + }, + EntityKind::Chicken => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.4 as f64, 0.7 as f64, 0.4 as f64), + }, + EntityKind::Cod => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.3 as f64, 0.5 as f64), + }, + EntityKind::Cow => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 1.4 as f64, 0.9 as f64), + }, + EntityKind::Creeper => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.7 as f64, 0.6 as f64), + }, + EntityKind::Dolphin => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 0.6 as f64, 0.9 as f64), + }, + EntityKind::Donkey => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.39648 as f64, 1.5 as f64, 1.39648 as f64), + }, + EntityKind::DragonFireball => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1 as f64, 1 as f64, 1 as f64), + }, + EntityKind::Drowned => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::ElderGuardian => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.9975 as f64, 1.9975 as f64, 1.9975 as f64), + }, + EntityKind::EndCrystal => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(2 as f64, 2 as f64, 2 as f64), + }, + EntityKind::EnderDragon => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(16 as f64, 8 as f64, 16 as f64), + }, + EntityKind::Enderman => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 2.9 as f64, 0.6 as f64), + }, + EntityKind::Endermite => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.4 as f64, 0.3 as f64, 0.4 as f64), + }, + EntityKind::Evoker => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::EvokerFangs => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.8 as f64, 0.5 as f64), + }, + EntityKind::ExperienceOrb => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.5 as f64, 0.5 as f64), + }, + EntityKind::EyeOfEnder => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::FallingBlock => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.98 as f64, 0.98 as f64), + }, + EntityKind::FireworkRocket => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::Fox => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 0.7 as f64, 0.6 as f64), + }, + EntityKind::Ghast => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(4 as f64, 4 as f64, 4 as f64), + }, + EntityKind::Giant => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(3.6 as f64, 12 as f64, 3.6 as f64), + }, + EntityKind::Guardian => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.85 as f64, 0.85 as f64, 0.85 as f64), + }, + EntityKind::Hoglin => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.39648 as f64, 1.4 as f64, 1.39648 as f64), + }, + EntityKind::Horse => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.39648 as f64, 1.6 as f64, 1.39648 as f64), + }, + EntityKind::Husk => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::Illusioner => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::IronGolem => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.4 as f64, 2.7 as f64, 1.4 as f64), + }, + EntityKind::Item => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::ItemFrame => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.5 as f64, 0.5 as f64), + }, + EntityKind::Fireball => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1 as f64, 1 as f64, 1 as f64), + }, + EntityKind::LeashKnot => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.5 as f64, 0.5 as f64), + }, + EntityKind::LightningBolt => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0 as f64, 0 as f64, 0 as f64), + }, + EntityKind::Llama => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 1.87 as f64, 0.9 as f64), + }, + EntityKind::LlamaSpit => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::MagmaCube => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(2.04 as f64, 2.04 as f64, 2.04 as f64), + }, + EntityKind::Minecart => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.7 as f64, 0.98 as f64), + }, + EntityKind::ChestMinecart => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.7 as f64, 0.98 as f64), + }, + EntityKind::CommandBlockMinecart => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.7 as f64, 0.98 as f64), + }, + EntityKind::FurnaceMinecart => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.7 as f64, 0.98 as f64), + }, + EntityKind::HopperMinecart => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.7 as f64, 0.98 as f64), + }, + EntityKind::SpawnerMinecart => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.7 as f64, 0.98 as f64), + }, + EntityKind::TntMinecart => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.7 as f64, 0.98 as f64), + }, + EntityKind::Mule => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.39648 as f64, 1.6 as f64, 1.39648 as f64), + }, + EntityKind::Mooshroom => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 1.4 as f64, 0.9 as f64), + }, + EntityKind::Ocelot => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 0.7 as f64, 0.6 as f64), + }, + EntityKind::Painting => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.5 as f64, 0.5 as f64), + }, + EntityKind::Panda => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.3 as f64, 1.25 as f64, 1.3 as f64), + }, + EntityKind::Parrot => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.9 as f64, 0.5 as f64), + }, + EntityKind::Phantom => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 0.5 as f64, 0.9 as f64), + }, + EntityKind::Pig => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 0.9 as f64, 0.9 as f64), + }, + EntityKind::Piglin => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::PiglinBrute => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::Pillager => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::PolarBear => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.4 as f64, 1.4 as f64, 1.4 as f64), + }, + EntityKind::Tnt => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.98 as f64, 0.98 as f64, 0.98 as f64), + }, + EntityKind::Pufferfish => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.7 as f64, 0.7 as f64, 0.7 as f64), + }, + EntityKind::Rabbit => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.4 as f64, 0.5 as f64, 0.4 as f64), + }, + EntityKind::Ravager => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.95 as f64, 2.2 as f64, 1.95 as f64), + }, + EntityKind::Salmon => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.7 as f64, 0.4 as f64, 0.7 as f64), + }, + EntityKind::Sheep => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 1.3 as f64, 0.9 as f64), + }, + EntityKind::Shulker => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1 as f64, 1 as f64, 1 as f64), + }, + EntityKind::ShulkerBullet => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.3125 as f64, 0.3125 as f64, 0.3125 as f64), + }, + EntityKind::Silverfish => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.4 as f64, 0.3 as f64, 0.4 as f64), + }, + EntityKind::Skeleton => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.99 as f64, 0.6 as f64), + }, + EntityKind::SkeletonHorse => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.39648 as f64, 1.6 as f64, 1.39648 as f64), + }, + EntityKind::Slime => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(2.04 as f64, 2.04 as f64, 2.04 as f64), + }, + EntityKind::SmallFireball => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.3125 as f64, 0.3125 as f64, 0.3125 as f64), + }, + EntityKind::SnowGolem => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.7 as f64, 1.9 as f64, 0.7 as f64), + }, + EntityKind::Snowball => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::SpectralArrow => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.5 as f64, 0.5 as f64), + }, + EntityKind::Spider => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.4 as f64, 0.9 as f64, 1.4 as f64), + }, + EntityKind::Squid => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.8 as f64, 0.8 as f64, 0.8 as f64), + }, + EntityKind::Stray => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.99 as f64, 0.6 as f64), + }, + EntityKind::Strider => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 1.7 as f64, 0.9 as f64), + }, + EntityKind::Egg => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::EnderPearl => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::ExperienceBottle => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::Potion => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + EntityKind::Trident => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.5 as f64, 0.5 as f64), + }, + EntityKind::TraderLlama => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 1.87 as f64, 0.9 as f64), + }, + EntityKind::TropicalFish => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.5 as f64, 0.4 as f64, 0.5 as f64), + }, + EntityKind::Turtle => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.2 as f64, 0.4 as f64, 1.2 as f64), + }, + EntityKind::Vex => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.4 as f64, 0.8 as f64, 0.4 as f64), + }, + EntityKind::Villager => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::Vindicator => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::WanderingTrader => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::Witch => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::Wither => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.9 as f64, 3.5 as f64, 0.9 as f64), + }, + EntityKind::WitherSkeleton => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.7 as f64, 2.4 as f64, 0.7 as f64), + }, + EntityKind::WitherSkull => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.3125 as f64, 0.3125 as f64, 0.3125 as f64), + }, + EntityKind::Wolf => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 0.85 as f64, 0.6 as f64), + }, + EntityKind::Zoglin => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.39648 as f64, 1.4 as f64, 1.39648 as f64), + }, + EntityKind::Zombie => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::ZombieHorse => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(1.39648 as f64, 1.6 as f64, 1.39648 as f64), + }, + EntityKind::ZombieVillager => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::ZombifiedPiglin => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.95 as f64, 0.6 as f64), + }, + EntityKind::Player => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.6 as f64, 1.8 as f64, 0.6 as f64), + }, + EntityKind::FishingBobber => vek::Aabb { + min: vek::Vec3::zero(), + max: vek::Vec3::new(0.25 as f64, 0.25 as f64, 0.25 as f64), + }, + } + } +} diff --git a/libcraft/core/src/gamemode.rs b/libcraft/core/src/gamemode.rs new file mode 100644 index 000000000..9996efea8 --- /dev/null +++ b/libcraft/core/src/gamemode.rs @@ -0,0 +1,28 @@ +use num_derive::{FromPrimitive, ToPrimitive}; +use serde::{Deserialize, Serialize}; + +/// A gamemode. +#[derive( + Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, FromPrimitive, ToPrimitive, +)] +#[serde(rename_all = "snake_case")] +#[repr(u8)] +pub enum Gamemode { + Survival = 0, + Creative = 1, + Adventure = 2, + Spectator = 3, +} + +impl Gamemode { + /// Gets a gamemode from its ID. + pub fn from_id(id: u8) -> Option<Self> { + Some(match id { + 0 => Gamemode::Survival, + 1 => Gamemode::Creative, + 2 => Gamemode::Adventure, + 3 => Gamemode::Spectator, + _ => return None, + }) + } +} diff --git a/libcraft/core/src/gamerules.rs b/libcraft/core/src/gamerules.rs new file mode 100644 index 000000000..e9455ca55 --- /dev/null +++ b/libcraft/core/src/gamerules.rs @@ -0,0 +1,82 @@ +//! Data sourced from: <https://minecraft.gamepedia.com/Game_rule> + +use serde::{Deserialize, Serialize}; + +/// All game rules. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GameRules { + announce_advancements: bool, + command_block_output: bool, + disable_elytra_movement_check: bool, + disable_raids: bool, + do_daylight_cycle: bool, + do_entity_drops: bool, + do_fire_tick: bool, + do_insomnia: bool, + do_immediate_respawn: bool, + do_limited_crafting: bool, + do_mob_loot: bool, + do_mob_spawning: bool, + do_patrol_spawning: bool, + do_tile_drops: bool, + do_trader_spawning: bool, + do_weather_cycle: bool, + drowning_damage: bool, + fall_damage: bool, + fire_damage: bool, + forgive_dead_players: bool, + keep_inventory: bool, + log_admin_commands: bool, + max_command_chain_length: u32, + max_entity_cramming: u32, + mob_griefing: bool, + natural_regeneration: bool, + random_tick_speed: u32, + reduced_debug_info: bool, + send_command_feedback: bool, + show_death_messages: bool, + spawn_radius: u32, + spectators_generate_chunks: bool, + universal_anger: bool, +} + +impl Default for GameRules { + fn default() -> Self { + Self { + announce_advancements: true, + command_block_output: true, + disable_elytra_movement_check: false, + disable_raids: false, + do_daylight_cycle: true, + do_entity_drops: true, + do_fire_tick: true, + do_insomnia: true, + do_immediate_respawn: false, + do_limited_crafting: false, + do_mob_loot: true, + do_mob_spawning: true, + do_patrol_spawning: true, + do_tile_drops: true, + do_trader_spawning: true, + do_weather_cycle: true, + drowning_damage: true, + fall_damage: true, + fire_damage: true, + forgive_dead_players: true, + keep_inventory: false, + log_admin_commands: true, + max_command_chain_length: 65536, + max_entity_cramming: 24, + mob_griefing: true, + natural_regeneration: true, + random_tick_speed: 3, + reduced_debug_info: false, + send_command_feedback: true, + show_death_messages: true, + spawn_radius: 10, + spectators_generate_chunks: true, + universal_anger: false, + } + } +} diff --git a/libcraft/core/src/interaction.rs b/libcraft/core/src/interaction.rs new file mode 100644 index 000000000..216d1c398 --- /dev/null +++ b/libcraft/core/src/interaction.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum InteractionType { + Interact, + Attack, + InteractAt, +} diff --git a/libcraft/core/src/lib.rs b/libcraft/core/src/lib.rs new file mode 100644 index 000000000..cd3d042c1 --- /dev/null +++ b/libcraft/core/src/lib.rs @@ -0,0 +1,25 @@ +//! Foundational types and constants for Minecraft. + +mod biome; +pub mod block; +mod consts; +mod dimension; +mod entity; +mod gamemode; +mod gamerules; +mod interaction; +mod player; +mod positions; + +pub use biome::Biome; +pub use consts::*; +pub use dimension::Dimension; +pub use entity::EntityKind; +pub use gamemode::Gamemode; +pub use gamerules::GameRules; +pub use interaction::InteractionType; +pub use player::Hand; +pub use positions::{ + vec3, Aabb, BlockFace, BlockPosition, ChunkPosition, Mat4f, Position, Vec2d, Vec2f, Vec2i, + Vec3d, Vec3f, Vec3i, Vec4d, Vec4f, Vec4i, +}; diff --git a/libcraft/core/src/particle.rs b/libcraft/core/src/particle.rs new file mode 100644 index 000000000..ea6dc8196 --- /dev/null +++ b/libcraft/core/src/particle.rs @@ -0,0 +1,403 @@ +// This file is @generated. Please do not edit. + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Particle { + AmbientEntityEffect, + AngryVillager, + Barrier, + Block(BlockId), + Bubble, + Cloud, + Crit, + DamageIndicator, + DragonBreath, + DrippingLava, + FallingLava, + LandingLava, + DrippingWater, + FallingWater, + Dust { + red: f32, + green: f32, + blue: f32, + scale: f32, + }, + Effect, + ElderGuardian, + EnchantedHit, + Enchant, + EndRod, + EntityEffect, + ExplosionEmitter, + Explosion, + FallingDust(BlockId), + Firework, + Fishing, + Flame, + SoulFireFlame, + Soul, + Flash, + HappyVillager, + Composter, + Heart, + InstantEffect, + Item(f32), + ItemSlime, + ItemSnowball, + LargeSmoke, + Lava, + Mycelium, + Note, + Poof, + Portal, + Rain, + Smoke, + Sneeze, + Spit, + SquidInk, + SweepAttack, + TotemOfUndying, + Underwater, + Splash, + Witch, + BubblePop, + CurrentDown, + BubbleColumnUp, + Nautilus, + Dolphin, + CampfireCosySmoke, + CampfireSignalSmoke, + DrippingHoney, + FallingHoney, + LandingHoney, + FallingNectar, + Ash, + CrimsonSpore, + WarpedSpore, + DrippingObsidianTear, + FallingObsidianTear, + LandingObsidianTear, + ReversePortal, + WhiteAsh, +} + +#[allow(warnings)] +#[allow(clippy::all)] +impl Particle { + /// Returns the `id` property of this `Particle`. + pub fn id(&self) -> u32 { + match self { + Particle::AmbientEntityEffect => 0, + Particle::AngryVillager => 1, + Particle::Barrier => 2, + Particle::Block => 3, + Particle::Bubble => 4, + Particle::Cloud => 5, + Particle::Crit => 6, + Particle::DamageIndicator => 7, + Particle::DragonBreath => 8, + Particle::DrippingLava => 9, + Particle::FallingLava => 10, + Particle::LandingLava => 11, + Particle::DrippingWater => 12, + Particle::FallingWater => 13, + Particle::Dust => 14, + Particle::Effect => 15, + Particle::ElderGuardian => 16, + Particle::EnchantedHit => 17, + Particle::Enchant => 18, + Particle::EndRod => 19, + Particle::EntityEffect => 20, + Particle::ExplosionEmitter => 21, + Particle::Explosion => 22, + Particle::FallingDust => 23, + Particle::Firework => 24, + Particle::Fishing => 25, + Particle::Flame => 26, + Particle::SoulFireFlame => 27, + Particle::Soul => 28, + Particle::Flash => 29, + Particle::HappyVillager => 30, + Particle::Composter => 31, + Particle::Heart => 32, + Particle::InstantEffect => 33, + Particle::Item => 34, + Particle::ItemSlime => 35, + Particle::ItemSnowball => 36, + Particle::LargeSmoke => 37, + Particle::Lava => 38, + Particle::Mycelium => 39, + Particle::Note => 40, + Particle::Poof => 41, + Particle::Portal => 42, + Particle::Rain => 43, + Particle::Smoke => 44, + Particle::Sneeze => 45, + Particle::Spit => 46, + Particle::SquidInk => 47, + Particle::SweepAttack => 48, + Particle::TotemOfUndying => 49, + Particle::Underwater => 50, + Particle::Splash => 51, + Particle::Witch => 52, + Particle::BubblePop => 53, + Particle::CurrentDown => 54, + Particle::BubbleColumnUp => 55, + Particle::Nautilus => 56, + Particle::Dolphin => 57, + Particle::CampfireCosySmoke => 58, + Particle::CampfireSignalSmoke => 59, + Particle::DrippingHoney => 60, + Particle::FallingHoney => 61, + Particle::LandingHoney => 62, + Particle::FallingNectar => 63, + Particle::Ash => 64, + Particle::CrimsonSpore => 65, + Particle::WarpedSpore => 66, + Particle::DrippingObsidianTear => 67, + Particle::FallingObsidianTear => 68, + Particle::LandingObsidianTear => 69, + Particle::ReversePortal => 70, + Particle::WhiteAsh => 71, + } + } + + /// Gets a `Particle` by its `id`. + pub fn from_id(id: u32) -> Option<Self> { + match id { + 0 => Some(Particle::AmbientEntityEffect), + 1 => Some(Particle::AngryVillager), + 2 => Some(Particle::Barrier), + 3 => Some(Particle::Block), + 4 => Some(Particle::Bubble), + 5 => Some(Particle::Cloud), + 6 => Some(Particle::Crit), + 7 => Some(Particle::DamageIndicator), + 8 => Some(Particle::DragonBreath), + 9 => Some(Particle::DrippingLava), + 10 => Some(Particle::FallingLava), + 11 => Some(Particle::LandingLava), + 12 => Some(Particle::DrippingWater), + 13 => Some(Particle::FallingWater), + 14 => Some(Particle::Dust), + 15 => Some(Particle::Effect), + 16 => Some(Particle::ElderGuardian), + 17 => Some(Particle::EnchantedHit), + 18 => Some(Particle::Enchant), + 19 => Some(Particle::EndRod), + 20 => Some(Particle::EntityEffect), + 21 => Some(Particle::ExplosionEmitter), + 22 => Some(Particle::Explosion), + 23 => Some(Particle::FallingDust), + 24 => Some(Particle::Firework), + 25 => Some(Particle::Fishing), + 26 => Some(Particle::Flame), + 27 => Some(Particle::SoulFireFlame), + 28 => Some(Particle::Soul), + 29 => Some(Particle::Flash), + 30 => Some(Particle::HappyVillager), + 31 => Some(Particle::Composter), + 32 => Some(Particle::Heart), + 33 => Some(Particle::InstantEffect), + 34 => Some(Particle::Item), + 35 => Some(Particle::ItemSlime), + 36 => Some(Particle::ItemSnowball), + 37 => Some(Particle::LargeSmoke), + 38 => Some(Particle::Lava), + 39 => Some(Particle::Mycelium), + 40 => Some(Particle::Note), + 41 => Some(Particle::Poof), + 42 => Some(Particle::Portal), + 43 => Some(Particle::Rain), + 44 => Some(Particle::Smoke), + 45 => Some(Particle::Sneeze), + 46 => Some(Particle::Spit), + 47 => Some(Particle::SquidInk), + 48 => Some(Particle::SweepAttack), + 49 => Some(Particle::TotemOfUndying), + 50 => Some(Particle::Underwater), + 51 => Some(Particle::Splash), + 52 => Some(Particle::Witch), + 53 => Some(Particle::BubblePop), + 54 => Some(Particle::CurrentDown), + 55 => Some(Particle::BubbleColumnUp), + 56 => Some(Particle::Nautilus), + 57 => Some(Particle::Dolphin), + 58 => Some(Particle::CampfireCosySmoke), + 59 => Some(Particle::CampfireSignalSmoke), + 60 => Some(Particle::DrippingHoney), + 61 => Some(Particle::FallingHoney), + 62 => Some(Particle::LandingHoney), + 63 => Some(Particle::FallingNectar), + 64 => Some(Particle::Ash), + 65 => Some(Particle::CrimsonSpore), + 66 => Some(Particle::WarpedSpore), + 67 => Some(Particle::DrippingObsidianTear), + 68 => Some(Particle::FallingObsidianTear), + 69 => Some(Particle::LandingObsidianTear), + 70 => Some(Particle::ReversePortal), + 71 => Some(Particle::WhiteAsh), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Particle { + /// Returns the `name` property of this `Particle`. + pub fn name(&self) -> &'static str { + match self { + Particle::AmbientEntityEffect => "ambient_entity_effect", + Particle::AngryVillager => "angry_villager", + Particle::Barrier => "barrier", + Particle::Block => "block", + Particle::Bubble => "bubble", + Particle::Cloud => "cloud", + Particle::Crit => "crit", + Particle::DamageIndicator => "damage_indicator", + Particle::DragonBreath => "dragon_breath", + Particle::DrippingLava => "dripping_lava", + Particle::FallingLava => "falling_lava", + Particle::LandingLava => "landing_lava", + Particle::DrippingWater => "dripping_water", + Particle::FallingWater => "falling_water", + Particle::Dust => "dust", + Particle::Effect => "effect", + Particle::ElderGuardian => "elder_guardian", + Particle::EnchantedHit => "enchanted_hit", + Particle::Enchant => "enchant", + Particle::EndRod => "end_rod", + Particle::EntityEffect => "entity_effect", + Particle::ExplosionEmitter => "explosion_emitter", + Particle::Explosion => "explosion", + Particle::FallingDust => "falling_dust", + Particle::Firework => "firework", + Particle::Fishing => "fishing", + Particle::Flame => "flame", + Particle::SoulFireFlame => "soul_fire_flame", + Particle::Soul => "soul", + Particle::Flash => "flash", + Particle::HappyVillager => "happy_villager", + Particle::Composter => "composter", + Particle::Heart => "heart", + Particle::InstantEffect => "instant_effect", + Particle::Item => "item", + Particle::ItemSlime => "item_slime", + Particle::ItemSnowball => "item_snowball", + Particle::LargeSmoke => "large_smoke", + Particle::Lava => "lava", + Particle::Mycelium => "mycelium", + Particle::Note => "note", + Particle::Poof => "poof", + Particle::Portal => "portal", + Particle::Rain => "rain", + Particle::Smoke => "smoke", + Particle::Sneeze => "sneeze", + Particle::Spit => "spit", + Particle::SquidInk => "squid_ink", + Particle::SweepAttack => "sweep_attack", + Particle::TotemOfUndying => "totem_of_undying", + Particle::Underwater => "underwater", + Particle::Splash => "splash", + Particle::Witch => "witch", + Particle::BubblePop => "bubble_pop", + Particle::CurrentDown => "current_down", + Particle::BubbleColumnUp => "bubble_column_up", + Particle::Nautilus => "nautilus", + Particle::Dolphin => "dolphin", + Particle::CampfireCosySmoke => "campfire_cosy_smoke", + Particle::CampfireSignalSmoke => "campfire_signal_smoke", + Particle::DrippingHoney => "dripping_honey", + Particle::FallingHoney => "falling_honey", + Particle::LandingHoney => "landing_honey", + Particle::FallingNectar => "falling_nectar", + Particle::Ash => "ash", + Particle::CrimsonSpore => "crimson_spore", + Particle::WarpedSpore => "warped_spore", + Particle::DrippingObsidianTear => "dripping_obsidian_tear", + Particle::FallingObsidianTear => "falling_obsidian_tear", + Particle::LandingObsidianTear => "landing_obsidian_tear", + Particle::ReversePortal => "reverse_portal", + Particle::WhiteAsh => "white_ash", + } + } + + /// Gets a `Particle` by its `name`. + pub fn from_name(name: &str) -> Option<Self> { + match name { + "ambient_entity_effect" => Some(Particle::AmbientEntityEffect), + "angry_villager" => Some(Particle::AngryVillager), + "barrier" => Some(Particle::Barrier), + "block" => Some(Particle::Block), + "bubble" => Some(Particle::Bubble), + "cloud" => Some(Particle::Cloud), + "crit" => Some(Particle::Crit), + "damage_indicator" => Some(Particle::DamageIndicator), + "dragon_breath" => Some(Particle::DragonBreath), + "dripping_lava" => Some(Particle::DrippingLava), + "falling_lava" => Some(Particle::FallingLava), + "landing_lava" => Some(Particle::LandingLava), + "dripping_water" => Some(Particle::DrippingWater), + "falling_water" => Some(Particle::FallingWater), + "dust" => Some(Particle::Dust), + "effect" => Some(Particle::Effect), + "elder_guardian" => Some(Particle::ElderGuardian), + "enchanted_hit" => Some(Particle::EnchantedHit), + "enchant" => Some(Particle::Enchant), + "end_rod" => Some(Particle::EndRod), + "entity_effect" => Some(Particle::EntityEffect), + "explosion_emitter" => Some(Particle::ExplosionEmitter), + "explosion" => Some(Particle::Explosion), + "falling_dust" => Some(Particle::FallingDust), + "firework" => Some(Particle::Firework), + "fishing" => Some(Particle::Fishing), + "flame" => Some(Particle::Flame), + "soul_fire_flame" => Some(Particle::SoulFireFlame), + "soul" => Some(Particle::Soul), + "flash" => Some(Particle::Flash), + "happy_villager" => Some(Particle::HappyVillager), + "composter" => Some(Particle::Composter), + "heart" => Some(Particle::Heart), + "instant_effect" => Some(Particle::InstantEffect), + "item" => Some(Particle::Item), + "item_slime" => Some(Particle::ItemSlime), + "item_snowball" => Some(Particle::ItemSnowball), + "large_smoke" => Some(Particle::LargeSmoke), + "lava" => Some(Particle::Lava), + "mycelium" => Some(Particle::Mycelium), + "note" => Some(Particle::Note), + "poof" => Some(Particle::Poof), + "portal" => Some(Particle::Portal), + "rain" => Some(Particle::Rain), + "smoke" => Some(Particle::Smoke), + "sneeze" => Some(Particle::Sneeze), + "spit" => Some(Particle::Spit), + "squid_ink" => Some(Particle::SquidInk), + "sweep_attack" => Some(Particle::SweepAttack), + "totem_of_undying" => Some(Particle::TotemOfUndying), + "underwater" => Some(Particle::Underwater), + "splash" => Some(Particle::Splash), + "witch" => Some(Particle::Witch), + "bubble_pop" => Some(Particle::BubblePop), + "current_down" => Some(Particle::CurrentDown), + "bubble_column_up" => Some(Particle::BubbleColumnUp), + "nautilus" => Some(Particle::Nautilus), + "dolphin" => Some(Particle::Dolphin), + "campfire_cosy_smoke" => Some(Particle::CampfireCosySmoke), + "campfire_signal_smoke" => Some(Particle::CampfireSignalSmoke), + "dripping_honey" => Some(Particle::DrippingHoney), + "falling_honey" => Some(Particle::FallingHoney), + "landing_honey" => Some(Particle::LandingHoney), + "falling_nectar" => Some(Particle::FallingNectar), + "ash" => Some(Particle::Ash), + "crimson_spore" => Some(Particle::CrimsonSpore), + "warped_spore" => Some(Particle::WarpedSpore), + "dripping_obsidian_tear" => Some(Particle::DrippingObsidianTear), + "falling_obsidian_tear" => Some(Particle::FallingObsidianTear), + "landing_obsidian_tear" => Some(Particle::LandingObsidianTear), + "reverse_portal" => Some(Particle::ReversePortal), + "white_ash" => Some(Particle::WhiteAsh), + _ => None, + } + } +} diff --git a/libcraft/core/src/player.rs b/libcraft/core/src/player.rs new file mode 100644 index 000000000..e2ad42a76 --- /dev/null +++ b/libcraft/core/src/player.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum Hand { + Main, + Offhand, +} diff --git a/libcraft/core/src/positions.rs b/libcraft/core/src/positions.rs new file mode 100644 index 000000000..81606b6f6 --- /dev/null +++ b/libcraft/core/src/positions.rs @@ -0,0 +1,444 @@ +//! Position and math-related types. + +use bytemuck::{Pod, Zeroable}; +use fmt::Formatter; +use serde::{Deserialize, Serialize}; +use std::{ + fmt::{self, Display}, + ops::{Add, Sub}, +}; +use vek::{Mat4, Vec2, Vec3, Vec4}; + +use crate::CHUNK_WIDTH; +pub type Vec2i = Vec2<i32>; +pub type Vec3i = Vec3<i32>; +pub type Vec4i = Vec4<i32>; + +pub type Vec2f = Vec2<f32>; +pub type Vec3f = Vec3<f32>; +pub type Vec4f = Vec4<f32>; + +/// Two-component double-precision floating point vector. +pub type Vec2d = Vec2<f64>; +/// Three-component double-precision floating point vector. +pub type Vec3d = Vec3<f64>; +/// Four-compounent double-precision floating point vector. +pub type Vec4d = Vec4<f64>; + +pub type Aabb = vek::Aabb<f64>; + +pub type Mat4f = Mat4<f32>; + +/// Creates a `Vec3<T>`. +pub fn vec3<T>(x: T, y: T, z: T) -> Vec3<T> { + Vec3::new(x, y, z) +} + +/// Creates a `Position`. +#[macro_export] +macro_rules! position { + ($x:expr, $y:expr, $z:expr, $pitch:expr, $yaw:expr $(,)?) => { + $crate::Position { + x: $x, + y: $y, + z: $z, + pitch: $pitch, + yaw: $yaw, + } + }; + ($x:expr, $y:expr, $z:expr $(,)?) => { + position!($x, $y, $z, 0.0, 0.0) + }; + ($x:expr, $y:expr, $z:expr, $on_ground: expr $(,)?) => { + position!($x, $y, $z, 0.0, 0.0, $on_ground) + }; +} + +/// The position of an entity. +/// +/// This includes a world-space transform, +/// a 2D Euler angle rotation, and an on_ground field used for physics. +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Pod, Zeroable)] +#[repr(C)] +pub struct Position { + pub x: f64, + pub y: f64, + pub z: f64, + pub pitch: f32, + pub yaw: f32, +} + +impl Default for Position { + fn default() -> Self { + position!(0.0, 64.0, 0.0) + } +} + +impl Position { + pub fn distance_to(&self, other: Position) -> f64 { + self.distance_squared_to(other).sqrt() + } + + pub fn distance_squared_to(&self, other: Position) -> f64 { + square(self.x - other.x) + square(self.y - other.y) + square(self.z - other.z) + } + + /// Returns a unit vector representing + /// the direction of this position's pitch + /// and yaw. + pub fn direction(&self) -> Vec3d { + let rotation_x = f64::from(self.yaw.to_radians()); + let rotation_y = f64::from(self.pitch.to_radians()); + + let y = -rotation_y.sin(); + + let xz = rotation_y.cos(); + + let x = -xz * rotation_x.sin(); + let z = xz * rotation_x.cos(); + + vec3(x, y, z) + } + + pub fn chunk(self) -> ChunkPosition { + self.into() + } + + pub fn block(self) -> BlockPosition { + self.into() + } + + pub fn vec(&self) -> Vec3d { + (*self).into() + } +} + +impl Add<Vec3d> for Position { + type Output = Position; + + fn add(mut self, rhs: Vec3d) -> Self::Output { + self.x += rhs.x; + self.y += rhs.y; + self.z += rhs.z; + self + } +} + +impl Add<Position> for Position { + type Output = Position; + + fn add(mut self, rhs: Position) -> Self::Output { + self.x += rhs.x; + self.y += rhs.y; + self.z += rhs.z; + self.pitch += rhs.pitch; + self.yaw += rhs.yaw; + self + } +} + +impl Sub<Vec3d> for Position { + type Output = Position; + + fn sub(mut self, rhs: Vec3d) -> Self::Output { + self.x -= rhs.x; + self.y -= rhs.y; + self.z -= rhs.z; + self + } +} + +impl Sub<Position> for Position { + type Output = Position; + + fn sub(mut self, rhs: Position) -> Self::Output { + self.x -= rhs.x; + self.y -= rhs.y; + self.z -= rhs.z; + self + } +} + +impl From<Position> for Vec3d { + fn from(pos: Position) -> Self { + vec3(pos.x, pos.y, pos.z) + } +} + +impl From<Vec3d> for Position { + fn from(vec: Vec3d) -> Self { + position!(vec.x, vec.y, vec.z) + } +} + +impl From<Position> for ChunkPosition { + fn from(pos: Position) -> Self { + Self { + x: (pos.x / 16.0).floor() as i32, + z: (pos.z / 16.0).floor() as i32, + } + } +} + +impl From<Position> for BlockPosition { + fn from(pos: Position) -> Self { + Self { + x: pos.x.floor() as i32, + y: pos.y.floor() as i32, + z: pos.z.floor() as i32, + } + } +} + +impl Display for Position { + fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { + write!(f, "({:.2}, {:.2}, {:.2})", self.x, self.y, self.z,) + } +} + +fn square(x: f64) -> f64 { + x * x +} + +/// Position of a chunk. +/// +/// Units are in chunks. 1 chunk equals 16 blocks. +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + Default, + Serialize, + Deserialize, + Zeroable, + Pod, +)] +#[repr(C)] +pub struct ChunkPosition { + pub x: i32, + pub z: i32, +} + +impl ChunkPosition { + pub const fn new(x: i32, z: i32) -> Self { + Self { x, z } + } + + /// Computes the Manhattan distance from this chunk to another. + pub fn manhattan_distance_to(self, other: ChunkPosition) -> i32 { + (self.x - other.x).abs() + (self.z - other.z).abs() + } + + /// Computes the squared Euclidean distance (in chunks) between `self` and `other`. + pub fn distance_squared_to(self, other: ChunkPosition) -> i32 { + (self.x - other.x).pow(2) + (self.z - other.z).pow(2) + } +} + +impl Display for ChunkPosition { + fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { + write!(f, "({}, {})", self.x, self.z) + } +} + +impl Add<ChunkPosition> for ChunkPosition { + type Output = ChunkPosition; + + fn add(self, rhs: ChunkPosition) -> Self::Output { + ChunkPosition { + x: self.x + rhs.x, + z: self.z + rhs.z, + } + } +} + +/// Position of a block. +/// +/// Y coordinate should be within +/// the interval [0, 256). +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + Default, + Serialize, + Deserialize, + Zeroable, + Pod, +)] +#[repr(C)] +pub struct BlockPosition { + pub x: i32, + pub y: i32, + pub z: i32, +} + +impl BlockPosition { + pub const fn new(x: i32, y: i32, z: i32) -> Self { + Self { x, y, z } + } + + /// Returns the Manhattan distance from this position to another. + pub fn manhattan_distance(self, other: BlockPosition) -> i32 { + (self.x - other.x).abs() + (self.y - other.y).abs() + (self.z - other.z).abs() + } + + /// Converts this `BlockPosition` to a `Position`. + pub fn position(self) -> Position { + self.into() + } + + /// Converts into a `ChunkPosition`. + pub fn chunk(self) -> ChunkPosition { + self.into() + } + + pub fn up(self) -> BlockPosition { + Self { + x: self.x, + y: self.y + 1, + z: self.z, + } + } + + pub fn down(self) -> BlockPosition { + Self { + x: self.x, + y: self.y - 1, + z: self.z, + } + } + + pub fn north(self) -> BlockPosition { + Self { + x: self.x, + y: self.y, + z: self.z - 1, + } + } + + pub fn south(self) -> BlockPosition { + Self { + x: self.x, + y: self.y, + z: self.z + 1, + } + } + + pub fn east(self) -> BlockPosition { + Self { + x: self.x + 1, + y: self.y, + z: self.z, + } + } + + pub fn west(self) -> BlockPosition { + Self { + x: self.x - 1, + y: self.y, + z: self.z, + } + } + + /// Returns `true` if the [`BlockPosition`] is valid. + /// + /// Minecraft defines a valid block position with the following limits: + /// - X (-33554432 to 33554431) + /// - Y (-2048 to 2047) + /// - Z (-33554432 to 33554431) + pub fn valid(self) -> bool { + (-33554432 <= self.x && self.x <= 33554431) + && (-2048 <= self.y && self.y <= 2047) + && (-33554432 <= self.z && self.z <= 33554431) + } +} + +impl Add<BlockPosition> for BlockPosition { + type Output = BlockPosition; + + fn add(mut self, rhs: BlockPosition) -> Self::Output { + self.x += rhs.x; + self.y += rhs.y; + self.z += rhs.z; + self + } +} + +impl Add<Vec3i> for BlockPosition { + type Output = Self; + + fn add(self, rhs: Vec3i) -> Self::Output { + self + BlockPosition::from(rhs) + } +} + +impl Sub<BlockPosition> for BlockPosition { + type Output = Self; + + fn sub(mut self, rhs: BlockPosition) -> Self::Output { + self.x -= rhs.x; + self.y -= rhs.y; + self.z -= rhs.z; + self + } +} + +impl Sub<Vec3i> for BlockPosition { + type Output = Self; + + fn sub(self, rhs: Vec3i) -> Self::Output { + self - BlockPosition::from(rhs) + } +} + +impl From<BlockPosition> for Vec3i { + fn from(pos: BlockPosition) -> Self { + vec3(pos.x, pos.y, pos.z) + } +} + +impl From<Vec3i> for BlockPosition { + fn from(vec: Vec3i) -> Self { + BlockPosition { + x: vec.x, + y: vec.y, + z: vec.z, + } + } +} + +impl From<BlockPosition> for Position { + fn from(pos: BlockPosition) -> Self { + position!(pos.x as f64 + 0.5, pos.y as f64 + 0.5, pos.z as f64 + 0.5) + } +} + +impl From<BlockPosition> for ChunkPosition { + fn from(pos: BlockPosition) -> Self { + Self { + x: pos.x.div_euclid(CHUNK_WIDTH as i32), + z: pos.z.div_euclid(CHUNK_WIDTH as i32), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum BlockFace { + Bottom, + Top, + North, + South, + West, + East, +} diff --git a/libcraft/generators/Cargo.toml b/libcraft/generators/Cargo.toml new file mode 100644 index 000000000..e657503f0 --- /dev/null +++ b/libcraft/generators/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "libcraft-generators" +version = "0.1.0" +authors = ["Kalle Kankaanpää"] +edition = "2018" + +[dependencies] +libcraft-blocks = { path = "../blocks" } + +anyhow = "1" +bincode = "1" +flate2 = "1" +serde_json = "1" +serde = "1" \ No newline at end of file diff --git a/libcraft/generators/README.md b/libcraft/generators/README.md new file mode 100644 index 000000000..1b8372f52 --- /dev/null +++ b/libcraft/generators/README.md @@ -0,0 +1,25 @@ +# libcraft-generators +This crate contains the generators for all of the autogenerated files in libcraft. + +Code generators are written in python and live in `python` directory. The crate also contains rust code that generates the `raw_block_states` lookup table. + +There are both shell and powershell scripts available to invoke the generators and generate all code. + +Running these scripts requires `rustfmt`, `cargo` and `python` 3.6 or greater. Note that code generation is not a mandatory part of the build process, so you only need to regenerate code after modifying a generator script. + +`libcraft-generators` currently provides the following generators: +* Generator for `Biome` enum in `libcraft-core` +* Generator for `BlockKind` enum in `libcraft-blocks` +* Generator for `EntityKind` enum in `libcraft-core` +* Generator for `Item` enum in `libcraft-items` +* Generator for `SimplifiedBlockKind` enum in `libcraft-blocks` +* Generator for `Particle` enum in `libcraft-core` +* Generator for the block state lookup table + +Data is sourced from multiple sources. +* [`PrimsarineJS/minecraft-data`](https://github.com/PrismarineJS/minecraft-data), which provides the majority +of data. These files live in the `minecraft-data` subdirectory, which is a Git submodule. Make sure +that Git submodules are up to date before running the scripts. +* `libcraft-data` directory contains custom data files, made especially for libcraft. +* `raw_block_states` generator uses block state data generated by the vanilla minecraft `server.jar` + * The block state data can be generated by downloading the `server.jar` and running `java -cp server.jar net.minecraft.data.Main --all` \ No newline at end of file diff --git a/libcraft/generators/generate.ps1 b/libcraft/generators/generate.ps1 new file mode 100644 index 000000000..0320e8c90 --- /dev/null +++ b/libcraft/generators/generate.ps1 @@ -0,0 +1,11 @@ +$generators = Get-ChildItem "python" -Filter *.py + +Write-Host "Running python generators" +foreach ($generator in $generators) { + python python/$generator +} + +Write-Host "Running rust generators" +cargo run --package libcraft-generators --bin libcraft-generators + +cargo fmt \ No newline at end of file diff --git a/libcraft/generators/generate.sh b/libcraft/generators/generate.sh new file mode 100755 index 000000000..df5eb10a2 --- /dev/null +++ b/libcraft/generators/generate.sh @@ -0,0 +1,12 @@ +generators=$(find python/ -type f -name "*.py") + +echo "Running python generators" +for generator in ${generators[@]}; do + echo "Running $generator" + python3 $generator +done + +echo "Running rust generators" +cargo run --package libcraft-generators --bin libcraft-generators + +cargo fmt \ No newline at end of file diff --git a/libcraft/generators/libcraft-data/entity_metadata.json b/libcraft/generators/libcraft-data/entity_metadata.json new file mode 100644 index 000000000..ec5943227 --- /dev/null +++ b/libcraft/generators/libcraft-data/entity_metadata.json @@ -0,0 +1,347 @@ +{ + "entity": { + "fields": { + "bitmask": { + "type": "u8", + "default": 0 + }, + "air_ticks": { + "type": "VarInt", + "default": 300 + }, + "custom_name": { + "type": "OptChat", + "default": "" + }, + "is_custom_name_visible": { + "type": "bool", + "default": false + }, + "is_silent": { + "type": "bool", + "default": false + }, + "is_gravity_disabled": { + "type": "bool", + "default": false + }, + "pose": { + "type": "Pose", + "default": "Pose::Standing" + } + } + }, + "thrown_egg": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "thrown_ender_pearl": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "thrown_experience_bottle": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "thrown_potion": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "snowball": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "eye_of_ender": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "falling_block": { + "extends": "entity", + "fields": { + "spawn_position": { + "type": "BlockPosition", + "default": "BlockPosition::new(0, 0, 0)" + } + } + }, + "area_effect_cloud": { + "extends": "enity", + "fields": { + "radius": { + "type": "f32", + "default": 0.5 + }, + "color": { + "type": "VarInt", + "default": 0 + }, + "is_single_point": { + "type": "bool", + "default": false + }, + "particle": { + "type": "Particle", + "default": "Particle::Effect" + } + } + }, + "fishing_hook": { + "extends": "entity", + "fields": { + "hooked_entity_id": { + "type": "VarInt", + "default": 0 + } + } + }, + "abstract_arrow": { + "extends": "entity", + "fields": { + "bitmask": { + "type": "u8", + "default": 0 + }, + "owner": { + "type": "OptUuid", + "default": "None" + }, + "piercing_level": { + "type": "u8", + "default": 0 + } + } + }, + "arrow": { + "extends": "abstract_arrow", + "fields": { + "color": { + "type": "VarInt", + "default": -1 + } + } + }, + "spectral_arrow": { + "extends": "abstract_arrow" + }, + "thrown_trident": { + "extends": "abstract_arrow", + "fields": { + "loyalty_level": { + "type": "VarInt", + "default": 0 + }, + "has_enchantment_glint": { + "type": "bool", + "default": false + } + } + }, + "boat": { + "extends": "entity", + "fields": { + "time_since_last_hit": { + "type": "VarInt", + "default": 0 + }, + "forward_direction": { + "type": "VarInt", + "default": 1 + }, + "damage_taken": { + "type": "f32", + "default": 0.0 + }, + "wood_kind": { + "type": "WoodKind", + "default": "WoodKind::Oak" + }, + "is_left_paddle_turning": { + "type": "bool", + "default": false + }, + "is_right_paddle_turning": { + "type": "bool", + "default": false + }, + "splash_timer": { + "type": "VarInt", + "default": 0 + } + } + }, + "end_crystal": { + "extends": "entity", + "fields": { + "beam_target": { + "type": "Option<BlockPosition>", + "default": "None" + }, + "show_bottom": { + "type": "bool", + "default": true + } + } + }, + "dragon_fireball": { + "extends": "entity" + }, + "small_fireball": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "fireball": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "wither_skull": { + "extends": "entity", + "fields": { + "is_invulnerable": { + "type": "bool", + "default": false + } + } + }, + "firework_rocket": { + "extends": "entity", + "fields": { + "firework": { + "type": "Slot", + "default": "None" + }, + "user_entity_id": { + "type": "Option<VarInt>", + "default": "None" + }, + "is_shot_at_angle": { + "type": "bool", + "default": false + } + } + }, + "item_frame": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + }, + "rotation": { + "type": "VarInt", + "default": 0 + } + } + }, + "item": { + "extends": "entity", + "fields": { + "item": { + "type": "Slot", + "default": "None" + } + } + }, + "living_entity": { + "extends": "entity", + "fields": { + "hand_states": { + "type": "u8", + "default": 0 + }, + "health": { + "type": "f32", + "default": 1.0 + }, + "potion_effect_color": { + "type": "VarInt", + "default": 0 + }, + "is_potion_effect_ambient": { + "type": "bool", + "default": false + }, + "arrows_stuck": { + "type": "VarInt", + "default": 0 + }, + "absorption_health": { + "type": "VarInt", + "default": 0 + }, + "bed_sleeping_in": { + "type": "Option<BlockPosition>", + "default": "None" + } + } + }, + "player": { + "extends": "living_entity", + "fields": { + "additional_hearts": { + "type": "f32", + "default": 0.0 + }, + "score": { + "type": "VarInt", + "default": 0 + }, + "displayed_skin_parts": { + "type": "u8", + "default": 0 + }, + "main_hand": { + "type": "Hand", + "default": "Hand::Right" + }, + "left_shoulder_parrot": { + "type": "Nbt", + "default": "Nbt::new(())" + }, + "right_shoulder_parrot": { + "type": "Nbt", + "default": "Nbt::new(())" + } + } + } +} + diff --git a/libcraft/generators/libcraft-data/inventory.json b/libcraft/generators/libcraft-data/inventory.json new file mode 100644 index 000000000..42b494720 --- /dev/null +++ b/libcraft/generators/libcraft-data/inventory.json @@ -0,0 +1,312 @@ +{ + "areas": [ + "storage", + "crafting_output", + "crafting_input", + "helmet", + "chestplate", + "leggings", + "boots", + "hotbar", + "offhand", + + "furnace_ingredient", + "furnace_fuel", + "furnace_output", + + "enchantment_item", + "enchantment_lapis", + + "brewing_bottle", + "brewing_ingredient", + "brewing_blaze_powder", + + "villager_input", + "villager_output", + + "beacon_payment", + + "anvil_input1", + "anvil_input2", + "anvil_output", + + "saddle", + "horse_armor", + "llama_carpet", + + "cartography_map", + "cartography_paper", + "cartography_output", + + "grindstone_input1", + "grindstone_input2", + "grindstone_output", + + "lectern_book", + + "loom_banner", + "loom_dye", + "loom_pattern", + "loom_output", + + "stonecutter_input", + "stonecutter_output" + ], + + "inventories": { + "player": { + "crafting_input": 4, + "crafting_output": 1, + "helmet": 1, + "chestplate": 1, + "leggings": 1, + "boots": 1, + "storage": 27, + "hotbar": 9, + "offhand": 1 + }, + "chest": { + "storage": 27 + }, + "crafting_table": { + "crafting_input": 9, + "crafting_output": 1 + }, + "furnace": { + "furnace_ingredient": 1, + "furnace_fuel": 1, + "furnace_output": 1 + } + }, + + "windows": { + "player": { + "inventories": ["player"], + "slots": { + "player:crafting_output": 1, + "player:crafting_input": 4, + + "player:helmet": 1, + "player:chestplate": 1, + "player:leggings": 1, + "player:boots": 1, + + "player:storage": 27, + "player:hotbar": 9, + "player:offhand": 1 + } + }, + + "generic_9x1": { + "inventories": ["block", "player"], + "slots": { + "block:storage": 9, + "player:storage": 27, + "player:hotbar": 9 + } + }, + "generic_9x2": { + "inventories": ["block", "player"], + "slots": { + "block:storage": 18, + "player:storage": 27, + "player:hotbar": 9 + } + }, + "generic_9x3": { + "inventories": ["block", "player"], + "slots": { + "block:storage": 27, + "player:storage": 27, + "player:hotbar": 9 + } + }, + "generic_9x4": { + "inventories": ["block", "player"], + "slots": { + "block:storage": 36, + "player:storage": 27, + "player:hotbar": 9 + } + }, + "generic_9x5": { + "inventories": ["block", "player"], + "slots": { + "block:storage": 45, + "player:storage": 27, + "player:hotbar": 9 + } + }, + "generic_9x6": { + "inventories": ["left_chest", "right_chest", "player"], + "slots": { + "left_chest:storage": 27, + "right_chest:storage": 27, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "generic_3x3": { + "inventories": ["block", "player"], + "slots": { + "block:storage": 9, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "crafting": { + "inventories": ["crafting_table", "player"], + "slots": { + "crafting_table:crafting_output": 1, + "crafting_table:crafting_input": 9, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "furnace": { + "inventories": ["furnace", "player"], + "slots": { + "furnace:furnace_ingredient": 1, + "furnace:furnace_fuel": 1, + "furnace:furnace_output": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + "blast_furnace": { + "inventories": ["blast_furnace", "player"], + "slots": { + "blast_furnace:furnace_ingredient": 1, + "blast_furnace:furnace_fuel": 1, + "blast_furnace:furnace_output": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + "smoker": { + "inventories": ["smoker", "player"], + "slots": { + "smoker:furnace_ingredient": 1, + "smoker:furnace_fuel": 1, + "smoker:furnace_output": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "enchantment": { + "inventories": ["enchantment_table", "player"], + "slots": { + "enchantment_table:enchantment_item": 1, + "enchantment_table:enchantment_lapis": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "brewing_stand": { + "inventories": ["brewing_stand", "player"], + "slots": { + "brewing_stand:brewing_bottle": 3, + "brewing_stand:brewing_ingredient": 1, + "brewing_stand:brewing_blaze_powder": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "beacon": { + "inventories": ["beacon", "player"], + "slots": { + "beacon:beacon_payment": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "anvil": { + "inventories": ["anvil", "player"], + "slots": { + "anvil:anvil_input1": 1, + "anvil:anvil_input2": 1, + "anvil:anvil_output": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "hopper": { + "inventories": ["hopper", "player"], + "slots": { + "hopper:storage": 4, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "shulker_box": { + "inventories": ["shulker_box", "player"], + "slots": { + "shulker_box:storage": 27, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "cartography": { + "inventories": ["cartography_table", "player"], + "slots": { + "cartography_table:cartography_map": 1, + "cartography_table:cartography_paper": 1, + "cartography_table:cartography_output": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "grindstone": { + "inventories": ["grindstone", "player"], + "slots": { + "grindstone:grindstone_input1": 1, + "grindstone:grindstone_input2": 1, + "grindstone:grindstone_output": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "lectern": { + "inventories": ["lectern", "player"], + "slots": { + "lectern:lectern_book": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "loom": { + "inventories": ["loom", "player"], + "slots": { + "loom:loom_banner": 1, + "loom:loom_dye": 1, + "loom:loom_pattern": 1, + "loom:loom_output": 1, + "player:storage": 27, + "player:hotbar": 9 + } + }, + + "stonecutter": { + "inventories": ["stonecutter", "player"], + "slots": { + "stonecutter:stonecutter_input": 1, + "stonecutter:stonecutter_output": 1, + "player:storage": 27, + "player:hotbar": 9 + } + } + } +} \ No newline at end of file diff --git a/libcraft/generators/libcraft-data/simplified_block.json b/libcraft/generators/libcraft-data/simplified_block.json new file mode 100644 index 000000000..79d97f792 --- /dev/null +++ b/libcraft/generators/libcraft-data/simplified_block.json @@ -0,0 +1,38 @@ +{ + "regexes": { + "air": "^.*air$", + "planks": "^.+_planks$", + "sapling": "^(\\w+|dark_oak)_sapling$", + "log": "^.+_(log|wood)$", + "leaves": ".+_leaves$", + "bed": "^.+_bed$", + "wool": "^.+_wool$", + "flower": "^(allium|poppy|dandelion|\\w+_(orchid|bluet|tulip|daisy))$", + "wooden_pressure_plate": "^(oak|spruce|birch|jungle|acacia|dark_oak)_pressure_plate$", + "stained_glass": "^.+_stained_glass$", + "wooden_trapdoor": "^(oak|spruce|birch|jungle|acacia|dark_oak)_trapdoor$", + "wooden_button": "^(oak|spruce|birch|jungle|acacia|dark_oak)_button$", + "anvil": "^(\\w+_)?anvil$", + "glazed_teracotta": "^.+_glazed_terracotta$", + "teracotta": "^.*terracotta$", + "stained_glass_pane": "^.+_stained_glass_pane$", + "carpet": "^.+_carpet$", + "wall_banner": "^.+_wall_banner$", + "banner": "^.+_banner$", + "slab": "^.+_slab$", + "stairs": "^.+_stairs$", + "fence_gate": "^.+_fence_gate$", + "fence": "^.+_fence$", + "wooden_door": "^(oak|spruce|birch|jungle|acacia|dark_oak)_door$", + "shulker_box": "^.*shulker_box$", + "concrete": "^.+_concrete$", + "concrete_powder": "^.+_concrete_powder$", + "coral": "^.+_coral$", + "coral_block": "^.+_coral_block$", + "coral_fan": "^.+_coral_fan$", + "coral_wall_fan": "^.+_coral_wall_fan$", + "mushroom": "^\\w+_mushroom$", + "wall_sign": "^.+_wall_sign", + "sign": "^.+_sign" + } +} diff --git a/libcraft/generators/python/.pep8 b/libcraft/generators/python/.pep8 new file mode 100644 index 000000000..cdedc3786 --- /dev/null +++ b/libcraft/generators/python/.pep8 @@ -0,0 +1,2 @@ +[pycodestyle] +max_line_length = 120 \ No newline at end of file diff --git a/libcraft/generators/python/biome.py b/libcraft/generators/python/biome.py new file mode 100644 index 000000000..6d4ae6884 --- /dev/null +++ b/libcraft/generators/python/biome.py @@ -0,0 +1,29 @@ +"""Generation of the Biome enum. Uses minecraft-data/biomes.json.""" +from common import load_minecraft_json, camel_case, generate_enum, generate_enum_property, output + +variants = [] +ids = {} +names = {} +display_names = {} +rainfalls = {} +temperatures = {} + +for biome in load_minecraft_json("biomes.json"): + variant = camel_case(biome['name']) + variants.append(variant) + ids[variant] = biome['id'] + names[variant] = biome['name'] + display_names[variant] = biome['displayName'] + rainfalls[variant] = biome['rainfall'] + temperatures[variant] = biome['temperature'] + + +output_data = generate_enum("Biome", variants) +output_data += generate_enum_property("Biome", "id", "u32", ids, True) +output_data += generate_enum_property("Biome", "name", "&str", names, True, "&'static str") +output_data += generate_enum_property("Biome", "display_name", "&str", display_names, True, "&'static str") +output_data += generate_enum_property("Biome", "rainfall", "f32", rainfalls) +output_data += generate_enum_property("Biome", "temperature", "f32", temperatures) + +output("core/src/biome.rs", output_data) + diff --git a/libcraft/generators/python/block.py b/libcraft/generators/python/block.py new file mode 100644 index 000000000..042ea03f7 --- /dev/null +++ b/libcraft/generators/python/block.py @@ -0,0 +1,96 @@ +from common import load_minecraft_json, camel_case, generate_enum, generate_enum_property, output + + +# build item ID => item kind index +item_kinds_by_id = {} +for item in load_minecraft_json("items.json"): + item_kinds_by_id[item['id']] = camel_case(item['name']) + +# Build material name => dig multipliers index +material_dig_multipliers = {} +for name, material in load_minecraft_json("materials.json").items(): + dig_multipliers = {} + for item_id, multiplier in material.items(): + dig_multipliers[item_kinds_by_id[int(item_id)]] = float(multiplier) + material_dig_multipliers[name] = dig_multipliers + +# Build material dig multipliers constants +material_constants = "" +material_constant_refs = {} +for name, dig_multipliers in material_dig_multipliers.items(): + dm = "" + for item, multiplier in dig_multipliers.items(): + dm += f"(libcraft_items::Item::{item}, {multiplier}_f32)," + constant = f"DIG_MULTIPLIERS_{name}" + material_constants += f"#[allow(dead_code, non_upper_case_globals)] const {constant}: &[(libcraft_items::Item, f32)] = &[{dm}];" + material_constant_refs[name] = constant + +blocks = [] +ids = {} +names = {} +display_names = {} +hardnesses = {} +diggables = {} +harvest_tools = {} +transparents = {} +light_emissions = {} +light_filters = {} +dig_multipliers = {} +solids = {} + +for block in load_minecraft_json("blocks.json"): + variant = camel_case(block['name']) + blocks.append(variant) + ids[variant] = block['id'] + names[variant] = block['name'] + display_names[variant] = block['displayName'] + hardnesses[variant] = block['hardness'] + if hardnesses[variant] is None: + hardnesses[variant] = 0 + diggables[variant] = block['diggable'] + transparents[variant] = block['transparent'] + light_emissions[variant] = block['emitLight'] + light_filters[variant] = block['filterLight'] + + solids[variant] = block['boundingBox'] == 'block' + + # Dig multipliers + material = block.get('material') + if material_constant_refs.get(material) is not None: + constant = material_constant_refs[material] + dig_multipliers[variant] = f"{constant}" + else: + dig_multipliers[variant] = "&[]" + + # Harvest tools + ht = "" + for tool_id in block.get('harvestTools', {}): + kind = item_kinds_by_id[int(tool_id)] + ht += f"libcraft_items::Item::{kind}," + + if len(ht) == 0: + harvest_tools[variant] = 'None' + else: + harvest_tools[variant] = f""" + const TOOLS: &[libcraft_items::Item] = &[{ht}]; + Some(TOOLS) + """ + +output_data = "#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, serde::Serialize, serde::Deserialize)]" + \ + generate_enum("BlockKind", blocks) +output_data += generate_enum_property("BlockKind", "id", "u32", ids, True) +output_data += generate_enum_property("BlockKind", "name", "&str", names, True, "&'static str") +output_data += generate_enum_property("BlockKind", "display_name", "&str", display_names, True, "&'static str") +output_data += generate_enum_property("BlockKind", "hardness", "f32", hardnesses) +output_data += generate_enum_property("BlockKind", "diggable", "bool", diggables) +output_data += generate_enum_property("BlockKind", "transparent", "bool", transparents) +output_data += generate_enum_property("BlockKind", "light_emission", "u8", light_emissions) +output_data += generate_enum_property("BlockKind", "light_filter", "u8", light_filters) +output_data += generate_enum_property("BlockKind", "solid", "bool", solids) +output_data += material_constants +output_data += generate_enum_property("BlockKind", "dig_multipliers", + "&'static [(libcraft_items::Item, f32)]", dig_multipliers) +output_data += generate_enum_property("BlockKind", "harvest_tools", + "Option<&'static [libcraft_items::Item]>", harvest_tools) + +output("blocks/src/block.rs", output_data) diff --git a/libcraft/generators/python/common.py b/libcraft/generators/python/common.py new file mode 100644 index 000000000..0a941583a --- /dev/null +++ b/libcraft/generators/python/common.py @@ -0,0 +1,164 @@ +"""Common code shared by most code generators.""" + +from subprocess import run +from json import load +from re import split +from pathlib import Path + +from typing import List + +LIBCRAFT_ROOT = Path(__file__).parents[1] / ".." +PRISMARINEJS_BASE_PATH = Path(__file__).parents[1] / ".." / ".." / "minecraft-data" / "data" / "pc" +LIBCRAFT_DATA_BASE_PATH = Path(__file__).parents[1] / "libcraft-data" + + +def rustfmt(file_path): + """ Runs rustfmt on a file""" + run(["rustfmt", file_path]) + + +def load_minecraft_json(name: str, version="1.16.1") -> dict: + """ + Loads a JSON file from the minecraft-data sub repository. + + Parameters: + name (str): Name of the file to load + version (str): String matching the targe minecraft version, defaults to 1.16.1 + + Returns: + A dict containing JSON content + """ + file = open(PRISMARINEJS_BASE_PATH / version / name) + return load(file) + + +def load_feather_json(name: str) -> dict: + """ + Loads a JSON file from the feather directory + + Parameters: + name (str): Name of the file to load + + Returns: + A dict containing JSON contents + """ + file = open(LIBCRAFT_DATA_BASE_PATH / name) + return load(file) + + +def output(path: str, content: str): + """ + Writes the contents to a file in provided path, then runs rustfmt. + + Parameters: + path: Path to destination file, relative to libcraft root + content: Contents to be written in the file + """ + + path = LIBCRAFT_ROOT / path + if not path.parent.exists(): + return print(f"Couldn't write to file.\nPath {path.parent} does not exist") + f = open(path, "w") + f.write("// This file is @generated. Please do not edit.\n") + f.write(content) + f.close() + print(f"Generated {path.name}") + + rustfmt(path) + + +def generate_enum_property( + enum: str, # Identifier of the enum (e.g. "Biome") + property_name: str, # Name of the property + type_: str, # The property type (e.g. u32, &str + mapping: dict, # Dictionary mapping from enum variant name => property value expression + # Whether to generate the reverse mapping (property value => Some(Self)) + reverse=False, + return_type=None, + # Property type that should be returned. This is used when the type has a lifetime, such as &'static str + # Whether to bind enum fields using Enum::Variant { .. } + needs_bindings=False, +) -> str: + """ + Generates lookup functions for an enum. + + Generates two function for an enum, one which maps the enum value to some + property value and one which does the reverse (returning an Option) + """ + if return_type is None: + return_type = type_ + + self_to_prop = "" + prop_to_self = "" + + # Add quotes to strings + if type_ == "&str": + for key, property_value in mapping.items(): + mapping[key] = f'"{property_value}"' + + # If floats are needed, convert integers to floats + if type_ == "f32" or type_ == "f64": + for key, property_value in mapping.items(): + mapping[key] = f'{property_value} as {type_}' + + # Bools are lowercase in Rust + if type_ == "bool": + for key, property_value in mapping.items(): + mapping[key] = str(property_value).lower() + + for variant, property_value in mapping.items(): + fields = "" + if needs_bindings: + fields = "{ .. }" + self_to_prop += f"{enum}::{variant} {fields} => {{ {property_value} }}," + prop_to_self += f"{property_value} => Some({enum}::{variant})," + + result = f""" + #[allow(warnings)] + #[allow(clippy::all)] + impl {enum} {{ + /// Returns the `{property_name}` property of this `{enum}`. + pub fn {property_name}(&self) -> {return_type} {{ + match self {{ + {self_to_prop} + }} + }} + """ + + if reverse: + result += f""" + /// Gets a `{enum}` by its `{property_name}`. + pub fn from_{property_name}({property_name}: {type_}) -> Option<Self> {{ + match {property_name} {{ + {prop_to_self} + _ => None, + }} + }} + """ + + # closing brace + result += "}" + + return result + + +def generate_enum(name: str, variants: List[str], derives: List[str] = [], prelude: str = "") -> str: + """Generates an enum definition with the provided variants and extra derives.""" + body = ','.join(variants) + ',' + extra_derives = "" if len(derives) == 0 else ',' + ','.join(derives) + output = f""" + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord{extra_derives})]""" + if len(prelude) != 0: + output += f""" + {prelude}""" + output += f""" + pub enum {name} {{ + {body} + }} + """ + return output + + +def camel_case(string: str) -> str: + """Converts a string to UpperCamelCase.""" + return ''.join(a.capitalize() for a in split('([^a-zA-Z0-9])', string) if a.isalnum()) diff --git a/libcraft/generators/python/entity.py b/libcraft/generators/python/entity.py new file mode 100644 index 000000000..e30c8b4e4 --- /dev/null +++ b/libcraft/generators/python/entity.py @@ -0,0 +1,29 @@ +from common import load_minecraft_json, camel_case, generate_enum, generate_enum_property, output + +entities = [] +ids = {} +internal_ids = {} +names = {} +display_names = {} +bboxes = {} + +for entity in load_minecraft_json("entities.json","1.16.2"): + variant = camel_case(entity['name']) + entities.append(variant) + ids[variant] = entity['id'] + internal_ids[variant] = entity['internalId'] + names[variant] = entity['name'] + display_names[variant] = entity['displayName'] + + width = entity['width'] + height = entity['height'] + bboxes[variant] = f"vek::Aabb {{ min: vek::Vec3::zero(), max: vek::Vec3::new({width} as f64, {height} as f64, {width} as f64), }}" + +output_data = generate_enum("EntityKind", entities) +output_data += generate_enum_property("EntityKind", "id", "u32", ids, True) +output_data += generate_enum_property("EntityKind", "internal_id", "u32", internal_ids, True) +output_data += generate_enum_property("EntityKind", "name", "&str", names, True, "&'static str") +output_data += generate_enum_property("EntityKind", "display_name", "&str", display_names, True, "&'static str") +output_data += generate_enum_property("EntityKind", "bounding_box", "vek::Aabb<f64>", bboxes) + +output("core/src/entity.rs", output_data) diff --git a/libcraft/generators/python/inventory.py b/libcraft/generators/python/inventory.py new file mode 100644 index 000000000..e7f3e4712 --- /dev/null +++ b/libcraft/generators/python/inventory.py @@ -0,0 +1,157 @@ +from pathlib import Path +import common +import collections + +data = common.load_feather_json("inventory.json") + +# Areas +areas = [] +for area in data['areas']: + areas.append(common.camel_case(area)) + +# Windows +windows = [] +names = {} +inventories = {} +area_offsets = collections.OrderedDict() + +for name, window in data['windows'].items(): + variant = common.camel_case(name) + windows.append(variant) + + names[variant] = name + inventories[variant] = window['inventories'] + + ao = collections.OrderedDict() + slot_counter = 0 + for inventory_and_area, number_of_slots in window['slots'].items(): + parts = inventory_and_area.split(":") + inventory = parts[0] + area_in_inventory = parts[1] + ao[(inventory, area_in_inventory)] = (slot_counter, number_of_slots) + slot_counter += number_of_slots + area_offsets[variant] = ao + +output = common.generate_enum("Area", areas) + +window = "#[derive(Debug, Clone)] pub enum Window {" +index_to_slot = "#[allow(unused_comparisons)] pub fn index_to_slot(&self, index: usize) -> Option<(&crate::Inventory, Area, usize)> { match self {" +slot_to_index = "pub fn slot_to_index(&self, inventory: &crate::Inventory, area: Area, slot: usize) -> Option<usize> { match self {" + +for variant in windows: + window += f"{variant} {{" + for inventory in inventories[variant]: + window += f"{inventory}: crate::Inventory," + window += "}," + + match_pattern = f"Window::{variant} {{" + for inventory in inventories[variant]: + match_pattern += f"{inventory}," + match_pattern += "}" + + index_to_slot += f"{match_pattern} => {{" + first = True + for (inventory, area_in_inventory), (slot_offset, number_of_slots) in area_offsets[variant].items(): + if not first: + index_to_slot += "else" + first = False + + area_in_inventory = common.camel_case(area_in_inventory) + max_slot = slot_offset + number_of_slots + slot_offset_operation = "" + if slot_offset != 0: + slot_offset_operation += f" - {slot_offset}" + index_to_slot += f""" + if ({slot_offset}..{max_slot}).contains(&index) {{ + let area = Area::{area_in_inventory}; + let slot = index{slot_offset_operation}; + Some(({inventory}, area, slot)) + }} + """ + index_to_slot += "else { None } }," + + slot_to_index += f"{match_pattern} => {{" + first = True + for (inventory, area_in_inventory), (slot_offset, number_of_slots) in area_offsets[variant].items(): + if not first: + slot_to_index += "else " + first = False + + area_in_inventory = common.camel_case(area_in_inventory) + if slot_offset == 0: + slot_to_index += f"if area == Area::{area_in_inventory} && {inventory}.ptr_eq(inventory) {{ Some(slot) }}" + else: + slot_to_index += f"if area == Area::{area_in_inventory} && {inventory}.ptr_eq(inventory) {{ Some(slot + {slot_offset}) }}" + + slot_to_index += "else { None } }," + + +window += "}" +index_to_slot += "} }" +slot_to_index += "} }" + +output += window +output += f"impl Window {{ {index_to_slot} {slot_to_index} }}" +output += common.generate_enum_property("Window", "name", "&str", names, False, "&'static str", True) + +# Inventories +inventories = [] +for name, areas in data['inventories'].items(): + variant = common.camel_case(name) + inv = { + 'name': name, + 'variant': variant, + 'areas': areas, + } + inventories.append(inv) + + +output += "#[derive(Debug, Clone)] pub enum InventoryBacking<T> {" +for inventory in inventories: + variant = inventory['variant'] + output += f"{variant} {{" + for area_name, area_size in inventory['areas'].items(): + output += f"{area_name}: [T; {area_size}]," + output += "}," +output += "}" + +get_area_fn = "pub fn area_slice(&self, area: Area) -> Option<&[T]> { match self {" +get_areas_fn = "pub fn areas(&self) -> &'static [Area] { match self {" +constructor_fns = "" +inventory_constructor_fns = "" + +for inventory in inventories: + name = inventory['name'] + variant = inventory['variant'] + areas = inventory['areas'] + match_arm = f"InventoryBacking::{variant} {{" + for area in areas: + match_arm += f"{area}," + match_arm += "}" + + get_area_fn += f"{match_arm} => match area {{" + for area in areas: + area_variant = common.camel_case(area) + get_area_fn += f"Area::{area_variant} => Some({area}.as_ref())," + get_area_fn += "_ => None }," + + get_areas_fn += f"\nInventoryBacking::{variant} {{ .. }} => {{static AREAS: [Area; {len(areas)}] = [" + for area in areas: + get_areas_fn += f"Area::{common.camel_case(area)}," + get_areas_fn += f"];\n &AREAS }}," + + constructor_fn = f"pub fn {name}() -> Self where T: Default {{ InventoryBacking::{variant} {{" + for area in areas: + constructor_fn += f"{area}: Default::default()," + + constructor_fn += "} }\n" + constructor_fns += constructor_fn + + inventory_constructor_fns += f"pub fn {name}() -> Self {{ Self {{ backing: std::sync::Arc::new(InventoryBacking::{name}()) }} }}" + +get_area_fn += "} }" +get_areas_fn += "} }" +output += f"impl <T> InventoryBacking<T> {{ {get_area_fn} {get_areas_fn} {constructor_fns} }}" +output += f"impl crate::Inventory {{ {inventory_constructor_fns} }}" + +common.output("inventory/src/inventory.rs", output) diff --git a/libcraft/generators/python/item.py b/libcraft/generators/python/item.py new file mode 100644 index 000000000..78d7ff2ab --- /dev/null +++ b/libcraft/generators/python/item.py @@ -0,0 +1,74 @@ +from common import load_minecraft_json, camel_case, generate_enum, generate_enum_property, output + +items = [] +ids = {} +names = {} +display_names = {} +stack_sizes = {} +durabilities = {} + +for item in load_minecraft_json("items.json", "1.16.2"): + variant = camel_case(item['name']) + items.append(variant) + ids[variant] = item['id'] + names[variant] = item['name'] + display_names[variant] = item['displayName'] + stack_sizes[variant] = item['stackSize'] + + durability = item.get('durability') + if durability is None: + durabilities[variant] = "None" + else: + durabilities[variant] = f"Some({durability})" + +output_data = "use serde::{Serialize, Deserialize};" + +output_data += generate_enum("Item", items, derives=["Serialize", "Deserialize"], + prelude="#[serde(try_from = \"String\", into = \"&'static str\")]") +output_data += generate_enum_property("Item", "id", "u32", ids, True) +output_data += generate_enum_property("Item", "name", "&str", names, True, "&'static str") +output_data += generate_enum_property("Item", "display_name", "&str", display_names, False, "&'static str") +output_data += generate_enum_property("Item", "stack_size", "u32", stack_sizes) +output_data += generate_enum_property("Item", "durability", "Option<u32>", durabilities) + +output_data += f""" + use std::convert::TryFrom; + + impl TryFrom<String> for Item {{ + type Error = &'static str; + + fn try_from(value: String) -> Result<Self, Self::Error> {{ + if let Some(item) = Item::from_name(value.as_str()) {{ + Ok(item) + }} else {{ + Err("Unknown item name.") + }} + }} + }} +""" + +output_data += f""" + impl From<Item> for &'static str {{ + fn from(i: Item) -> Self {{ + i.name() + }} + }} +""" + +output_data += f""" + use std::str::FromStr; + + impl FromStr for Item {{ + type Err = &'static str; + + fn from_str(s: &str) -> Result<Self, Self::Err> {{ + if let Some(item) = Item::from_name(s) {{ + Ok(item) + }} else {{ + Err("Unknown item name.") + }} + }} + }} +""" + +output("items/src/item.rs", output_data) diff --git a/libcraft/generators/python/particle.py b/libcraft/generators/python/particle.py new file mode 100644 index 000000000..2bb3dd775 --- /dev/null +++ b/libcraft/generators/python/particle.py @@ -0,0 +1,51 @@ +# This file cannot be generated anymore, since the current particle.rs in libcraft/crates/particles has a +# is an enum that has the particle data built into it. + +# I made an attempt on incorporating this into the generator, but ultimately gave up since it's not future-proof +# at all + +from common import load_minecraft_json, output, generate_enum, generate_enum_property, camel_case + +def main (): + particles = [] + ids = {} + names = {} + + types = load_minecraft_json("protocol.json", "1.16")["types"]["particleData"][1]['fields'] + print(types) + + for particle in load_minecraft_json("particles.json", "1.16"): + variant = camel_case(particle['name']) + id = str(particle['id']) + if id in types.keys(): + data = types[id] + print(data[1]) + particles.append(generate_particle_data(variant, data[1])) + else: + particles.append(variant) + ids[variant] = id + names[variant] = particle['name'] + + output_data = generate_enum("Particle", particles) + output_data += generate_enum_property("Particle", "id", "u32", ids, True) + output_data += generate_enum_property("Particle", "name", "&str", names, True, "&'static str") + output("core/src/particle.rs", output_data) + +def generate_particle_data (name: str, data: dict): + + if (len(data) == 1): + feather_type = "f32" + if data[0]['name'] == 'blockState': + feather_type = "BlockId" + return name + f"({feather_type})" + else: + enum_item = f"{name}{{" + for i in range(0, len(data)): + enum_item += f"{data[i]['name']}:{data[i]['type']}" + if i < len(data): + enum_item += "," + + return enum_item + "}" + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/libcraft/generators/python/simplified_block.py b/libcraft/generators/python/simplified_block.py new file mode 100644 index 000000000..170db4e46 --- /dev/null +++ b/libcraft/generators/python/simplified_block.py @@ -0,0 +1,35 @@ +from common import load_minecraft_json, load_feather_json, camel_case, generate_enum, generate_enum_property, output +from re import compile + +blocks = load_minecraft_json("blocks.json") +simplified_block = load_feather_json("simplified_block.json") + +regexes = {} +for name, regex in simplified_block['regexes'].items(): + regexes[name] = compile(regex) + +variants = [] +mapping = {} +for name in regexes: + variants.append(camel_case(name)) + +for block in blocks: + name = block['name'] + block_variant = camel_case(name) + + # Detect which SimplifiedBlockKind matches this block. + found = False + for simplified, regex in regexes.items(): + if regex.match(name) is not None: + mapping[block_variant] = "SimplifiedBlockKind::" + camel_case(simplified) + found = True + break + + if not found: + # Default to block variant + variants.append(block_variant) + mapping[block_variant] = "SimplifiedBlockKind::" + block_variant + +output_data = "use crate::BlockKind;" + generate_enum("SimplifiedBlockKind", variants) +output_data += generate_enum_property("BlockKind", "simplified_kind", "SimplifiedBlockKind", mapping) +output("blocks/src/simplified_block.rs", output_data) diff --git a/libcraft/generators/src/common.rs b/libcraft/generators/src/common.rs new file mode 100644 index 000000000..56c98fa07 --- /dev/null +++ b/libcraft/generators/src/common.rs @@ -0,0 +1,37 @@ +use std::fs::{read_to_string, write}; +use std::io::Write; + +use libcraft_blocks::data::BlockReport; +use libcraft_blocks::BlockKind; + +use anyhow::{anyhow, Context, Result}; +use flate2::Compression; +use serde::Serialize; + +pub fn load_block_report(path: &str) -> Result<BlockReport> { + println!("Reading BlockReport from blocks.json"); + let block_report = read_to_string(path).context("blocks report `blocks.json` not found")?; + serde_json::from_str::<BlockReport>(&block_report).map_err(|err| err.into()) +} + +/// Writes data to file provided in compressed binary format (.bc.gz) +pub fn compress_and_write<T: Serialize>(data: Vec<T>, path: &str) -> Result<()> { + println!("Writing {} entries to {}", data.len(), path); + let encoded = bincode::serialize(&data)?; + + let mut writer = flate2::write::GzEncoder::new(Vec::new(), Compression::best()); + writer.write_all(&encoded)?; + write( + [env!("CARGO_MANIFEST_DIR"), "/../../", path].concat(), + &writer.finish()?, + )?; + + Ok(()) +} + +pub fn state_name_to_block_kind(name: &str) -> Result<BlockKind> { + name.split(':') + .last() + .and_then(BlockKind::from_name) + .ok_or_else(|| anyhow!("Could not convert state name to BlockKind")) +} diff --git a/libcraft/generators/src/generators.rs b/libcraft/generators/src/generators.rs new file mode 100644 index 000000000..15c7abc22 --- /dev/null +++ b/libcraft/generators/src/generators.rs @@ -0,0 +1,30 @@ +use crate::common::{compress_and_write, state_name_to_block_kind}; +use libcraft_blocks::data::BlockReport; + +pub fn generate_block_states(block_report: &BlockReport, path: &str) -> anyhow::Result<()> { + let mut raw_block_states = Vec::new(); + + for (name, entry) in &block_report.blocks { + let kind = state_name_to_block_kind(name)?; + for state in &entry.states { + raw_block_states.push(state.to_raw_state(kind)); + } + } + + raw_block_states.sort_unstable_by_key(|state| state.id); + + compress_and_write(raw_block_states, path) +} + +pub fn generate_block_properties(block_report: &BlockReport, path: &str) -> anyhow::Result<()> { + let mut raw_block_properties = Vec::new(); + + for (name, entry) in &block_report.blocks { + let kind = state_name_to_block_kind(name)?; + raw_block_properties.push(entry.to_raw_properties(kind)) + } + + raw_block_properties.sort_unstable_by_key(|properties| properties.kind); + + compress_and_write(raw_block_properties, path) +} diff --git a/libcraft/generators/src/main.rs b/libcraft/generators/src/main.rs new file mode 100644 index 000000000..8dc3c9373 --- /dev/null +++ b/libcraft/generators/src/main.rs @@ -0,0 +1,18 @@ +mod common; +mod generators; + +use common::load_block_report; +use generators::{generate_block_properties, generate_block_states}; + +fn main() -> anyhow::Result<()> { + let block_report = load_block_report("blocks.json")?; + println!("Generating raw block states"); + generate_block_states(&block_report, "crates/blocks/assets/raw_block_states.bc.gz")?; + println!("Generating raw block properties"); + generate_block_properties( + &block_report, + "crates/blocks/assets/raw_block_properties.bc.gz", + )?; + + Ok(()) +} diff --git a/libcraft/inventory/Cargo.toml b/libcraft/inventory/Cargo.toml new file mode 100644 index 000000000..93fc27208 --- /dev/null +++ b/libcraft/inventory/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "libcraft-inventory" +version = "0.1.0" +authors = ["Tracreed <davidalasow@gmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libcraft-items = { path = "../items" } +parking_lot = "0.11" diff --git a/libcraft/inventory/src/inventory.rs b/libcraft/inventory/src/inventory.rs new file mode 100644 index 000000000..975d6030a --- /dev/null +++ b/libcraft/inventory/src/inventory.rs @@ -0,0 +1,1218 @@ +// This file is @generated. Please do not edit. + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Area { + Storage, + CraftingOutput, + CraftingInput, + Helmet, + Chestplate, + Leggings, + Boots, + Hotbar, + Offhand, + FurnaceIngredient, + FurnaceFuel, + FurnaceOutput, + EnchantmentItem, + EnchantmentLapis, + BrewingBottle, + BrewingIngredient, + BrewingBlazePowder, + VillagerInput, + VillagerOutput, + BeaconPayment, + AnvilInput1, + AnvilInput2, + AnvilOutput, + Saddle, + HorseArmor, + LlamaCarpet, + CartographyMap, + CartographyPaper, + CartographyOutput, + GrindstoneInput1, + GrindstoneInput2, + GrindstoneOutput, + LecternBook, + LoomBanner, + LoomDye, + LoomPattern, + LoomOutput, + StonecutterInput, + StonecutterOutput, +} +#[derive(Debug, Clone)] +pub enum Window { + Player { + player: crate::Inventory, + }, + Generic9x1 { + block: crate::Inventory, + player: crate::Inventory, + }, + Generic9x2 { + block: crate::Inventory, + player: crate::Inventory, + }, + Generic9x3 { + block: crate::Inventory, + player: crate::Inventory, + }, + Generic9x4 { + block: crate::Inventory, + player: crate::Inventory, + }, + Generic9x5 { + block: crate::Inventory, + player: crate::Inventory, + }, + Generic9x6 { + left_chest: crate::Inventory, + right_chest: crate::Inventory, + player: crate::Inventory, + }, + Generic3x3 { + block: crate::Inventory, + player: crate::Inventory, + }, + Crafting { + crafting_table: crate::Inventory, + player: crate::Inventory, + }, + Furnace { + furnace: crate::Inventory, + player: crate::Inventory, + }, + BlastFurnace { + blast_furnace: crate::Inventory, + player: crate::Inventory, + }, + Smoker { + smoker: crate::Inventory, + player: crate::Inventory, + }, + Enchantment { + enchantment_table: crate::Inventory, + player: crate::Inventory, + }, + BrewingStand { + brewing_stand: crate::Inventory, + player: crate::Inventory, + }, + Beacon { + beacon: crate::Inventory, + player: crate::Inventory, + }, + Anvil { + anvil: crate::Inventory, + player: crate::Inventory, + }, + Hopper { + hopper: crate::Inventory, + player: crate::Inventory, + }, + ShulkerBox { + shulker_box: crate::Inventory, + player: crate::Inventory, + }, + Cartography { + cartography_table: crate::Inventory, + player: crate::Inventory, + }, + Grindstone { + grindstone: crate::Inventory, + player: crate::Inventory, + }, + Lectern { + lectern: crate::Inventory, + player: crate::Inventory, + }, + Loom { + loom: crate::Inventory, + player: crate::Inventory, + }, + Stonecutter { + stonecutter: crate::Inventory, + player: crate::Inventory, + }, +} +impl Window { + #[allow(unused_comparisons)] + pub fn index_to_slot(&self, index: usize) -> Option<(&crate::Inventory, Area, usize)> { + match self { + Window::Player { player } => { + if (0..1).contains(&index) { + let area = Area::CraftingOutput; + let slot = index; + Some((player, area, slot)) + } else if (1..5).contains(&index) { + let area = Area::CraftingInput; + let slot = index - 1; + Some((player, area, slot)) + } else if (5..6).contains(&index) { + let area = Area::Helmet; + let slot = index - 5; + Some((player, area, slot)) + } else if (6..7).contains(&index) { + let area = Area::Chestplate; + let slot = index - 6; + Some((player, area, slot)) + } else if (7..8).contains(&index) { + let area = Area::Leggings; + let slot = index - 7; + Some((player, area, slot)) + } else if (8..9).contains(&index) { + let area = Area::Boots; + let slot = index - 8; + Some((player, area, slot)) + } else if (9..36).contains(&index) { + let area = Area::Storage; + let slot = index - 9; + Some((player, area, slot)) + } else if (36..45).contains(&index) { + let area = Area::Hotbar; + let slot = index - 36; + Some((player, area, slot)) + } else if (45..46).contains(&index) { + let area = Area::Offhand; + let slot = index - 45; + Some((player, area, slot)) + } else { + None + } + } + Window::Generic9x1 { block, player } => { + if (0..9).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((block, area, slot)) + } else if (9..36).contains(&index) { + let area = Area::Storage; + let slot = index - 9; + Some((player, area, slot)) + } else if (36..45).contains(&index) { + let area = Area::Hotbar; + let slot = index - 36; + Some((player, area, slot)) + } else { + None + } + } + Window::Generic9x2 { block, player } => { + if (0..18).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((block, area, slot)) + } else if (18..45).contains(&index) { + let area = Area::Storage; + let slot = index - 18; + Some((player, area, slot)) + } else if (45..54).contains(&index) { + let area = Area::Hotbar; + let slot = index - 45; + Some((player, area, slot)) + } else { + None + } + } + Window::Generic9x3 { block, player } => { + if (0..27).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((block, area, slot)) + } else if (27..54).contains(&index) { + let area = Area::Storage; + let slot = index - 27; + Some((player, area, slot)) + } else if (54..63).contains(&index) { + let area = Area::Hotbar; + let slot = index - 54; + Some((player, area, slot)) + } else { + None + } + } + Window::Generic9x4 { block, player } => { + if (0..36).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((block, area, slot)) + } else if (36..63).contains(&index) { + let area = Area::Storage; + let slot = index - 36; + Some((player, area, slot)) + } else if (63..72).contains(&index) { + let area = Area::Hotbar; + let slot = index - 63; + Some((player, area, slot)) + } else { + None + } + } + Window::Generic9x5 { block, player } => { + if (0..45).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((block, area, slot)) + } else if (45..72).contains(&index) { + let area = Area::Storage; + let slot = index - 45; + Some((player, area, slot)) + } else if (72..81).contains(&index) { + let area = Area::Hotbar; + let slot = index - 72; + Some((player, area, slot)) + } else { + None + } + } + Window::Generic9x6 { + left_chest, + right_chest, + player, + } => { + if (0..27).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((left_chest, area, slot)) + } else if (27..54).contains(&index) { + let area = Area::Storage; + let slot = index - 27; + Some((right_chest, area, slot)) + } else if (54..81).contains(&index) { + let area = Area::Storage; + let slot = index - 54; + Some((player, area, slot)) + } else if (81..90).contains(&index) { + let area = Area::Hotbar; + let slot = index - 81; + Some((player, area, slot)) + } else { + None + } + } + Window::Generic3x3 { block, player } => { + if (0..9).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((block, area, slot)) + } else if (9..36).contains(&index) { + let area = Area::Storage; + let slot = index - 9; + Some((player, area, slot)) + } else if (36..45).contains(&index) { + let area = Area::Hotbar; + let slot = index - 36; + Some((player, area, slot)) + } else { + None + } + } + Window::Crafting { + crafting_table, + player, + } => { + if (0..1).contains(&index) { + let area = Area::CraftingOutput; + let slot = index; + Some((crafting_table, area, slot)) + } else if (1..10).contains(&index) { + let area = Area::CraftingInput; + let slot = index - 1; + Some((crafting_table, area, slot)) + } else if (10..37).contains(&index) { + let area = Area::Storage; + let slot = index - 10; + Some((player, area, slot)) + } else if (37..46).contains(&index) { + let area = Area::Hotbar; + let slot = index - 37; + Some((player, area, slot)) + } else { + None + } + } + Window::Furnace { furnace, player } => { + if (0..1).contains(&index) { + let area = Area::FurnaceIngredient; + let slot = index; + Some((furnace, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::FurnaceFuel; + let slot = index - 1; + Some((furnace, area, slot)) + } else if (2..3).contains(&index) { + let area = Area::FurnaceOutput; + let slot = index - 2; + Some((furnace, area, slot)) + } else if (3..30).contains(&index) { + let area = Area::Storage; + let slot = index - 3; + Some((player, area, slot)) + } else if (30..39).contains(&index) { + let area = Area::Hotbar; + let slot = index - 30; + Some((player, area, slot)) + } else { + None + } + } + Window::BlastFurnace { + blast_furnace, + player, + } => { + if (0..1).contains(&index) { + let area = Area::FurnaceIngredient; + let slot = index; + Some((blast_furnace, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::FurnaceFuel; + let slot = index - 1; + Some((blast_furnace, area, slot)) + } else if (2..3).contains(&index) { + let area = Area::FurnaceOutput; + let slot = index - 2; + Some((blast_furnace, area, slot)) + } else if (3..30).contains(&index) { + let area = Area::Storage; + let slot = index - 3; + Some((player, area, slot)) + } else if (30..39).contains(&index) { + let area = Area::Hotbar; + let slot = index - 30; + Some((player, area, slot)) + } else { + None + } + } + Window::Smoker { smoker, player } => { + if (0..1).contains(&index) { + let area = Area::FurnaceIngredient; + let slot = index; + Some((smoker, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::FurnaceFuel; + let slot = index - 1; + Some((smoker, area, slot)) + } else if (2..3).contains(&index) { + let area = Area::FurnaceOutput; + let slot = index - 2; + Some((smoker, area, slot)) + } else if (3..30).contains(&index) { + let area = Area::Storage; + let slot = index - 3; + Some((player, area, slot)) + } else if (30..39).contains(&index) { + let area = Area::Hotbar; + let slot = index - 30; + Some((player, area, slot)) + } else { + None + } + } + Window::Enchantment { + enchantment_table, + player, + } => { + if (0..1).contains(&index) { + let area = Area::EnchantmentItem; + let slot = index; + Some((enchantment_table, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::EnchantmentLapis; + let slot = index - 1; + Some((enchantment_table, area, slot)) + } else if (2..29).contains(&index) { + let area = Area::Storage; + let slot = index - 2; + Some((player, area, slot)) + } else if (29..38).contains(&index) { + let area = Area::Hotbar; + let slot = index - 29; + Some((player, area, slot)) + } else { + None + } + } + Window::BrewingStand { + brewing_stand, + player, + } => { + if (0..3).contains(&index) { + let area = Area::BrewingBottle; + let slot = index; + Some((brewing_stand, area, slot)) + } else if (3..4).contains(&index) { + let area = Area::BrewingIngredient; + let slot = index - 3; + Some((brewing_stand, area, slot)) + } else if (4..5).contains(&index) { + let area = Area::BrewingBlazePowder; + let slot = index - 4; + Some((brewing_stand, area, slot)) + } else if (5..32).contains(&index) { + let area = Area::Storage; + let slot = index - 5; + Some((player, area, slot)) + } else if (32..41).contains(&index) { + let area = Area::Hotbar; + let slot = index - 32; + Some((player, area, slot)) + } else { + None + } + } + Window::Beacon { beacon, player } => { + if (0..1).contains(&index) { + let area = Area::BeaconPayment; + let slot = index; + Some((beacon, area, slot)) + } else if (1..28).contains(&index) { + let area = Area::Storage; + let slot = index - 1; + Some((player, area, slot)) + } else if (28..37).contains(&index) { + let area = Area::Hotbar; + let slot = index - 28; + Some((player, area, slot)) + } else { + None + } + } + Window::Anvil { anvil, player } => { + if (0..1).contains(&index) { + let area = Area::AnvilInput1; + let slot = index; + Some((anvil, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::AnvilInput2; + let slot = index - 1; + Some((anvil, area, slot)) + } else if (2..3).contains(&index) { + let area = Area::AnvilOutput; + let slot = index - 2; + Some((anvil, area, slot)) + } else if (3..30).contains(&index) { + let area = Area::Storage; + let slot = index - 3; + Some((player, area, slot)) + } else if (30..39).contains(&index) { + let area = Area::Hotbar; + let slot = index - 30; + Some((player, area, slot)) + } else { + None + } + } + Window::Hopper { hopper, player } => { + if (0..4).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((hopper, area, slot)) + } else if (4..31).contains(&index) { + let area = Area::Storage; + let slot = index - 4; + Some((player, area, slot)) + } else if (31..40).contains(&index) { + let area = Area::Hotbar; + let slot = index - 31; + Some((player, area, slot)) + } else { + None + } + } + Window::ShulkerBox { + shulker_box, + player, + } => { + if (0..27).contains(&index) { + let area = Area::Storage; + let slot = index; + Some((shulker_box, area, slot)) + } else if (27..54).contains(&index) { + let area = Area::Storage; + let slot = index - 27; + Some((player, area, slot)) + } else if (54..63).contains(&index) { + let area = Area::Hotbar; + let slot = index - 54; + Some((player, area, slot)) + } else { + None + } + } + Window::Cartography { + cartography_table, + player, + } => { + if (0..1).contains(&index) { + let area = Area::CartographyMap; + let slot = index; + Some((cartography_table, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::CartographyPaper; + let slot = index - 1; + Some((cartography_table, area, slot)) + } else if (2..3).contains(&index) { + let area = Area::CartographyOutput; + let slot = index - 2; + Some((cartography_table, area, slot)) + } else if (3..30).contains(&index) { + let area = Area::Storage; + let slot = index - 3; + Some((player, area, slot)) + } else if (30..39).contains(&index) { + let area = Area::Hotbar; + let slot = index - 30; + Some((player, area, slot)) + } else { + None + } + } + Window::Grindstone { grindstone, player } => { + if (0..1).contains(&index) { + let area = Area::GrindstoneInput1; + let slot = index; + Some((grindstone, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::GrindstoneInput2; + let slot = index - 1; + Some((grindstone, area, slot)) + } else if (2..3).contains(&index) { + let area = Area::GrindstoneOutput; + let slot = index - 2; + Some((grindstone, area, slot)) + } else if (3..30).contains(&index) { + let area = Area::Storage; + let slot = index - 3; + Some((player, area, slot)) + } else if (30..39).contains(&index) { + let area = Area::Hotbar; + let slot = index - 30; + Some((player, area, slot)) + } else { + None + } + } + Window::Lectern { lectern, player } => { + if (0..1).contains(&index) { + let area = Area::LecternBook; + let slot = index; + Some((lectern, area, slot)) + } else if (1..28).contains(&index) { + let area = Area::Storage; + let slot = index - 1; + Some((player, area, slot)) + } else if (28..37).contains(&index) { + let area = Area::Hotbar; + let slot = index - 28; + Some((player, area, slot)) + } else { + None + } + } + Window::Loom { loom, player } => { + if (0..1).contains(&index) { + let area = Area::LoomBanner; + let slot = index; + Some((loom, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::LoomDye; + let slot = index - 1; + Some((loom, area, slot)) + } else if (2..3).contains(&index) { + let area = Area::LoomPattern; + let slot = index - 2; + Some((loom, area, slot)) + } else if (3..4).contains(&index) { + let area = Area::LoomOutput; + let slot = index - 3; + Some((loom, area, slot)) + } else if (4..31).contains(&index) { + let area = Area::Storage; + let slot = index - 4; + Some((player, area, slot)) + } else if (31..40).contains(&index) { + let area = Area::Hotbar; + let slot = index - 31; + Some((player, area, slot)) + } else { + None + } + } + Window::Stonecutter { + stonecutter, + player, + } => { + if (0..1).contains(&index) { + let area = Area::StonecutterInput; + let slot = index; + Some((stonecutter, area, slot)) + } else if (1..2).contains(&index) { + let area = Area::StonecutterOutput; + let slot = index - 1; + Some((stonecutter, area, slot)) + } else if (2..29).contains(&index) { + let area = Area::Storage; + let slot = index - 2; + Some((player, area, slot)) + } else if (29..38).contains(&index) { + let area = Area::Hotbar; + let slot = index - 29; + Some((player, area, slot)) + } else { + None + } + } + } + } + pub fn slot_to_index( + &self, + inventory: &crate::Inventory, + area: Area, + slot: usize, + ) -> Option<usize> { + match self { + Window::Player { player } => { + if area == Area::CraftingOutput && player.ptr_eq(inventory) { + Some(slot) + } else if area == Area::CraftingInput && player.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::Helmet && player.ptr_eq(inventory) { + Some(slot + 5) + } else if area == Area::Chestplate && player.ptr_eq(inventory) { + Some(slot + 6) + } else if area == Area::Leggings && player.ptr_eq(inventory) { + Some(slot + 7) + } else if area == Area::Boots && player.ptr_eq(inventory) { + Some(slot + 8) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 9) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 36) + } else if area == Area::Offhand && player.ptr_eq(inventory) { + Some(slot + 45) + } else { + None + } + } + Window::Generic9x1 { block, player } => { + if area == Area::Storage && block.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 9) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 36) + } else { + None + } + } + Window::Generic9x2 { block, player } => { + if area == Area::Storage && block.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 18) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 45) + } else { + None + } + } + Window::Generic9x3 { block, player } => { + if area == Area::Storage && block.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 27) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 54) + } else { + None + } + } + Window::Generic9x4 { block, player } => { + if area == Area::Storage && block.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 36) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 63) + } else { + None + } + } + Window::Generic9x5 { block, player } => { + if area == Area::Storage && block.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 45) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 72) + } else { + None + } + } + Window::Generic9x6 { + left_chest, + right_chest, + player, + } => { + if area == Area::Storage && left_chest.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && right_chest.ptr_eq(inventory) { + Some(slot + 27) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 54) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 81) + } else { + None + } + } + Window::Generic3x3 { block, player } => { + if area == Area::Storage && block.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 9) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 36) + } else { + None + } + } + Window::Crafting { + crafting_table, + player, + } => { + if area == Area::CraftingOutput && crafting_table.ptr_eq(inventory) { + Some(slot) + } else if area == Area::CraftingInput && crafting_table.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 10) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 37) + } else { + None + } + } + Window::Furnace { furnace, player } => { + if area == Area::FurnaceIngredient && furnace.ptr_eq(inventory) { + Some(slot) + } else if area == Area::FurnaceFuel && furnace.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::FurnaceOutput && furnace.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 3) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 30) + } else { + None + } + } + Window::BlastFurnace { + blast_furnace, + player, + } => { + if area == Area::FurnaceIngredient && blast_furnace.ptr_eq(inventory) { + Some(slot) + } else if area == Area::FurnaceFuel && blast_furnace.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::FurnaceOutput && blast_furnace.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 3) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 30) + } else { + None + } + } + Window::Smoker { smoker, player } => { + if area == Area::FurnaceIngredient && smoker.ptr_eq(inventory) { + Some(slot) + } else if area == Area::FurnaceFuel && smoker.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::FurnaceOutput && smoker.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 3) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 30) + } else { + None + } + } + Window::Enchantment { + enchantment_table, + player, + } => { + if area == Area::EnchantmentItem && enchantment_table.ptr_eq(inventory) { + Some(slot) + } else if area == Area::EnchantmentLapis && enchantment_table.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 29) + } else { + None + } + } + Window::BrewingStand { + brewing_stand, + player, + } => { + if area == Area::BrewingBottle && brewing_stand.ptr_eq(inventory) { + Some(slot) + } else if area == Area::BrewingIngredient && brewing_stand.ptr_eq(inventory) { + Some(slot + 3) + } else if area == Area::BrewingBlazePowder && brewing_stand.ptr_eq(inventory) { + Some(slot + 4) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 5) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 32) + } else { + None + } + } + Window::Beacon { beacon, player } => { + if area == Area::BeaconPayment && beacon.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 28) + } else { + None + } + } + Window::Anvil { anvil, player } => { + if area == Area::AnvilInput1 && anvil.ptr_eq(inventory) { + Some(slot) + } else if area == Area::AnvilInput2 && anvil.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::AnvilOutput && anvil.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 3) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 30) + } else { + None + } + } + Window::Hopper { hopper, player } => { + if area == Area::Storage && hopper.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 4) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 31) + } else { + None + } + } + Window::ShulkerBox { + shulker_box, + player, + } => { + if area == Area::Storage && shulker_box.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 27) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 54) + } else { + None + } + } + Window::Cartography { + cartography_table, + player, + } => { + if area == Area::CartographyMap && cartography_table.ptr_eq(inventory) { + Some(slot) + } else if area == Area::CartographyPaper && cartography_table.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::CartographyOutput && cartography_table.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 3) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 30) + } else { + None + } + } + Window::Grindstone { grindstone, player } => { + if area == Area::GrindstoneInput1 && grindstone.ptr_eq(inventory) { + Some(slot) + } else if area == Area::GrindstoneInput2 && grindstone.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::GrindstoneOutput && grindstone.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 3) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 30) + } else { + None + } + } + Window::Lectern { lectern, player } => { + if area == Area::LecternBook && lectern.ptr_eq(inventory) { + Some(slot) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 28) + } else { + None + } + } + Window::Loom { loom, player } => { + if area == Area::LoomBanner && loom.ptr_eq(inventory) { + Some(slot) + } else if area == Area::LoomDye && loom.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::LoomPattern && loom.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::LoomOutput && loom.ptr_eq(inventory) { + Some(slot + 3) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 4) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 31) + } else { + None + } + } + Window::Stonecutter { + stonecutter, + player, + } => { + if area == Area::StonecutterInput && stonecutter.ptr_eq(inventory) { + Some(slot) + } else if area == Area::StonecutterOutput && stonecutter.ptr_eq(inventory) { + Some(slot + 1) + } else if area == Area::Storage && player.ptr_eq(inventory) { + Some(slot + 2) + } else if area == Area::Hotbar && player.ptr_eq(inventory) { + Some(slot + 29) + } else { + None + } + } + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Window { + /// Returns the `name` property of this `Window`. + pub fn name(&self) -> &'static str { + match self { + Window::Player { .. } => "player", + Window::Generic9x1 { .. } => "generic_9x1", + Window::Generic9x2 { .. } => "generic_9x2", + Window::Generic9x3 { .. } => "generic_9x3", + Window::Generic9x4 { .. } => "generic_9x4", + Window::Generic9x5 { .. } => "generic_9x5", + Window::Generic9x6 { .. } => "generic_9x6", + Window::Generic3x3 { .. } => "generic_3x3", + Window::Crafting { .. } => "crafting", + Window::Furnace { .. } => "furnace", + Window::BlastFurnace { .. } => "blast_furnace", + Window::Smoker { .. } => "smoker", + Window::Enchantment { .. } => "enchantment", + Window::BrewingStand { .. } => "brewing_stand", + Window::Beacon { .. } => "beacon", + Window::Anvil { .. } => "anvil", + Window::Hopper { .. } => "hopper", + Window::ShulkerBox { .. } => "shulker_box", + Window::Cartography { .. } => "cartography", + Window::Grindstone { .. } => "grindstone", + Window::Lectern { .. } => "lectern", + Window::Loom { .. } => "loom", + Window::Stonecutter { .. } => "stonecutter", + } + } +} +#[derive(Debug, Clone)] +pub enum InventoryBacking<T> { + Player { + crafting_input: [T; 4], + crafting_output: [T; 1], + helmet: [T; 1], + chestplate: [T; 1], + leggings: [T; 1], + boots: [T; 1], + storage: [T; 27], + hotbar: [T; 9], + offhand: [T; 1], + }, + Chest { + storage: [T; 27], + }, + CraftingTable { + crafting_input: [T; 9], + crafting_output: [T; 1], + }, + Furnace { + furnace_ingredient: [T; 1], + furnace_fuel: [T; 1], + furnace_output: [T; 1], + }, +} +impl<T> InventoryBacking<T> { + pub fn area_slice(&self, area: Area) -> Option<&[T]> { + match self { + InventoryBacking::Player { + crafting_input, + crafting_output, + helmet, + chestplate, + leggings, + boots, + storage, + hotbar, + offhand, + } => match area { + Area::CraftingInput => Some(crafting_input.as_ref()), + Area::CraftingOutput => Some(crafting_output.as_ref()), + Area::Helmet => Some(helmet.as_ref()), + Area::Chestplate => Some(chestplate.as_ref()), + Area::Leggings => Some(leggings.as_ref()), + Area::Boots => Some(boots.as_ref()), + Area::Storage => Some(storage.as_ref()), + Area::Hotbar => Some(hotbar.as_ref()), + Area::Offhand => Some(offhand.as_ref()), + _ => None, + }, + InventoryBacking::Chest { storage } => match area { + Area::Storage => Some(storage.as_ref()), + _ => None, + }, + InventoryBacking::CraftingTable { + crafting_input, + crafting_output, + } => match area { + Area::CraftingInput => Some(crafting_input.as_ref()), + Area::CraftingOutput => Some(crafting_output.as_ref()), + _ => None, + }, + InventoryBacking::Furnace { + furnace_ingredient, + furnace_fuel, + furnace_output, + } => match area { + Area::FurnaceIngredient => Some(furnace_ingredient.as_ref()), + Area::FurnaceFuel => Some(furnace_fuel.as_ref()), + Area::FurnaceOutput => Some(furnace_output.as_ref()), + _ => None, + }, + } + } + pub fn areas(&self) -> &'static [Area] { + match self { + InventoryBacking::Player { .. } => { + static AREAS: [Area; 9] = [ + Area::CraftingInput, + Area::CraftingOutput, + Area::Helmet, + Area::Chestplate, + Area::Leggings, + Area::Boots, + Area::Storage, + Area::Hotbar, + Area::Offhand, + ]; + &AREAS + } + InventoryBacking::Chest { .. } => { + static AREAS: [Area; 1] = [Area::Storage]; + &AREAS + } + InventoryBacking::CraftingTable { .. } => { + static AREAS: [Area; 2] = [Area::CraftingInput, Area::CraftingOutput]; + &AREAS + } + InventoryBacking::Furnace { .. } => { + static AREAS: [Area; 3] = [ + Area::FurnaceIngredient, + Area::FurnaceFuel, + Area::FurnaceOutput, + ]; + &AREAS + } + } + } + pub fn player() -> Self + where + T: Default, + { + InventoryBacking::Player { + crafting_input: Default::default(), + crafting_output: Default::default(), + helmet: Default::default(), + chestplate: Default::default(), + leggings: Default::default(), + boots: Default::default(), + storage: Default::default(), + hotbar: Default::default(), + offhand: Default::default(), + } + } + pub fn chest() -> Self + where + T: Default, + { + InventoryBacking::Chest { + storage: Default::default(), + } + } + pub fn crafting_table() -> Self + where + T: Default, + { + InventoryBacking::CraftingTable { + crafting_input: Default::default(), + crafting_output: Default::default(), + } + } + pub fn furnace() -> Self + where + T: Default, + { + InventoryBacking::Furnace { + furnace_ingredient: Default::default(), + furnace_fuel: Default::default(), + furnace_output: Default::default(), + } + } +} +impl crate::Inventory { + pub fn player() -> Self { + Self { + backing: std::sync::Arc::new(InventoryBacking::player()), + } + } + pub fn chest() -> Self { + Self { + backing: std::sync::Arc::new(InventoryBacking::chest()), + } + } + pub fn crafting_table() -> Self { + Self { + backing: std::sync::Arc::new(InventoryBacking::crafting_table()), + } + } + pub fn furnace() -> Self { + Self { + backing: std::sync::Arc::new(InventoryBacking::furnace()), + } + } +} diff --git a/libcraft/inventory/src/lib.rs b/libcraft/inventory/src/lib.rs new file mode 100644 index 000000000..a2abc3cb6 --- /dev/null +++ b/libcraft/inventory/src/lib.rs @@ -0,0 +1,113 @@ +mod inventory; + +use parking_lot::{Mutex, MutexGuard}; +use std::{error::Error, sync::Arc}; + +pub use inventory::{Area, InventoryBacking, Window}; + +use libcraft_items::InventorySlot; + +type Slot = Mutex<InventorySlot>; + +/// A handle to an inventory. +/// +/// An inventory is composed of one or more _areas_, each +/// if which contains one or more item stacks stored in an array. Areas are defined +/// by the `Area` enum; examples include `Storage`, `Hotbar`, `Helmet`, `Offhand`, +/// and `CraftingInput`. +/// +/// Note that an `Inventory` is a _handle_; it's backed by an `Arc`. As such, cloning +/// it is cheap and creates a new handle to the same inventory. Interior mutability +/// is used to make this safe. +#[derive(Debug, Clone)] +pub struct Inventory { + backing: Arc<InventoryBacking<Slot>>, +} + +impl Inventory { + /// Returns whether two `Inventory` handles point to the same + /// backing inventory. + pub fn ptr_eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.backing, &other.backing) + } + + /// Gets the item at the given index within an area in this inventory. + /// + /// The returned value is a `MutexGuard` and can be mutated. + /// + /// # Note + /// _Never_ keep two returned `MutexGuard`s for the same inventory alive + /// at once. Deadlocks are not fun. + pub fn item(&self, area: Area, slot: usize) -> Option<MutexGuard<InventorySlot>> { + let slice = self.backing.area_slice(area)?; + slice.get(slot).map(Mutex::lock) + } + + pub fn to_vec(&self) -> Vec<InventorySlot> { + let mut vec = Vec::new(); + for area in self.backing.areas() { + if let Some(items) = self.backing.area_slice(*area) { + for item in items { + let i = item.lock(); + vec.push(i.clone()); + } + } + } + vec + } + + /// Creates a new handle to the same inventory. + /// + /// This operation is the same as calling `clone()`, but it's more explicit + /// in its intent. + pub fn new_handle(&self) -> Inventory { + self.clone() + } +} + +#[derive(Debug)] +pub enum WindowError { + OutOfBounds(usize), +} + +impl std::fmt::Display for WindowError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::OutOfBounds(value) => { + f.write_fmt(format_args!("Slot index {} is out of bounds", value)) + } + } + } +} + +impl Error for WindowError {} + +impl Window { + /// Gets the item at the provided protocol index. + /// Returns an error if index is invalid. + pub fn item(&self, index: usize) -> Result<MutexGuard<InventorySlot>, WindowError> { + let (inventory, area, slot) = self + .index_to_slot(index) + .ok_or(WindowError::OutOfBounds(index))?; + inventory + .item(area, slot) + .ok_or(WindowError::OutOfBounds(index)) + } + + /// Sets the item at the provided protocol index. + /// Returns an error if the index is invalid. + pub fn set_item(&self, index: usize, item: InventorySlot) -> Result<(), WindowError> { + *self.item(index)? = item; + Ok(()) + } + + pub fn to_vec(&self) -> Vec<InventorySlot> { + let mut i = 0; + let mut vec = Vec::new(); + while let Ok(item) = self.item(i) { + vec.push(item.clone()); + i += 1; + } + vec + } +} diff --git a/libcraft/items/Cargo.toml b/libcraft/items/Cargo.toml new file mode 100644 index 000000000..ea9e1fd38 --- /dev/null +++ b/libcraft/items/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "libcraft-items" +version = "0.1.0" +authors = ["Kalle Kankaanpää", "Pau Machetti <paumachetti@gmail.com>"] +edition = "2018" + +[dependencies] +serde = { version = "1", features = ["derive"] } diff --git a/libcraft/items/src/enchantment.rs b/libcraft/items/src/enchantment.rs new file mode 100644 index 000000000..a06661c8a --- /dev/null +++ b/libcraft/items/src/enchantment.rs @@ -0,0 +1,107 @@ +//! Data sourced from: <https://minecraft.gamepedia.com/Enchanting#Enchantments> + +use serde::{Deserialize, Serialize}; + +/// An enchantment attached to an item. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Enchantment { + /// The type of the enchantment. + #[serde(rename = "id")] + kind: EnchantmentKind, + /// Enchantment level, represented by an `i8` for vanilla compatibility + #[serde(rename = "lvl")] + level: i8, +} + +impl Enchantment { + /// Creates an enchantment given the type of + /// enchantment and the level. + /// + /// Will allow any level of enchantment, i.e, + /// level is not capped by the maximum level + /// of the enchantment that can be acquired in the game. + /// + /// The level is capped at `i8::MAX` for compatability + /// with Vanilla. + #[must_use] + #[allow(clippy::cast_possible_truncation)] + pub fn new(kind: EnchantmentKind, level: u32) -> Self { + Self { + kind, + level: level.min(i8::MAX as u32) as i8, + } + } + + /// Gets the kind of this enchantment. + #[must_use] + pub const fn kind(&self) -> EnchantmentKind { + self.kind + } + + /// Gets the level of this enchantment. + #[must_use] + #[allow(clippy::cast_sign_loss)] + pub fn level(&self) -> u32 { + self.level.max(0) as u32 + } + + /// Sets the kind of this enchantment. + /// + /// The level is not affected. + pub fn set_kind(&mut self, kind: EnchantmentKind) { + self.kind = kind; + } + + /// Sets the level of this enchantment. + /// + /// The level is capped to `i8::MAX`. + #[allow(clippy::cast_possible_truncation)] + pub fn set_level(&mut self, level: u32) { + self.level = level.min(i8::MAX as u32) as i8; + } +} + +/// Kind of an enchantment. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum EnchantmentKind { + AquaAffinity, + BaneOfArthropods, + BlastProtection, + Channeling, + Cleaving, + CurseOfBinding, + CurseOfVanishing, + DepthStrider, + Efficiency, + FeatherFalling, + FireAspect, + FireProtection, + Flame, + Fortune, + FrostWalker, + Impaling, + Infinity, + Knockback, + Looting, + Loyalty, + LuckOfTheSea, + Lure, + Mending, + Multishot, + Piercing, + Power, + ProjectileProtection, + Protection, + Punch, + QuickCharge, + Respiration, + Riptide, + Sharpness, + SilkTouch, + Smite, + SoulSpeed, + SweepingEdge, + Thorns, + Unbreaking, +} diff --git a/libcraft/items/src/inventory_slot.rs b/libcraft/items/src/inventory_slot.rs new file mode 100644 index 000000000..7f7e37c2a --- /dev/null +++ b/libcraft/items/src/inventory_slot.rs @@ -0,0 +1,372 @@ +use crate::{Item, ItemStack}; +use core::mem; +use serde::{Deserialize, Serialize}; + +/// Represents an Inventory slot. May be empty +/// or filled (contains an `ItemStack`). +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum InventorySlot { + Filled(ItemStack), + Empty, +} + +impl Default for InventorySlot { + fn default() -> Self { + Self::Empty + } +} + +impl From<Option<ItemStack>> for InventorySlot { + fn from(it: Option<ItemStack>) -> Self { + it.map(Self::Filled).unwrap_or_default() + } +} + +impl From<InventorySlot> for Option<ItemStack> { + fn from(it: InventorySlot) -> Self { + it.into_option() + } +} + +impl InventorySlot { + /// Creates a new instance with the type `kind` and `count` items + #[must_use] + #[allow(clippy::missing_panics_doc)] + pub fn new(kind: Item, count: u32) -> Self { + ItemStack::new(kind, count) + .map(Self::Filled) + .unwrap_or_default() + } + + /// If instace of `Self::Filled`, then it returns `Some(stack_size)` + /// where `stack_size` is the biggest number of items allowable + /// for the given item in a stack. + /// If instance of `Self::Empty`, then we can't know the stack + /// size and None is returned. + #[must_use] + pub fn stack_size(&self) -> Option<u32> { + self.map_ref(ItemStack::stack_size) + } + + /// Takes all items and makes self empty. + #[must_use] + pub fn take_all(&mut self) -> Self { + mem::take(self) + } + + /// Takes half (rounded down) of the items in self. + #[must_use] + pub fn take_half(&mut self) -> Self { + let half = (self.count() + 1) / 2; + self.try_take(half) + } + + /// Tries to take the specified amount from 'self' + /// and put it into the output. If amount is bigger + /// then what self can provide then this is the same + /// as calling take. + #[must_use] + #[allow(clippy::missing_panics_doc)] + pub fn try_take(&mut self, amount: u32) -> Self { + if amount == 0 { + return Self::Empty; + } + + if let Self::Filled(stack) = self { + if stack.count() <= amount { + // We take all and set self to empty + mem::take(self) + } else { + // We take some of self. + let mut out = stack.clone(); + // `amount` != 0 + out.set_count(amount).unwrap(); + // `stack.count` > amount + stack.remove(amount).unwrap(); + Self::Filled(out) + } + } else { + Self::Empty + } + } + + /// Tries to take the exact specified amount from 'self', + /// but if that is not possible then it returns None. + pub fn take(&mut self, amount: u32) -> Option<Self> { + if amount <= self.count() { + Some(self.try_take(amount)) + } else { + None + } + } + + /// Returns the number of items stored in the inventory slot. + #[must_use] + pub fn count(&self) -> u32 { + self.map_ref(ItemStack::count).unwrap_or(0) + } + + /// Should only be called if the caller can guarantee that there is space + /// such that the new could is not greater then `self.stack_size`(). + /// And that the slot actually contains an item. + fn add_count(&mut self, n: u32) { + self.option_mut() + .expect("add count called on empty inventory slot!") + .add(n) + .expect("new item count exceeds stack size"); + } + + /// Transfers up to `n` items from 'self' to `other`. + #[allow(clippy::missing_panics_doc)] + pub fn transfer_to(&mut self, n: u32, other: &mut Self) { + if !self.is_mergable(other) { + return; + } + + match (self.is_filled(), other.is_filled()) { + (true, true) => { + // `other` is guaranteed to be `Filled` + let space_in_other = other.stack_size().unwrap() - other.count(); + let moving = n.min(space_in_other).min(self.count()); + let taken = self.try_take(moving); + other.add_count(taken.count()); + } + (true, false) => { + let taken = self.try_take(n); + *other = taken; + } + (false, _) => {} // No items to move + } + } + + /// Checks if the `InventorySlot` is empty. + #[must_use] + pub const fn is_empty(&self) -> bool { + matches!(self, Self::Empty) + } + + /// Checks if the `InventorySlot` is filled. + #[must_use] + pub const fn is_filled(&self) -> bool { + !self.is_empty() + } + + /// Returns the number of items moved from other to self. + #[allow(clippy::missing_panics_doc)] + pub fn merge(&mut self, other: &mut Self) -> u32 { + if !self.is_mergable(other) { + return 0; + } + match (self.is_filled(), other.is_filled()) { + (true, true) => { + // `self` is `Filled` + let moving = (self.stack_size().unwrap() - self.count()).min(other.count()); + let taken = other.try_take(moving); + self.add_count(taken.count()); + taken.count() + } + (_, false) => 0, + (false, true) => { + mem::swap(self, other); + self.count() + } + } + } + + /// Returns true if either one is empty, or they + /// contain the same `ItemStack` type. Does *not* consider + /// if there is space enough for the move to happen. + #[must_use] + pub fn is_mergable(&self, other: &Self) -> bool { + match (self, other) { + (InventorySlot::Filled(a), InventorySlot::Filled(b)) => a.stackable_types(b), + (InventorySlot::Empty, _) | (_, InventorySlot::Empty) => true, + } + } + + /// Returns the item kind of the inventory slot if it is filled, + /// otherwise it returns None. + #[must_use] + pub fn item_kind(&self) -> Option<Item> { + self.map_ref(ItemStack::item) + } + + /// Convert `self` into an `Option<ItemStack>` + #[must_use] + pub fn into_option(self) -> Option<ItemStack> { + match self { + InventorySlot::Filled(f) => Some(f), + InventorySlot::Empty => None, + } + } + /// Convert a reference to `self` into an `Option<&ItemStack>` + #[must_use] + pub const fn option_ref(&self) -> Option<&ItemStack> { + match self { + InventorySlot::Filled(f) => Some(f), + InventorySlot::Empty => None, + } + } + /// Convert a mutable reference to `self` into an `Option<&mut ItemStack>` + #[must_use] + pub fn option_mut(&mut self) -> Option<&mut ItemStack> { + match self { + InventorySlot::Filled(f) => Some(f), + InventorySlot::Empty => None, + } + } + /// Map `f` over the inner item stack, optionally returning the resulting value. + #[must_use] + pub fn map<F: FnOnce(ItemStack) -> U, U>(self, f: F) -> Option<U> { + self.into_option().map(f) + } + /// Map `f` over the inner item stack, optionally returning the resulting value. + #[must_use] + pub fn map_ref<F: FnOnce(&ItemStack) -> U, U>(&self, f: F) -> Option<U> { + self.option_ref().map(f) + } + /// Map `f` over the inner item stack, optionally returning the resulting value. + #[must_use] + pub fn map_mut<F: FnOnce(&mut ItemStack) -> U, U>(&mut self, f: F) -> Option<U> { + self.option_mut().map(f) + } +} + +impl IntoIterator for InventorySlot { + type Item = ItemStack; + + type IntoIter = std::option::IntoIter<ItemStack>; + + fn into_iter(self) -> Self::IntoIter { + self.into_option().into_iter() + } +} +impl<'a> IntoIterator for &'a InventorySlot { + type Item = &'a ItemStack; + + type IntoIter = std::option::IntoIter<&'a ItemStack>; + + fn into_iter(self) -> Self::IntoIter { + self.option_ref().into_iter() + } +} +impl<'a> IntoIterator for &'a mut InventorySlot { + type Item = &'a mut ItemStack; + + type IntoIter = std::option::IntoIter<&'a mut ItemStack>; + + fn into_iter(self) -> Self::IntoIter { + self.option_mut().into_iter() + } +} + +#[cfg(test)] +mod test { + use crate::{InventorySlot, Item}; + + #[test] + fn test_merge() { + let mut a = InventorySlot::new(Item::Stone, 5); + let mut b = InventorySlot::new(Item::Stone, 30); + a.merge(&mut b); + println!("{:?}", a); + assert!(a.is_mergable(&b)); + assert_eq!(a.count(), 35); + assert!(b.is_empty()); + + a = InventorySlot::new(Item::Stone, 60); + b = InventorySlot::new(Item::Stone, 10); + assert_eq!(a.merge(&mut b), 4); + assert_eq!(b.count(), 6); + + a = InventorySlot::new(Item::AcaciaDoor, 1); + b = InventorySlot::new(Item::AcaciaButton, 1); + assert_eq!(a.merge(&mut b), 0); + + a = InventorySlot::new(Item::Stone, 1); + b = InventorySlot::Empty; + assert_eq!(a.merge(&mut b), 0); + + a = InventorySlot::Empty; + b = InventorySlot::new(Item::Stone, 10); + assert_eq!(a.merge(&mut b), 10); + assert!(b.is_empty()); + } + + #[test] + fn take_half() { + let mut a = InventorySlot::new(Item::Stone, 5); + let b = a.take_half(); + assert_eq!(a.count() + b.count(), 5); + assert_eq!(a.count(), 2); + + a = InventorySlot::new(Item::Stone, 1); + let b = a.take_half(); + assert_eq!(a.count(), 0); + assert_eq!(b.count(), 1); + + a = InventorySlot::Empty; + let b = a.take_half(); + assert!(a.is_empty() && b.is_empty()); + } + + #[test] + fn transfer_to() { + let mut a = InventorySlot::new(Item::Stone, 5); + let mut b = InventorySlot::new(Item::Stone, 2); + a.transfer_to(2, &mut b); + assert_eq!(a.count(), 3); + assert_eq!(b.count(), 4); + + a = InventorySlot::new(Item::AcaciaDoor, 3); + b = InventorySlot::new(Item::AcaciaButton, 5); + a.transfer_to(1, &mut b); + assert_eq!(a.count(), 3); + assert_eq!(b.count(), 5); + + a = InventorySlot::new(Item::Stone, 3); + b = InventorySlot::new(Item::Stone, 5); + a.transfer_to(10, &mut b); + assert_eq!(a.count(), 0); + assert_eq!(b.count(), 8); + + a = InventorySlot::new(Item::Stone, 10); + b = InventorySlot::new(Item::Stone, 60); + a.transfer_to(20, &mut b); + assert_eq!(a.count(), 6); + assert_eq!(b.count(), 64); + + a = InventorySlot::new(Item::Stone, 5); + b = InventorySlot::Empty; + a.transfer_to(2, &mut b); + assert_eq!(a.count(), 3); + assert_eq!(b.count(), 2); + + a = InventorySlot::Empty; + b = InventorySlot::new(Item::Stone, 5); + a.transfer_to(2, &mut b); + assert_eq!(a.count(), 0); + assert_eq!(b.count(), 5); + } + + #[test] + fn try_take() { + let mut a = InventorySlot::new(Item::Stone, 64); + assert_eq!(a.try_take(16), InventorySlot::new(Item::Stone, 16)); + assert_eq!(a.try_take(0), InventorySlot::Empty); + assert_eq!(a.try_take(50), InventorySlot::new(Item::Stone, 48)); + assert_eq!(a.try_take(2), InventorySlot::Empty); + a = InventorySlot::new(Item::Stone, 5); + assert_eq!(a.try_take(u32::MAX), InventorySlot::new(Item::Stone, 5)); + } + + #[test] + fn take() { + let mut a = InventorySlot::new(Item::Stone, 64); + assert_eq!(a.take(16), Some(InventorySlot::new(Item::Stone, 16))); + assert_eq!(a.take(0), Some(InventorySlot::Empty)); + assert_eq!(a.take(50), None); + assert_eq!(a.take(48), Some(InventorySlot::new(Item::Stone, 48))); + assert_eq!(a.take(1), None); + } +} diff --git a/libcraft/items/src/item.rs b/libcraft/items/src/item.rs new file mode 100644 index 000000000..c29fd8b62 --- /dev/null +++ b/libcraft/items/src/item.rs @@ -0,0 +1,7907 @@ +// This file is @generated. Please do not edit. +use serde::{Deserialize, Serialize}; +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +#[serde(try_from = "String", into = "&'static str")] +pub enum Item { + Air, + Stone, + Granite, + PolishedGranite, + Diorite, + PolishedDiorite, + Andesite, + PolishedAndesite, + GrassBlock, + Dirt, + CoarseDirt, + Podzol, + CrimsonNylium, + WarpedNylium, + Cobblestone, + OakPlanks, + SprucePlanks, + BirchPlanks, + JunglePlanks, + AcaciaPlanks, + DarkOakPlanks, + CrimsonPlanks, + WarpedPlanks, + OakSapling, + SpruceSapling, + BirchSapling, + JungleSapling, + AcaciaSapling, + DarkOakSapling, + Bedrock, + Sand, + RedSand, + Gravel, + GoldOre, + IronOre, + CoalOre, + NetherGoldOre, + OakLog, + SpruceLog, + BirchLog, + JungleLog, + AcaciaLog, + DarkOakLog, + CrimsonStem, + WarpedStem, + StrippedOakLog, + StrippedSpruceLog, + StrippedBirchLog, + StrippedJungleLog, + StrippedAcaciaLog, + StrippedDarkOakLog, + StrippedCrimsonStem, + StrippedWarpedStem, + StrippedOakWood, + StrippedSpruceWood, + StrippedBirchWood, + StrippedJungleWood, + StrippedAcaciaWood, + StrippedDarkOakWood, + StrippedCrimsonHyphae, + StrippedWarpedHyphae, + OakWood, + SpruceWood, + BirchWood, + JungleWood, + AcaciaWood, + DarkOakWood, + CrimsonHyphae, + WarpedHyphae, + OakLeaves, + SpruceLeaves, + BirchLeaves, + JungleLeaves, + AcaciaLeaves, + DarkOakLeaves, + Sponge, + WetSponge, + Glass, + LapisOre, + LapisBlock, + Dispenser, + Sandstone, + ChiseledSandstone, + CutSandstone, + NoteBlock, + PoweredRail, + DetectorRail, + StickyPiston, + Cobweb, + Grass, + Fern, + DeadBush, + Seagrass, + SeaPickle, + Piston, + WhiteWool, + OrangeWool, + MagentaWool, + LightBlueWool, + YellowWool, + LimeWool, + PinkWool, + GrayWool, + LightGrayWool, + CyanWool, + PurpleWool, + BlueWool, + BrownWool, + GreenWool, + RedWool, + BlackWool, + Dandelion, + Poppy, + BlueOrchid, + Allium, + AzureBluet, + RedTulip, + OrangeTulip, + WhiteTulip, + PinkTulip, + OxeyeDaisy, + Cornflower, + LilyOfTheValley, + WitherRose, + BrownMushroom, + RedMushroom, + CrimsonFungus, + WarpedFungus, + CrimsonRoots, + WarpedRoots, + NetherSprouts, + WeepingVines, + TwistingVines, + SugarCane, + Kelp, + Bamboo, + GoldBlock, + IronBlock, + OakSlab, + SpruceSlab, + BirchSlab, + JungleSlab, + AcaciaSlab, + DarkOakSlab, + CrimsonSlab, + WarpedSlab, + StoneSlab, + SmoothStoneSlab, + SandstoneSlab, + CutSandstoneSlab, + PetrifiedOakSlab, + CobblestoneSlab, + BrickSlab, + StoneBrickSlab, + NetherBrickSlab, + QuartzSlab, + RedSandstoneSlab, + CutRedSandstoneSlab, + PurpurSlab, + PrismarineSlab, + PrismarineBrickSlab, + DarkPrismarineSlab, + SmoothQuartz, + SmoothRedSandstone, + SmoothSandstone, + SmoothStone, + Bricks, + Tnt, + Bookshelf, + MossyCobblestone, + Obsidian, + Torch, + EndRod, + ChorusPlant, + ChorusFlower, + PurpurBlock, + PurpurPillar, + PurpurStairs, + Spawner, + OakStairs, + Chest, + DiamondOre, + DiamondBlock, + CraftingTable, + Farmland, + Furnace, + Ladder, + Rail, + CobblestoneStairs, + Lever, + StonePressurePlate, + OakPressurePlate, + SprucePressurePlate, + BirchPressurePlate, + JunglePressurePlate, + AcaciaPressurePlate, + DarkOakPressurePlate, + CrimsonPressurePlate, + WarpedPressurePlate, + PolishedBlackstonePressurePlate, + RedstoneOre, + RedstoneTorch, + Snow, + Ice, + SnowBlock, + Cactus, + Clay, + Jukebox, + OakFence, + SpruceFence, + BirchFence, + JungleFence, + AcaciaFence, + DarkOakFence, + CrimsonFence, + WarpedFence, + Pumpkin, + CarvedPumpkin, + Netherrack, + SoulSand, + SoulSoil, + Basalt, + PolishedBasalt, + SoulTorch, + Glowstone, + JackOLantern, + OakTrapdoor, + SpruceTrapdoor, + BirchTrapdoor, + JungleTrapdoor, + AcaciaTrapdoor, + DarkOakTrapdoor, + CrimsonTrapdoor, + WarpedTrapdoor, + InfestedStone, + InfestedCobblestone, + InfestedStoneBricks, + InfestedMossyStoneBricks, + InfestedCrackedStoneBricks, + InfestedChiseledStoneBricks, + StoneBricks, + MossyStoneBricks, + CrackedStoneBricks, + ChiseledStoneBricks, + BrownMushroomBlock, + RedMushroomBlock, + MushroomStem, + IronBars, + Chain, + GlassPane, + Melon, + Vine, + OakFenceGate, + SpruceFenceGate, + BirchFenceGate, + JungleFenceGate, + AcaciaFenceGate, + DarkOakFenceGate, + CrimsonFenceGate, + WarpedFenceGate, + BrickStairs, + StoneBrickStairs, + Mycelium, + LilyPad, + NetherBricks, + CrackedNetherBricks, + ChiseledNetherBricks, + NetherBrickFence, + NetherBrickStairs, + EnchantingTable, + EndPortalFrame, + EndStone, + EndStoneBricks, + DragonEgg, + RedstoneLamp, + SandstoneStairs, + EmeraldOre, + EnderChest, + TripwireHook, + EmeraldBlock, + SpruceStairs, + BirchStairs, + JungleStairs, + CrimsonStairs, + WarpedStairs, + CommandBlock, + Beacon, + CobblestoneWall, + MossyCobblestoneWall, + BrickWall, + PrismarineWall, + RedSandstoneWall, + MossyStoneBrickWall, + GraniteWall, + StoneBrickWall, + NetherBrickWall, + AndesiteWall, + RedNetherBrickWall, + SandstoneWall, + EndStoneBrickWall, + DioriteWall, + BlackstoneWall, + PolishedBlackstoneWall, + PolishedBlackstoneBrickWall, + StoneButton, + OakButton, + SpruceButton, + BirchButton, + JungleButton, + AcaciaButton, + DarkOakButton, + CrimsonButton, + WarpedButton, + PolishedBlackstoneButton, + Anvil, + ChippedAnvil, + DamagedAnvil, + TrappedChest, + LightWeightedPressurePlate, + HeavyWeightedPressurePlate, + DaylightDetector, + RedstoneBlock, + NetherQuartzOre, + Hopper, + ChiseledQuartzBlock, + QuartzBlock, + QuartzBricks, + QuartzPillar, + QuartzStairs, + ActivatorRail, + Dropper, + WhiteTerracotta, + OrangeTerracotta, + MagentaTerracotta, + LightBlueTerracotta, + YellowTerracotta, + LimeTerracotta, + PinkTerracotta, + GrayTerracotta, + LightGrayTerracotta, + CyanTerracotta, + PurpleTerracotta, + BlueTerracotta, + BrownTerracotta, + GreenTerracotta, + RedTerracotta, + BlackTerracotta, + Barrier, + IronTrapdoor, + HayBlock, + WhiteCarpet, + OrangeCarpet, + MagentaCarpet, + LightBlueCarpet, + YellowCarpet, + LimeCarpet, + PinkCarpet, + GrayCarpet, + LightGrayCarpet, + CyanCarpet, + PurpleCarpet, + BlueCarpet, + BrownCarpet, + GreenCarpet, + RedCarpet, + BlackCarpet, + Terracotta, + CoalBlock, + PackedIce, + AcaciaStairs, + DarkOakStairs, + SlimeBlock, + GrassPath, + Sunflower, + Lilac, + RoseBush, + Peony, + TallGrass, + LargeFern, + WhiteStainedGlass, + OrangeStainedGlass, + MagentaStainedGlass, + LightBlueStainedGlass, + YellowStainedGlass, + LimeStainedGlass, + PinkStainedGlass, + GrayStainedGlass, + LightGrayStainedGlass, + CyanStainedGlass, + PurpleStainedGlass, + BlueStainedGlass, + BrownStainedGlass, + GreenStainedGlass, + RedStainedGlass, + BlackStainedGlass, + WhiteStainedGlassPane, + OrangeStainedGlassPane, + MagentaStainedGlassPane, + LightBlueStainedGlassPane, + YellowStainedGlassPane, + LimeStainedGlassPane, + PinkStainedGlassPane, + GrayStainedGlassPane, + LightGrayStainedGlassPane, + CyanStainedGlassPane, + PurpleStainedGlassPane, + BlueStainedGlassPane, + BrownStainedGlassPane, + GreenStainedGlassPane, + RedStainedGlassPane, + BlackStainedGlassPane, + Prismarine, + PrismarineBricks, + DarkPrismarine, + PrismarineStairs, + PrismarineBrickStairs, + DarkPrismarineStairs, + SeaLantern, + RedSandstone, + ChiseledRedSandstone, + CutRedSandstone, + RedSandstoneStairs, + RepeatingCommandBlock, + ChainCommandBlock, + MagmaBlock, + NetherWartBlock, + WarpedWartBlock, + RedNetherBricks, + BoneBlock, + StructureVoid, + Observer, + ShulkerBox, + WhiteShulkerBox, + OrangeShulkerBox, + MagentaShulkerBox, + LightBlueShulkerBox, + YellowShulkerBox, + LimeShulkerBox, + PinkShulkerBox, + GrayShulkerBox, + LightGrayShulkerBox, + CyanShulkerBox, + PurpleShulkerBox, + BlueShulkerBox, + BrownShulkerBox, + GreenShulkerBox, + RedShulkerBox, + BlackShulkerBox, + WhiteGlazedTerracotta, + OrangeGlazedTerracotta, + MagentaGlazedTerracotta, + LightBlueGlazedTerracotta, + YellowGlazedTerracotta, + LimeGlazedTerracotta, + PinkGlazedTerracotta, + GrayGlazedTerracotta, + LightGrayGlazedTerracotta, + CyanGlazedTerracotta, + PurpleGlazedTerracotta, + BlueGlazedTerracotta, + BrownGlazedTerracotta, + GreenGlazedTerracotta, + RedGlazedTerracotta, + BlackGlazedTerracotta, + WhiteConcrete, + OrangeConcrete, + MagentaConcrete, + LightBlueConcrete, + YellowConcrete, + LimeConcrete, + PinkConcrete, + GrayConcrete, + LightGrayConcrete, + CyanConcrete, + PurpleConcrete, + BlueConcrete, + BrownConcrete, + GreenConcrete, + RedConcrete, + BlackConcrete, + WhiteConcretePowder, + OrangeConcretePowder, + MagentaConcretePowder, + LightBlueConcretePowder, + YellowConcretePowder, + LimeConcretePowder, + PinkConcretePowder, + GrayConcretePowder, + LightGrayConcretePowder, + CyanConcretePowder, + PurpleConcretePowder, + BlueConcretePowder, + BrownConcretePowder, + GreenConcretePowder, + RedConcretePowder, + BlackConcretePowder, + TurtleEgg, + DeadTubeCoralBlock, + DeadBrainCoralBlock, + DeadBubbleCoralBlock, + DeadFireCoralBlock, + DeadHornCoralBlock, + TubeCoralBlock, + BrainCoralBlock, + BubbleCoralBlock, + FireCoralBlock, + HornCoralBlock, + TubeCoral, + BrainCoral, + BubbleCoral, + FireCoral, + HornCoral, + DeadBrainCoral, + DeadBubbleCoral, + DeadFireCoral, + DeadHornCoral, + DeadTubeCoral, + TubeCoralFan, + BrainCoralFan, + BubbleCoralFan, + FireCoralFan, + HornCoralFan, + DeadTubeCoralFan, + DeadBrainCoralFan, + DeadBubbleCoralFan, + DeadFireCoralFan, + DeadHornCoralFan, + BlueIce, + Conduit, + PolishedGraniteStairs, + SmoothRedSandstoneStairs, + MossyStoneBrickStairs, + PolishedDioriteStairs, + MossyCobblestoneStairs, + EndStoneBrickStairs, + StoneStairs, + SmoothSandstoneStairs, + SmoothQuartzStairs, + GraniteStairs, + AndesiteStairs, + RedNetherBrickStairs, + PolishedAndesiteStairs, + DioriteStairs, + PolishedGraniteSlab, + SmoothRedSandstoneSlab, + MossyStoneBrickSlab, + PolishedDioriteSlab, + MossyCobblestoneSlab, + EndStoneBrickSlab, + SmoothSandstoneSlab, + SmoothQuartzSlab, + GraniteSlab, + AndesiteSlab, + RedNetherBrickSlab, + PolishedAndesiteSlab, + DioriteSlab, + Scaffolding, + IronDoor, + OakDoor, + SpruceDoor, + BirchDoor, + JungleDoor, + AcaciaDoor, + DarkOakDoor, + CrimsonDoor, + WarpedDoor, + Repeater, + Comparator, + StructureBlock, + Jigsaw, + TurtleHelmet, + Scute, + FlintAndSteel, + Apple, + Bow, + Arrow, + Coal, + Charcoal, + Diamond, + IronIngot, + GoldIngot, + NetheriteIngot, + NetheriteScrap, + WoodenSword, + WoodenShovel, + WoodenPickaxe, + WoodenAxe, + WoodenHoe, + StoneSword, + StoneShovel, + StonePickaxe, + StoneAxe, + StoneHoe, + GoldenSword, + GoldenShovel, + GoldenPickaxe, + GoldenAxe, + GoldenHoe, + IronSword, + IronShovel, + IronPickaxe, + IronAxe, + IronHoe, + DiamondSword, + DiamondShovel, + DiamondPickaxe, + DiamondAxe, + DiamondHoe, + NetheriteSword, + NetheriteShovel, + NetheritePickaxe, + NetheriteAxe, + NetheriteHoe, + Stick, + Bowl, + MushroomStew, + String, + Feather, + Gunpowder, + WheatSeeds, + Wheat, + Bread, + LeatherHelmet, + LeatherChestplate, + LeatherLeggings, + LeatherBoots, + ChainmailHelmet, + ChainmailChestplate, + ChainmailLeggings, + ChainmailBoots, + IronHelmet, + IronChestplate, + IronLeggings, + IronBoots, + DiamondHelmet, + DiamondChestplate, + DiamondLeggings, + DiamondBoots, + GoldenHelmet, + GoldenChestplate, + GoldenLeggings, + GoldenBoots, + NetheriteHelmet, + NetheriteChestplate, + NetheriteLeggings, + NetheriteBoots, + Flint, + Porkchop, + CookedPorkchop, + Painting, + GoldenApple, + EnchantedGoldenApple, + OakSign, + SpruceSign, + BirchSign, + JungleSign, + AcaciaSign, + DarkOakSign, + CrimsonSign, + WarpedSign, + Bucket, + WaterBucket, + LavaBucket, + Minecart, + Saddle, + Redstone, + Snowball, + OakBoat, + Leather, + MilkBucket, + PufferfishBucket, + SalmonBucket, + CodBucket, + TropicalFishBucket, + Brick, + ClayBall, + DriedKelpBlock, + Paper, + Book, + SlimeBall, + ChestMinecart, + FurnaceMinecart, + Egg, + Compass, + FishingRod, + Clock, + GlowstoneDust, + Cod, + Salmon, + TropicalFish, + Pufferfish, + CookedCod, + CookedSalmon, + InkSac, + CocoaBeans, + LapisLazuli, + WhiteDye, + OrangeDye, + MagentaDye, + LightBlueDye, + YellowDye, + LimeDye, + PinkDye, + GrayDye, + LightGrayDye, + CyanDye, + PurpleDye, + BlueDye, + BrownDye, + GreenDye, + RedDye, + BlackDye, + BoneMeal, + Bone, + Sugar, + Cake, + WhiteBed, + OrangeBed, + MagentaBed, + LightBlueBed, + YellowBed, + LimeBed, + PinkBed, + GrayBed, + LightGrayBed, + CyanBed, + PurpleBed, + BlueBed, + BrownBed, + GreenBed, + RedBed, + BlackBed, + Cookie, + FilledMap, + Shears, + MelonSlice, + DriedKelp, + PumpkinSeeds, + MelonSeeds, + Beef, + CookedBeef, + Chicken, + CookedChicken, + RottenFlesh, + EnderPearl, + BlazeRod, + GhastTear, + GoldNugget, + NetherWart, + Potion, + GlassBottle, + SpiderEye, + FermentedSpiderEye, + BlazePowder, + MagmaCream, + BrewingStand, + Cauldron, + EnderEye, + GlisteringMelonSlice, + BatSpawnEgg, + BeeSpawnEgg, + BlazeSpawnEgg, + CatSpawnEgg, + CaveSpiderSpawnEgg, + ChickenSpawnEgg, + CodSpawnEgg, + CowSpawnEgg, + CreeperSpawnEgg, + DolphinSpawnEgg, + DonkeySpawnEgg, + DrownedSpawnEgg, + ElderGuardianSpawnEgg, + EndermanSpawnEgg, + EndermiteSpawnEgg, + EvokerSpawnEgg, + FoxSpawnEgg, + GhastSpawnEgg, + GuardianSpawnEgg, + HoglinSpawnEgg, + HorseSpawnEgg, + HuskSpawnEgg, + LlamaSpawnEgg, + MagmaCubeSpawnEgg, + MooshroomSpawnEgg, + MuleSpawnEgg, + OcelotSpawnEgg, + PandaSpawnEgg, + ParrotSpawnEgg, + PhantomSpawnEgg, + PigSpawnEgg, + PiglinSpawnEgg, + PiglinBruteSpawnEgg, + PillagerSpawnEgg, + PolarBearSpawnEgg, + PufferfishSpawnEgg, + RabbitSpawnEgg, + RavagerSpawnEgg, + SalmonSpawnEgg, + SheepSpawnEgg, + ShulkerSpawnEgg, + SilverfishSpawnEgg, + SkeletonSpawnEgg, + SkeletonHorseSpawnEgg, + SlimeSpawnEgg, + SpiderSpawnEgg, + SquidSpawnEgg, + StraySpawnEgg, + StriderSpawnEgg, + TraderLlamaSpawnEgg, + TropicalFishSpawnEgg, + TurtleSpawnEgg, + VexSpawnEgg, + VillagerSpawnEgg, + VindicatorSpawnEgg, + WanderingTraderSpawnEgg, + WitchSpawnEgg, + WitherSkeletonSpawnEgg, + WolfSpawnEgg, + ZoglinSpawnEgg, + ZombieSpawnEgg, + ZombieHorseSpawnEgg, + ZombieVillagerSpawnEgg, + ZombifiedPiglinSpawnEgg, + ExperienceBottle, + FireCharge, + WritableBook, + WrittenBook, + Emerald, + ItemFrame, + FlowerPot, + Carrot, + Potato, + BakedPotato, + PoisonousPotato, + Map, + GoldenCarrot, + SkeletonSkull, + WitherSkeletonSkull, + PlayerHead, + ZombieHead, + CreeperHead, + DragonHead, + CarrotOnAStick, + WarpedFungusOnAStick, + NetherStar, + PumpkinPie, + FireworkRocket, + FireworkStar, + EnchantedBook, + NetherBrick, + Quartz, + TntMinecart, + HopperMinecart, + PrismarineShard, + PrismarineCrystals, + Rabbit, + CookedRabbit, + RabbitStew, + RabbitFoot, + RabbitHide, + ArmorStand, + IronHorseArmor, + GoldenHorseArmor, + DiamondHorseArmor, + LeatherHorseArmor, + Lead, + NameTag, + CommandBlockMinecart, + Mutton, + CookedMutton, + WhiteBanner, + OrangeBanner, + MagentaBanner, + LightBlueBanner, + YellowBanner, + LimeBanner, + PinkBanner, + GrayBanner, + LightGrayBanner, + CyanBanner, + PurpleBanner, + BlueBanner, + BrownBanner, + GreenBanner, + RedBanner, + BlackBanner, + EndCrystal, + ChorusFruit, + PoppedChorusFruit, + Beetroot, + BeetrootSeeds, + BeetrootSoup, + DragonBreath, + SplashPotion, + SpectralArrow, + TippedArrow, + LingeringPotion, + Shield, + Elytra, + SpruceBoat, + BirchBoat, + JungleBoat, + AcaciaBoat, + DarkOakBoat, + TotemOfUndying, + ShulkerShell, + IronNugget, + KnowledgeBook, + DebugStick, + MusicDisc13, + MusicDiscCat, + MusicDiscBlocks, + MusicDiscChirp, + MusicDiscFar, + MusicDiscMall, + MusicDiscMellohi, + MusicDiscStal, + MusicDiscStrad, + MusicDiscWard, + MusicDisc11, + MusicDiscWait, + MusicDiscPigstep, + Trident, + PhantomMembrane, + NautilusShell, + HeartOfTheSea, + Crossbow, + SuspiciousStew, + Loom, + FlowerBannerPattern, + CreeperBannerPattern, + SkullBannerPattern, + MojangBannerPattern, + GlobeBannerPattern, + PiglinBannerPattern, + Composter, + Barrel, + Smoker, + BlastFurnace, + CartographyTable, + FletchingTable, + Grindstone, + Lectern, + SmithingTable, + Stonecutter, + Bell, + Lantern, + SoulLantern, + SweetBerries, + Campfire, + SoulCampfire, + Shroomlight, + Honeycomb, + BeeNest, + Beehive, + HoneyBottle, + HoneyBlock, + HoneycombBlock, + Lodestone, + NetheriteBlock, + AncientDebris, + Target, + CryingObsidian, + Blackstone, + BlackstoneSlab, + BlackstoneStairs, + GildedBlackstone, + PolishedBlackstone, + PolishedBlackstoneSlab, + PolishedBlackstoneStairs, + ChiseledPolishedBlackstone, + PolishedBlackstoneBricks, + PolishedBlackstoneBrickSlab, + PolishedBlackstoneBrickStairs, + CrackedPolishedBlackstoneBricks, + RespawnAnchor, +} + +#[allow(warnings)] +#[allow(clippy::all)] +impl Item { + /// Returns the `id` property of this `Item`. + pub fn id(&self) -> u32 { + match self { + Item::Air => 0, + Item::Stone => 1, + Item::Granite => 2, + Item::PolishedGranite => 3, + Item::Diorite => 4, + Item::PolishedDiorite => 5, + Item::Andesite => 6, + Item::PolishedAndesite => 7, + Item::GrassBlock => 8, + Item::Dirt => 9, + Item::CoarseDirt => 10, + Item::Podzol => 11, + Item::CrimsonNylium => 12, + Item::WarpedNylium => 13, + Item::Cobblestone => 14, + Item::OakPlanks => 15, + Item::SprucePlanks => 16, + Item::BirchPlanks => 17, + Item::JunglePlanks => 18, + Item::AcaciaPlanks => 19, + Item::DarkOakPlanks => 20, + Item::CrimsonPlanks => 21, + Item::WarpedPlanks => 22, + Item::OakSapling => 23, + Item::SpruceSapling => 24, + Item::BirchSapling => 25, + Item::JungleSapling => 26, + Item::AcaciaSapling => 27, + Item::DarkOakSapling => 28, + Item::Bedrock => 29, + Item::Sand => 30, + Item::RedSand => 31, + Item::Gravel => 32, + Item::GoldOre => 33, + Item::IronOre => 34, + Item::CoalOre => 35, + Item::NetherGoldOre => 36, + Item::OakLog => 37, + Item::SpruceLog => 38, + Item::BirchLog => 39, + Item::JungleLog => 40, + Item::AcaciaLog => 41, + Item::DarkOakLog => 42, + Item::CrimsonStem => 43, + Item::WarpedStem => 44, + Item::StrippedOakLog => 45, + Item::StrippedSpruceLog => 46, + Item::StrippedBirchLog => 47, + Item::StrippedJungleLog => 48, + Item::StrippedAcaciaLog => 49, + Item::StrippedDarkOakLog => 50, + Item::StrippedCrimsonStem => 51, + Item::StrippedWarpedStem => 52, + Item::StrippedOakWood => 53, + Item::StrippedSpruceWood => 54, + Item::StrippedBirchWood => 55, + Item::StrippedJungleWood => 56, + Item::StrippedAcaciaWood => 57, + Item::StrippedDarkOakWood => 58, + Item::StrippedCrimsonHyphae => 59, + Item::StrippedWarpedHyphae => 60, + Item::OakWood => 61, + Item::SpruceWood => 62, + Item::BirchWood => 63, + Item::JungleWood => 64, + Item::AcaciaWood => 65, + Item::DarkOakWood => 66, + Item::CrimsonHyphae => 67, + Item::WarpedHyphae => 68, + Item::OakLeaves => 69, + Item::SpruceLeaves => 70, + Item::BirchLeaves => 71, + Item::JungleLeaves => 72, + Item::AcaciaLeaves => 73, + Item::DarkOakLeaves => 74, + Item::Sponge => 75, + Item::WetSponge => 76, + Item::Glass => 77, + Item::LapisOre => 78, + Item::LapisBlock => 79, + Item::Dispenser => 80, + Item::Sandstone => 81, + Item::ChiseledSandstone => 82, + Item::CutSandstone => 83, + Item::NoteBlock => 84, + Item::PoweredRail => 85, + Item::DetectorRail => 86, + Item::StickyPiston => 87, + Item::Cobweb => 88, + Item::Grass => 89, + Item::Fern => 90, + Item::DeadBush => 91, + Item::Seagrass => 92, + Item::SeaPickle => 93, + Item::Piston => 94, + Item::WhiteWool => 95, + Item::OrangeWool => 96, + Item::MagentaWool => 97, + Item::LightBlueWool => 98, + Item::YellowWool => 99, + Item::LimeWool => 100, + Item::PinkWool => 101, + Item::GrayWool => 102, + Item::LightGrayWool => 103, + Item::CyanWool => 104, + Item::PurpleWool => 105, + Item::BlueWool => 106, + Item::BrownWool => 107, + Item::GreenWool => 108, + Item::RedWool => 109, + Item::BlackWool => 110, + Item::Dandelion => 111, + Item::Poppy => 112, + Item::BlueOrchid => 113, + Item::Allium => 114, + Item::AzureBluet => 115, + Item::RedTulip => 116, + Item::OrangeTulip => 117, + Item::WhiteTulip => 118, + Item::PinkTulip => 119, + Item::OxeyeDaisy => 120, + Item::Cornflower => 121, + Item::LilyOfTheValley => 122, + Item::WitherRose => 123, + Item::BrownMushroom => 124, + Item::RedMushroom => 125, + Item::CrimsonFungus => 126, + Item::WarpedFungus => 127, + Item::CrimsonRoots => 128, + Item::WarpedRoots => 129, + Item::NetherSprouts => 130, + Item::WeepingVines => 131, + Item::TwistingVines => 132, + Item::SugarCane => 133, + Item::Kelp => 134, + Item::Bamboo => 135, + Item::GoldBlock => 136, + Item::IronBlock => 137, + Item::OakSlab => 138, + Item::SpruceSlab => 139, + Item::BirchSlab => 140, + Item::JungleSlab => 141, + Item::AcaciaSlab => 142, + Item::DarkOakSlab => 143, + Item::CrimsonSlab => 144, + Item::WarpedSlab => 145, + Item::StoneSlab => 146, + Item::SmoothStoneSlab => 147, + Item::SandstoneSlab => 148, + Item::CutSandstoneSlab => 149, + Item::PetrifiedOakSlab => 150, + Item::CobblestoneSlab => 151, + Item::BrickSlab => 152, + Item::StoneBrickSlab => 153, + Item::NetherBrickSlab => 154, + Item::QuartzSlab => 155, + Item::RedSandstoneSlab => 156, + Item::CutRedSandstoneSlab => 157, + Item::PurpurSlab => 158, + Item::PrismarineSlab => 159, + Item::PrismarineBrickSlab => 160, + Item::DarkPrismarineSlab => 161, + Item::SmoothQuartz => 162, + Item::SmoothRedSandstone => 163, + Item::SmoothSandstone => 164, + Item::SmoothStone => 165, + Item::Bricks => 166, + Item::Tnt => 167, + Item::Bookshelf => 168, + Item::MossyCobblestone => 169, + Item::Obsidian => 170, + Item::Torch => 171, + Item::EndRod => 172, + Item::ChorusPlant => 173, + Item::ChorusFlower => 174, + Item::PurpurBlock => 175, + Item::PurpurPillar => 176, + Item::PurpurStairs => 177, + Item::Spawner => 178, + Item::OakStairs => 179, + Item::Chest => 180, + Item::DiamondOre => 181, + Item::DiamondBlock => 182, + Item::CraftingTable => 183, + Item::Farmland => 184, + Item::Furnace => 185, + Item::Ladder => 186, + Item::Rail => 187, + Item::CobblestoneStairs => 188, + Item::Lever => 189, + Item::StonePressurePlate => 190, + Item::OakPressurePlate => 191, + Item::SprucePressurePlate => 192, + Item::BirchPressurePlate => 193, + Item::JunglePressurePlate => 194, + Item::AcaciaPressurePlate => 195, + Item::DarkOakPressurePlate => 196, + Item::CrimsonPressurePlate => 197, + Item::WarpedPressurePlate => 198, + Item::PolishedBlackstonePressurePlate => 199, + Item::RedstoneOre => 200, + Item::RedstoneTorch => 201, + Item::Snow => 202, + Item::Ice => 203, + Item::SnowBlock => 204, + Item::Cactus => 205, + Item::Clay => 206, + Item::Jukebox => 207, + Item::OakFence => 208, + Item::SpruceFence => 209, + Item::BirchFence => 210, + Item::JungleFence => 211, + Item::AcaciaFence => 212, + Item::DarkOakFence => 213, + Item::CrimsonFence => 214, + Item::WarpedFence => 215, + Item::Pumpkin => 216, + Item::CarvedPumpkin => 217, + Item::Netherrack => 218, + Item::SoulSand => 219, + Item::SoulSoil => 220, + Item::Basalt => 221, + Item::PolishedBasalt => 222, + Item::SoulTorch => 223, + Item::Glowstone => 224, + Item::JackOLantern => 225, + Item::OakTrapdoor => 226, + Item::SpruceTrapdoor => 227, + Item::BirchTrapdoor => 228, + Item::JungleTrapdoor => 229, + Item::AcaciaTrapdoor => 230, + Item::DarkOakTrapdoor => 231, + Item::CrimsonTrapdoor => 232, + Item::WarpedTrapdoor => 233, + Item::InfestedStone => 234, + Item::InfestedCobblestone => 235, + Item::InfestedStoneBricks => 236, + Item::InfestedMossyStoneBricks => 237, + Item::InfestedCrackedStoneBricks => 238, + Item::InfestedChiseledStoneBricks => 239, + Item::StoneBricks => 240, + Item::MossyStoneBricks => 241, + Item::CrackedStoneBricks => 242, + Item::ChiseledStoneBricks => 243, + Item::BrownMushroomBlock => 244, + Item::RedMushroomBlock => 245, + Item::MushroomStem => 246, + Item::IronBars => 247, + Item::Chain => 248, + Item::GlassPane => 249, + Item::Melon => 250, + Item::Vine => 251, + Item::OakFenceGate => 252, + Item::SpruceFenceGate => 253, + Item::BirchFenceGate => 254, + Item::JungleFenceGate => 255, + Item::AcaciaFenceGate => 256, + Item::DarkOakFenceGate => 257, + Item::CrimsonFenceGate => 258, + Item::WarpedFenceGate => 259, + Item::BrickStairs => 260, + Item::StoneBrickStairs => 261, + Item::Mycelium => 262, + Item::LilyPad => 263, + Item::NetherBricks => 264, + Item::CrackedNetherBricks => 265, + Item::ChiseledNetherBricks => 266, + Item::NetherBrickFence => 267, + Item::NetherBrickStairs => 268, + Item::EnchantingTable => 269, + Item::EndPortalFrame => 270, + Item::EndStone => 271, + Item::EndStoneBricks => 272, + Item::DragonEgg => 273, + Item::RedstoneLamp => 274, + Item::SandstoneStairs => 275, + Item::EmeraldOre => 276, + Item::EnderChest => 277, + Item::TripwireHook => 278, + Item::EmeraldBlock => 279, + Item::SpruceStairs => 280, + Item::BirchStairs => 281, + Item::JungleStairs => 282, + Item::CrimsonStairs => 283, + Item::WarpedStairs => 284, + Item::CommandBlock => 285, + Item::Beacon => 286, + Item::CobblestoneWall => 287, + Item::MossyCobblestoneWall => 288, + Item::BrickWall => 289, + Item::PrismarineWall => 290, + Item::RedSandstoneWall => 291, + Item::MossyStoneBrickWall => 292, + Item::GraniteWall => 293, + Item::StoneBrickWall => 294, + Item::NetherBrickWall => 295, + Item::AndesiteWall => 296, + Item::RedNetherBrickWall => 297, + Item::SandstoneWall => 298, + Item::EndStoneBrickWall => 299, + Item::DioriteWall => 300, + Item::BlackstoneWall => 301, + Item::PolishedBlackstoneWall => 302, + Item::PolishedBlackstoneBrickWall => 303, + Item::StoneButton => 304, + Item::OakButton => 305, + Item::SpruceButton => 306, + Item::BirchButton => 307, + Item::JungleButton => 308, + Item::AcaciaButton => 309, + Item::DarkOakButton => 310, + Item::CrimsonButton => 311, + Item::WarpedButton => 312, + Item::PolishedBlackstoneButton => 313, + Item::Anvil => 314, + Item::ChippedAnvil => 315, + Item::DamagedAnvil => 316, + Item::TrappedChest => 317, + Item::LightWeightedPressurePlate => 318, + Item::HeavyWeightedPressurePlate => 319, + Item::DaylightDetector => 320, + Item::RedstoneBlock => 321, + Item::NetherQuartzOre => 322, + Item::Hopper => 323, + Item::ChiseledQuartzBlock => 324, + Item::QuartzBlock => 325, + Item::QuartzBricks => 326, + Item::QuartzPillar => 327, + Item::QuartzStairs => 328, + Item::ActivatorRail => 329, + Item::Dropper => 330, + Item::WhiteTerracotta => 331, + Item::OrangeTerracotta => 332, + Item::MagentaTerracotta => 333, + Item::LightBlueTerracotta => 334, + Item::YellowTerracotta => 335, + Item::LimeTerracotta => 336, + Item::PinkTerracotta => 337, + Item::GrayTerracotta => 338, + Item::LightGrayTerracotta => 339, + Item::CyanTerracotta => 340, + Item::PurpleTerracotta => 341, + Item::BlueTerracotta => 342, + Item::BrownTerracotta => 343, + Item::GreenTerracotta => 344, + Item::RedTerracotta => 345, + Item::BlackTerracotta => 346, + Item::Barrier => 347, + Item::IronTrapdoor => 348, + Item::HayBlock => 349, + Item::WhiteCarpet => 350, + Item::OrangeCarpet => 351, + Item::MagentaCarpet => 352, + Item::LightBlueCarpet => 353, + Item::YellowCarpet => 354, + Item::LimeCarpet => 355, + Item::PinkCarpet => 356, + Item::GrayCarpet => 357, + Item::LightGrayCarpet => 358, + Item::CyanCarpet => 359, + Item::PurpleCarpet => 360, + Item::BlueCarpet => 361, + Item::BrownCarpet => 362, + Item::GreenCarpet => 363, + Item::RedCarpet => 364, + Item::BlackCarpet => 365, + Item::Terracotta => 366, + Item::CoalBlock => 367, + Item::PackedIce => 368, + Item::AcaciaStairs => 369, + Item::DarkOakStairs => 370, + Item::SlimeBlock => 371, + Item::GrassPath => 372, + Item::Sunflower => 373, + Item::Lilac => 374, + Item::RoseBush => 375, + Item::Peony => 376, + Item::TallGrass => 377, + Item::LargeFern => 378, + Item::WhiteStainedGlass => 379, + Item::OrangeStainedGlass => 380, + Item::MagentaStainedGlass => 381, + Item::LightBlueStainedGlass => 382, + Item::YellowStainedGlass => 383, + Item::LimeStainedGlass => 384, + Item::PinkStainedGlass => 385, + Item::GrayStainedGlass => 386, + Item::LightGrayStainedGlass => 387, + Item::CyanStainedGlass => 388, + Item::PurpleStainedGlass => 389, + Item::BlueStainedGlass => 390, + Item::BrownStainedGlass => 391, + Item::GreenStainedGlass => 392, + Item::RedStainedGlass => 393, + Item::BlackStainedGlass => 394, + Item::WhiteStainedGlassPane => 395, + Item::OrangeStainedGlassPane => 396, + Item::MagentaStainedGlassPane => 397, + Item::LightBlueStainedGlassPane => 398, + Item::YellowStainedGlassPane => 399, + Item::LimeStainedGlassPane => 400, + Item::PinkStainedGlassPane => 401, + Item::GrayStainedGlassPane => 402, + Item::LightGrayStainedGlassPane => 403, + Item::CyanStainedGlassPane => 404, + Item::PurpleStainedGlassPane => 405, + Item::BlueStainedGlassPane => 406, + Item::BrownStainedGlassPane => 407, + Item::GreenStainedGlassPane => 408, + Item::RedStainedGlassPane => 409, + Item::BlackStainedGlassPane => 410, + Item::Prismarine => 411, + Item::PrismarineBricks => 412, + Item::DarkPrismarine => 413, + Item::PrismarineStairs => 414, + Item::PrismarineBrickStairs => 415, + Item::DarkPrismarineStairs => 416, + Item::SeaLantern => 417, + Item::RedSandstone => 418, + Item::ChiseledRedSandstone => 419, + Item::CutRedSandstone => 420, + Item::RedSandstoneStairs => 421, + Item::RepeatingCommandBlock => 422, + Item::ChainCommandBlock => 423, + Item::MagmaBlock => 424, + Item::NetherWartBlock => 425, + Item::WarpedWartBlock => 426, + Item::RedNetherBricks => 427, + Item::BoneBlock => 428, + Item::StructureVoid => 429, + Item::Observer => 430, + Item::ShulkerBox => 431, + Item::WhiteShulkerBox => 432, + Item::OrangeShulkerBox => 433, + Item::MagentaShulkerBox => 434, + Item::LightBlueShulkerBox => 435, + Item::YellowShulkerBox => 436, + Item::LimeShulkerBox => 437, + Item::PinkShulkerBox => 438, + Item::GrayShulkerBox => 439, + Item::LightGrayShulkerBox => 440, + Item::CyanShulkerBox => 441, + Item::PurpleShulkerBox => 442, + Item::BlueShulkerBox => 443, + Item::BrownShulkerBox => 444, + Item::GreenShulkerBox => 445, + Item::RedShulkerBox => 446, + Item::BlackShulkerBox => 447, + Item::WhiteGlazedTerracotta => 448, + Item::OrangeGlazedTerracotta => 449, + Item::MagentaGlazedTerracotta => 450, + Item::LightBlueGlazedTerracotta => 451, + Item::YellowGlazedTerracotta => 452, + Item::LimeGlazedTerracotta => 453, + Item::PinkGlazedTerracotta => 454, + Item::GrayGlazedTerracotta => 455, + Item::LightGrayGlazedTerracotta => 456, + Item::CyanGlazedTerracotta => 457, + Item::PurpleGlazedTerracotta => 458, + Item::BlueGlazedTerracotta => 459, + Item::BrownGlazedTerracotta => 460, + Item::GreenGlazedTerracotta => 461, + Item::RedGlazedTerracotta => 462, + Item::BlackGlazedTerracotta => 463, + Item::WhiteConcrete => 464, + Item::OrangeConcrete => 465, + Item::MagentaConcrete => 466, + Item::LightBlueConcrete => 467, + Item::YellowConcrete => 468, + Item::LimeConcrete => 469, + Item::PinkConcrete => 470, + Item::GrayConcrete => 471, + Item::LightGrayConcrete => 472, + Item::CyanConcrete => 473, + Item::PurpleConcrete => 474, + Item::BlueConcrete => 475, + Item::BrownConcrete => 476, + Item::GreenConcrete => 477, + Item::RedConcrete => 478, + Item::BlackConcrete => 479, + Item::WhiteConcretePowder => 480, + Item::OrangeConcretePowder => 481, + Item::MagentaConcretePowder => 482, + Item::LightBlueConcretePowder => 483, + Item::YellowConcretePowder => 484, + Item::LimeConcretePowder => 485, + Item::PinkConcretePowder => 486, + Item::GrayConcretePowder => 487, + Item::LightGrayConcretePowder => 488, + Item::CyanConcretePowder => 489, + Item::PurpleConcretePowder => 490, + Item::BlueConcretePowder => 491, + Item::BrownConcretePowder => 492, + Item::GreenConcretePowder => 493, + Item::RedConcretePowder => 494, + Item::BlackConcretePowder => 495, + Item::TurtleEgg => 496, + Item::DeadTubeCoralBlock => 497, + Item::DeadBrainCoralBlock => 498, + Item::DeadBubbleCoralBlock => 499, + Item::DeadFireCoralBlock => 500, + Item::DeadHornCoralBlock => 501, + Item::TubeCoralBlock => 502, + Item::BrainCoralBlock => 503, + Item::BubbleCoralBlock => 504, + Item::FireCoralBlock => 505, + Item::HornCoralBlock => 506, + Item::TubeCoral => 507, + Item::BrainCoral => 508, + Item::BubbleCoral => 509, + Item::FireCoral => 510, + Item::HornCoral => 511, + Item::DeadBrainCoral => 512, + Item::DeadBubbleCoral => 513, + Item::DeadFireCoral => 514, + Item::DeadHornCoral => 515, + Item::DeadTubeCoral => 516, + Item::TubeCoralFan => 517, + Item::BrainCoralFan => 518, + Item::BubbleCoralFan => 519, + Item::FireCoralFan => 520, + Item::HornCoralFan => 521, + Item::DeadTubeCoralFan => 522, + Item::DeadBrainCoralFan => 523, + Item::DeadBubbleCoralFan => 524, + Item::DeadFireCoralFan => 525, + Item::DeadHornCoralFan => 526, + Item::BlueIce => 527, + Item::Conduit => 528, + Item::PolishedGraniteStairs => 529, + Item::SmoothRedSandstoneStairs => 530, + Item::MossyStoneBrickStairs => 531, + Item::PolishedDioriteStairs => 532, + Item::MossyCobblestoneStairs => 533, + Item::EndStoneBrickStairs => 534, + Item::StoneStairs => 535, + Item::SmoothSandstoneStairs => 536, + Item::SmoothQuartzStairs => 537, + Item::GraniteStairs => 538, + Item::AndesiteStairs => 539, + Item::RedNetherBrickStairs => 540, + Item::PolishedAndesiteStairs => 541, + Item::DioriteStairs => 542, + Item::PolishedGraniteSlab => 543, + Item::SmoothRedSandstoneSlab => 544, + Item::MossyStoneBrickSlab => 545, + Item::PolishedDioriteSlab => 546, + Item::MossyCobblestoneSlab => 547, + Item::EndStoneBrickSlab => 548, + Item::SmoothSandstoneSlab => 549, + Item::SmoothQuartzSlab => 550, + Item::GraniteSlab => 551, + Item::AndesiteSlab => 552, + Item::RedNetherBrickSlab => 553, + Item::PolishedAndesiteSlab => 554, + Item::DioriteSlab => 555, + Item::Scaffolding => 556, + Item::IronDoor => 557, + Item::OakDoor => 558, + Item::SpruceDoor => 559, + Item::BirchDoor => 560, + Item::JungleDoor => 561, + Item::AcaciaDoor => 562, + Item::DarkOakDoor => 563, + Item::CrimsonDoor => 564, + Item::WarpedDoor => 565, + Item::Repeater => 566, + Item::Comparator => 567, + Item::StructureBlock => 568, + Item::Jigsaw => 569, + Item::TurtleHelmet => 570, + Item::Scute => 571, + Item::FlintAndSteel => 572, + Item::Apple => 573, + Item::Bow => 574, + Item::Arrow => 575, + Item::Coal => 576, + Item::Charcoal => 577, + Item::Diamond => 578, + Item::IronIngot => 579, + Item::GoldIngot => 580, + Item::NetheriteIngot => 581, + Item::NetheriteScrap => 582, + Item::WoodenSword => 583, + Item::WoodenShovel => 584, + Item::WoodenPickaxe => 585, + Item::WoodenAxe => 586, + Item::WoodenHoe => 587, + Item::StoneSword => 588, + Item::StoneShovel => 589, + Item::StonePickaxe => 590, + Item::StoneAxe => 591, + Item::StoneHoe => 592, + Item::GoldenSword => 593, + Item::GoldenShovel => 594, + Item::GoldenPickaxe => 595, + Item::GoldenAxe => 596, + Item::GoldenHoe => 597, + Item::IronSword => 598, + Item::IronShovel => 599, + Item::IronPickaxe => 600, + Item::IronAxe => 601, + Item::IronHoe => 602, + Item::DiamondSword => 603, + Item::DiamondShovel => 604, + Item::DiamondPickaxe => 605, + Item::DiamondAxe => 606, + Item::DiamondHoe => 607, + Item::NetheriteSword => 608, + Item::NetheriteShovel => 609, + Item::NetheritePickaxe => 610, + Item::NetheriteAxe => 611, + Item::NetheriteHoe => 612, + Item::Stick => 613, + Item::Bowl => 614, + Item::MushroomStew => 615, + Item::String => 616, + Item::Feather => 617, + Item::Gunpowder => 618, + Item::WheatSeeds => 619, + Item::Wheat => 620, + Item::Bread => 621, + Item::LeatherHelmet => 622, + Item::LeatherChestplate => 623, + Item::LeatherLeggings => 624, + Item::LeatherBoots => 625, + Item::ChainmailHelmet => 626, + Item::ChainmailChestplate => 627, + Item::ChainmailLeggings => 628, + Item::ChainmailBoots => 629, + Item::IronHelmet => 630, + Item::IronChestplate => 631, + Item::IronLeggings => 632, + Item::IronBoots => 633, + Item::DiamondHelmet => 634, + Item::DiamondChestplate => 635, + Item::DiamondLeggings => 636, + Item::DiamondBoots => 637, + Item::GoldenHelmet => 638, + Item::GoldenChestplate => 639, + Item::GoldenLeggings => 640, + Item::GoldenBoots => 641, + Item::NetheriteHelmet => 642, + Item::NetheriteChestplate => 643, + Item::NetheriteLeggings => 644, + Item::NetheriteBoots => 645, + Item::Flint => 646, + Item::Porkchop => 647, + Item::CookedPorkchop => 648, + Item::Painting => 649, + Item::GoldenApple => 650, + Item::EnchantedGoldenApple => 651, + Item::OakSign => 652, + Item::SpruceSign => 653, + Item::BirchSign => 654, + Item::JungleSign => 655, + Item::AcaciaSign => 656, + Item::DarkOakSign => 657, + Item::CrimsonSign => 658, + Item::WarpedSign => 659, + Item::Bucket => 660, + Item::WaterBucket => 661, + Item::LavaBucket => 662, + Item::Minecart => 663, + Item::Saddle => 664, + Item::Redstone => 665, + Item::Snowball => 666, + Item::OakBoat => 667, + Item::Leather => 668, + Item::MilkBucket => 669, + Item::PufferfishBucket => 670, + Item::SalmonBucket => 671, + Item::CodBucket => 672, + Item::TropicalFishBucket => 673, + Item::Brick => 674, + Item::ClayBall => 675, + Item::DriedKelpBlock => 676, + Item::Paper => 677, + Item::Book => 678, + Item::SlimeBall => 679, + Item::ChestMinecart => 680, + Item::FurnaceMinecart => 681, + Item::Egg => 682, + Item::Compass => 683, + Item::FishingRod => 684, + Item::Clock => 685, + Item::GlowstoneDust => 686, + Item::Cod => 687, + Item::Salmon => 688, + Item::TropicalFish => 689, + Item::Pufferfish => 690, + Item::CookedCod => 691, + Item::CookedSalmon => 692, + Item::InkSac => 693, + Item::CocoaBeans => 694, + Item::LapisLazuli => 695, + Item::WhiteDye => 696, + Item::OrangeDye => 697, + Item::MagentaDye => 698, + Item::LightBlueDye => 699, + Item::YellowDye => 700, + Item::LimeDye => 701, + Item::PinkDye => 702, + Item::GrayDye => 703, + Item::LightGrayDye => 704, + Item::CyanDye => 705, + Item::PurpleDye => 706, + Item::BlueDye => 707, + Item::BrownDye => 708, + Item::GreenDye => 709, + Item::RedDye => 710, + Item::BlackDye => 711, + Item::BoneMeal => 712, + Item::Bone => 713, + Item::Sugar => 714, + Item::Cake => 715, + Item::WhiteBed => 716, + Item::OrangeBed => 717, + Item::MagentaBed => 718, + Item::LightBlueBed => 719, + Item::YellowBed => 720, + Item::LimeBed => 721, + Item::PinkBed => 722, + Item::GrayBed => 723, + Item::LightGrayBed => 724, + Item::CyanBed => 725, + Item::PurpleBed => 726, + Item::BlueBed => 727, + Item::BrownBed => 728, + Item::GreenBed => 729, + Item::RedBed => 730, + Item::BlackBed => 731, + Item::Cookie => 732, + Item::FilledMap => 733, + Item::Shears => 734, + Item::MelonSlice => 735, + Item::DriedKelp => 736, + Item::PumpkinSeeds => 737, + Item::MelonSeeds => 738, + Item::Beef => 739, + Item::CookedBeef => 740, + Item::Chicken => 741, + Item::CookedChicken => 742, + Item::RottenFlesh => 743, + Item::EnderPearl => 744, + Item::BlazeRod => 745, + Item::GhastTear => 746, + Item::GoldNugget => 747, + Item::NetherWart => 748, + Item::Potion => 749, + Item::GlassBottle => 750, + Item::SpiderEye => 751, + Item::FermentedSpiderEye => 752, + Item::BlazePowder => 753, + Item::MagmaCream => 754, + Item::BrewingStand => 755, + Item::Cauldron => 756, + Item::EnderEye => 757, + Item::GlisteringMelonSlice => 758, + Item::BatSpawnEgg => 759, + Item::BeeSpawnEgg => 760, + Item::BlazeSpawnEgg => 761, + Item::CatSpawnEgg => 762, + Item::CaveSpiderSpawnEgg => 763, + Item::ChickenSpawnEgg => 764, + Item::CodSpawnEgg => 765, + Item::CowSpawnEgg => 766, + Item::CreeperSpawnEgg => 767, + Item::DolphinSpawnEgg => 768, + Item::DonkeySpawnEgg => 769, + Item::DrownedSpawnEgg => 770, + Item::ElderGuardianSpawnEgg => 771, + Item::EndermanSpawnEgg => 772, + Item::EndermiteSpawnEgg => 773, + Item::EvokerSpawnEgg => 774, + Item::FoxSpawnEgg => 775, + Item::GhastSpawnEgg => 776, + Item::GuardianSpawnEgg => 777, + Item::HoglinSpawnEgg => 778, + Item::HorseSpawnEgg => 779, + Item::HuskSpawnEgg => 780, + Item::LlamaSpawnEgg => 781, + Item::MagmaCubeSpawnEgg => 782, + Item::MooshroomSpawnEgg => 783, + Item::MuleSpawnEgg => 784, + Item::OcelotSpawnEgg => 785, + Item::PandaSpawnEgg => 786, + Item::ParrotSpawnEgg => 787, + Item::PhantomSpawnEgg => 788, + Item::PigSpawnEgg => 789, + Item::PiglinSpawnEgg => 790, + Item::PiglinBruteSpawnEgg => 791, + Item::PillagerSpawnEgg => 792, + Item::PolarBearSpawnEgg => 793, + Item::PufferfishSpawnEgg => 794, + Item::RabbitSpawnEgg => 795, + Item::RavagerSpawnEgg => 796, + Item::SalmonSpawnEgg => 797, + Item::SheepSpawnEgg => 798, + Item::ShulkerSpawnEgg => 799, + Item::SilverfishSpawnEgg => 800, + Item::SkeletonSpawnEgg => 801, + Item::SkeletonHorseSpawnEgg => 802, + Item::SlimeSpawnEgg => 803, + Item::SpiderSpawnEgg => 804, + Item::SquidSpawnEgg => 805, + Item::StraySpawnEgg => 806, + Item::StriderSpawnEgg => 807, + Item::TraderLlamaSpawnEgg => 808, + Item::TropicalFishSpawnEgg => 809, + Item::TurtleSpawnEgg => 810, + Item::VexSpawnEgg => 811, + Item::VillagerSpawnEgg => 812, + Item::VindicatorSpawnEgg => 813, + Item::WanderingTraderSpawnEgg => 814, + Item::WitchSpawnEgg => 815, + Item::WitherSkeletonSpawnEgg => 816, + Item::WolfSpawnEgg => 817, + Item::ZoglinSpawnEgg => 818, + Item::ZombieSpawnEgg => 819, + Item::ZombieHorseSpawnEgg => 820, + Item::ZombieVillagerSpawnEgg => 821, + Item::ZombifiedPiglinSpawnEgg => 822, + Item::ExperienceBottle => 823, + Item::FireCharge => 824, + Item::WritableBook => 825, + Item::WrittenBook => 826, + Item::Emerald => 827, + Item::ItemFrame => 828, + Item::FlowerPot => 829, + Item::Carrot => 830, + Item::Potato => 831, + Item::BakedPotato => 832, + Item::PoisonousPotato => 833, + Item::Map => 834, + Item::GoldenCarrot => 835, + Item::SkeletonSkull => 836, + Item::WitherSkeletonSkull => 837, + Item::PlayerHead => 838, + Item::ZombieHead => 839, + Item::CreeperHead => 840, + Item::DragonHead => 841, + Item::CarrotOnAStick => 842, + Item::WarpedFungusOnAStick => 843, + Item::NetherStar => 844, + Item::PumpkinPie => 845, + Item::FireworkRocket => 846, + Item::FireworkStar => 847, + Item::EnchantedBook => 848, + Item::NetherBrick => 849, + Item::Quartz => 850, + Item::TntMinecart => 851, + Item::HopperMinecart => 852, + Item::PrismarineShard => 853, + Item::PrismarineCrystals => 854, + Item::Rabbit => 855, + Item::CookedRabbit => 856, + Item::RabbitStew => 857, + Item::RabbitFoot => 858, + Item::RabbitHide => 859, + Item::ArmorStand => 860, + Item::IronHorseArmor => 861, + Item::GoldenHorseArmor => 862, + Item::DiamondHorseArmor => 863, + Item::LeatherHorseArmor => 864, + Item::Lead => 865, + Item::NameTag => 866, + Item::CommandBlockMinecart => 867, + Item::Mutton => 868, + Item::CookedMutton => 869, + Item::WhiteBanner => 870, + Item::OrangeBanner => 871, + Item::MagentaBanner => 872, + Item::LightBlueBanner => 873, + Item::YellowBanner => 874, + Item::LimeBanner => 875, + Item::PinkBanner => 876, + Item::GrayBanner => 877, + Item::LightGrayBanner => 878, + Item::CyanBanner => 879, + Item::PurpleBanner => 880, + Item::BlueBanner => 881, + Item::BrownBanner => 882, + Item::GreenBanner => 883, + Item::RedBanner => 884, + Item::BlackBanner => 885, + Item::EndCrystal => 886, + Item::ChorusFruit => 887, + Item::PoppedChorusFruit => 888, + Item::Beetroot => 889, + Item::BeetrootSeeds => 890, + Item::BeetrootSoup => 891, + Item::DragonBreath => 892, + Item::SplashPotion => 893, + Item::SpectralArrow => 894, + Item::TippedArrow => 895, + Item::LingeringPotion => 896, + Item::Shield => 897, + Item::Elytra => 898, + Item::SpruceBoat => 899, + Item::BirchBoat => 900, + Item::JungleBoat => 901, + Item::AcaciaBoat => 902, + Item::DarkOakBoat => 903, + Item::TotemOfUndying => 904, + Item::ShulkerShell => 905, + Item::IronNugget => 906, + Item::KnowledgeBook => 907, + Item::DebugStick => 908, + Item::MusicDisc13 => 909, + Item::MusicDiscCat => 910, + Item::MusicDiscBlocks => 911, + Item::MusicDiscChirp => 912, + Item::MusicDiscFar => 913, + Item::MusicDiscMall => 914, + Item::MusicDiscMellohi => 915, + Item::MusicDiscStal => 916, + Item::MusicDiscStrad => 917, + Item::MusicDiscWard => 918, + Item::MusicDisc11 => 919, + Item::MusicDiscWait => 920, + Item::MusicDiscPigstep => 921, + Item::Trident => 922, + Item::PhantomMembrane => 923, + Item::NautilusShell => 924, + Item::HeartOfTheSea => 925, + Item::Crossbow => 926, + Item::SuspiciousStew => 927, + Item::Loom => 928, + Item::FlowerBannerPattern => 929, + Item::CreeperBannerPattern => 930, + Item::SkullBannerPattern => 931, + Item::MojangBannerPattern => 932, + Item::GlobeBannerPattern => 933, + Item::PiglinBannerPattern => 934, + Item::Composter => 935, + Item::Barrel => 936, + Item::Smoker => 937, + Item::BlastFurnace => 938, + Item::CartographyTable => 939, + Item::FletchingTable => 940, + Item::Grindstone => 941, + Item::Lectern => 942, + Item::SmithingTable => 943, + Item::Stonecutter => 944, + Item::Bell => 945, + Item::Lantern => 946, + Item::SoulLantern => 947, + Item::SweetBerries => 948, + Item::Campfire => 949, + Item::SoulCampfire => 950, + Item::Shroomlight => 951, + Item::Honeycomb => 952, + Item::BeeNest => 953, + Item::Beehive => 954, + Item::HoneyBottle => 955, + Item::HoneyBlock => 956, + Item::HoneycombBlock => 957, + Item::Lodestone => 958, + Item::NetheriteBlock => 959, + Item::AncientDebris => 960, + Item::Target => 961, + Item::CryingObsidian => 962, + Item::Blackstone => 963, + Item::BlackstoneSlab => 964, + Item::BlackstoneStairs => 965, + Item::GildedBlackstone => 966, + Item::PolishedBlackstone => 967, + Item::PolishedBlackstoneSlab => 968, + Item::PolishedBlackstoneStairs => 969, + Item::ChiseledPolishedBlackstone => 970, + Item::PolishedBlackstoneBricks => 971, + Item::PolishedBlackstoneBrickSlab => 972, + Item::PolishedBlackstoneBrickStairs => 973, + Item::CrackedPolishedBlackstoneBricks => 974, + Item::RespawnAnchor => 975, + } + } + + /// Gets a `Item` by its `id`. + pub fn from_id(id: u32) -> Option<Self> { + match id { + 0 => Some(Item::Air), + 1 => Some(Item::Stone), + 2 => Some(Item::Granite), + 3 => Some(Item::PolishedGranite), + 4 => Some(Item::Diorite), + 5 => Some(Item::PolishedDiorite), + 6 => Some(Item::Andesite), + 7 => Some(Item::PolishedAndesite), + 8 => Some(Item::GrassBlock), + 9 => Some(Item::Dirt), + 10 => Some(Item::CoarseDirt), + 11 => Some(Item::Podzol), + 12 => Some(Item::CrimsonNylium), + 13 => Some(Item::WarpedNylium), + 14 => Some(Item::Cobblestone), + 15 => Some(Item::OakPlanks), + 16 => Some(Item::SprucePlanks), + 17 => Some(Item::BirchPlanks), + 18 => Some(Item::JunglePlanks), + 19 => Some(Item::AcaciaPlanks), + 20 => Some(Item::DarkOakPlanks), + 21 => Some(Item::CrimsonPlanks), + 22 => Some(Item::WarpedPlanks), + 23 => Some(Item::OakSapling), + 24 => Some(Item::SpruceSapling), + 25 => Some(Item::BirchSapling), + 26 => Some(Item::JungleSapling), + 27 => Some(Item::AcaciaSapling), + 28 => Some(Item::DarkOakSapling), + 29 => Some(Item::Bedrock), + 30 => Some(Item::Sand), + 31 => Some(Item::RedSand), + 32 => Some(Item::Gravel), + 33 => Some(Item::GoldOre), + 34 => Some(Item::IronOre), + 35 => Some(Item::CoalOre), + 36 => Some(Item::NetherGoldOre), + 37 => Some(Item::OakLog), + 38 => Some(Item::SpruceLog), + 39 => Some(Item::BirchLog), + 40 => Some(Item::JungleLog), + 41 => Some(Item::AcaciaLog), + 42 => Some(Item::DarkOakLog), + 43 => Some(Item::CrimsonStem), + 44 => Some(Item::WarpedStem), + 45 => Some(Item::StrippedOakLog), + 46 => Some(Item::StrippedSpruceLog), + 47 => Some(Item::StrippedBirchLog), + 48 => Some(Item::StrippedJungleLog), + 49 => Some(Item::StrippedAcaciaLog), + 50 => Some(Item::StrippedDarkOakLog), + 51 => Some(Item::StrippedCrimsonStem), + 52 => Some(Item::StrippedWarpedStem), + 53 => Some(Item::StrippedOakWood), + 54 => Some(Item::StrippedSpruceWood), + 55 => Some(Item::StrippedBirchWood), + 56 => Some(Item::StrippedJungleWood), + 57 => Some(Item::StrippedAcaciaWood), + 58 => Some(Item::StrippedDarkOakWood), + 59 => Some(Item::StrippedCrimsonHyphae), + 60 => Some(Item::StrippedWarpedHyphae), + 61 => Some(Item::OakWood), + 62 => Some(Item::SpruceWood), + 63 => Some(Item::BirchWood), + 64 => Some(Item::JungleWood), + 65 => Some(Item::AcaciaWood), + 66 => Some(Item::DarkOakWood), + 67 => Some(Item::CrimsonHyphae), + 68 => Some(Item::WarpedHyphae), + 69 => Some(Item::OakLeaves), + 70 => Some(Item::SpruceLeaves), + 71 => Some(Item::BirchLeaves), + 72 => Some(Item::JungleLeaves), + 73 => Some(Item::AcaciaLeaves), + 74 => Some(Item::DarkOakLeaves), + 75 => Some(Item::Sponge), + 76 => Some(Item::WetSponge), + 77 => Some(Item::Glass), + 78 => Some(Item::LapisOre), + 79 => Some(Item::LapisBlock), + 80 => Some(Item::Dispenser), + 81 => Some(Item::Sandstone), + 82 => Some(Item::ChiseledSandstone), + 83 => Some(Item::CutSandstone), + 84 => Some(Item::NoteBlock), + 85 => Some(Item::PoweredRail), + 86 => Some(Item::DetectorRail), + 87 => Some(Item::StickyPiston), + 88 => Some(Item::Cobweb), + 89 => Some(Item::Grass), + 90 => Some(Item::Fern), + 91 => Some(Item::DeadBush), + 92 => Some(Item::Seagrass), + 93 => Some(Item::SeaPickle), + 94 => Some(Item::Piston), + 95 => Some(Item::WhiteWool), + 96 => Some(Item::OrangeWool), + 97 => Some(Item::MagentaWool), + 98 => Some(Item::LightBlueWool), + 99 => Some(Item::YellowWool), + 100 => Some(Item::LimeWool), + 101 => Some(Item::PinkWool), + 102 => Some(Item::GrayWool), + 103 => Some(Item::LightGrayWool), + 104 => Some(Item::CyanWool), + 105 => Some(Item::PurpleWool), + 106 => Some(Item::BlueWool), + 107 => Some(Item::BrownWool), + 108 => Some(Item::GreenWool), + 109 => Some(Item::RedWool), + 110 => Some(Item::BlackWool), + 111 => Some(Item::Dandelion), + 112 => Some(Item::Poppy), + 113 => Some(Item::BlueOrchid), + 114 => Some(Item::Allium), + 115 => Some(Item::AzureBluet), + 116 => Some(Item::RedTulip), + 117 => Some(Item::OrangeTulip), + 118 => Some(Item::WhiteTulip), + 119 => Some(Item::PinkTulip), + 120 => Some(Item::OxeyeDaisy), + 121 => Some(Item::Cornflower), + 122 => Some(Item::LilyOfTheValley), + 123 => Some(Item::WitherRose), + 124 => Some(Item::BrownMushroom), + 125 => Some(Item::RedMushroom), + 126 => Some(Item::CrimsonFungus), + 127 => Some(Item::WarpedFungus), + 128 => Some(Item::CrimsonRoots), + 129 => Some(Item::WarpedRoots), + 130 => Some(Item::NetherSprouts), + 131 => Some(Item::WeepingVines), + 132 => Some(Item::TwistingVines), + 133 => Some(Item::SugarCane), + 134 => Some(Item::Kelp), + 135 => Some(Item::Bamboo), + 136 => Some(Item::GoldBlock), + 137 => Some(Item::IronBlock), + 138 => Some(Item::OakSlab), + 139 => Some(Item::SpruceSlab), + 140 => Some(Item::BirchSlab), + 141 => Some(Item::JungleSlab), + 142 => Some(Item::AcaciaSlab), + 143 => Some(Item::DarkOakSlab), + 144 => Some(Item::CrimsonSlab), + 145 => Some(Item::WarpedSlab), + 146 => Some(Item::StoneSlab), + 147 => Some(Item::SmoothStoneSlab), + 148 => Some(Item::SandstoneSlab), + 149 => Some(Item::CutSandstoneSlab), + 150 => Some(Item::PetrifiedOakSlab), + 151 => Some(Item::CobblestoneSlab), + 152 => Some(Item::BrickSlab), + 153 => Some(Item::StoneBrickSlab), + 154 => Some(Item::NetherBrickSlab), + 155 => Some(Item::QuartzSlab), + 156 => Some(Item::RedSandstoneSlab), + 157 => Some(Item::CutRedSandstoneSlab), + 158 => Some(Item::PurpurSlab), + 159 => Some(Item::PrismarineSlab), + 160 => Some(Item::PrismarineBrickSlab), + 161 => Some(Item::DarkPrismarineSlab), + 162 => Some(Item::SmoothQuartz), + 163 => Some(Item::SmoothRedSandstone), + 164 => Some(Item::SmoothSandstone), + 165 => Some(Item::SmoothStone), + 166 => Some(Item::Bricks), + 167 => Some(Item::Tnt), + 168 => Some(Item::Bookshelf), + 169 => Some(Item::MossyCobblestone), + 170 => Some(Item::Obsidian), + 171 => Some(Item::Torch), + 172 => Some(Item::EndRod), + 173 => Some(Item::ChorusPlant), + 174 => Some(Item::ChorusFlower), + 175 => Some(Item::PurpurBlock), + 176 => Some(Item::PurpurPillar), + 177 => Some(Item::PurpurStairs), + 178 => Some(Item::Spawner), + 179 => Some(Item::OakStairs), + 180 => Some(Item::Chest), + 181 => Some(Item::DiamondOre), + 182 => Some(Item::DiamondBlock), + 183 => Some(Item::CraftingTable), + 184 => Some(Item::Farmland), + 185 => Some(Item::Furnace), + 186 => Some(Item::Ladder), + 187 => Some(Item::Rail), + 188 => Some(Item::CobblestoneStairs), + 189 => Some(Item::Lever), + 190 => Some(Item::StonePressurePlate), + 191 => Some(Item::OakPressurePlate), + 192 => Some(Item::SprucePressurePlate), + 193 => Some(Item::BirchPressurePlate), + 194 => Some(Item::JunglePressurePlate), + 195 => Some(Item::AcaciaPressurePlate), + 196 => Some(Item::DarkOakPressurePlate), + 197 => Some(Item::CrimsonPressurePlate), + 198 => Some(Item::WarpedPressurePlate), + 199 => Some(Item::PolishedBlackstonePressurePlate), + 200 => Some(Item::RedstoneOre), + 201 => Some(Item::RedstoneTorch), + 202 => Some(Item::Snow), + 203 => Some(Item::Ice), + 204 => Some(Item::SnowBlock), + 205 => Some(Item::Cactus), + 206 => Some(Item::Clay), + 207 => Some(Item::Jukebox), + 208 => Some(Item::OakFence), + 209 => Some(Item::SpruceFence), + 210 => Some(Item::BirchFence), + 211 => Some(Item::JungleFence), + 212 => Some(Item::AcaciaFence), + 213 => Some(Item::DarkOakFence), + 214 => Some(Item::CrimsonFence), + 215 => Some(Item::WarpedFence), + 216 => Some(Item::Pumpkin), + 217 => Some(Item::CarvedPumpkin), + 218 => Some(Item::Netherrack), + 219 => Some(Item::SoulSand), + 220 => Some(Item::SoulSoil), + 221 => Some(Item::Basalt), + 222 => Some(Item::PolishedBasalt), + 223 => Some(Item::SoulTorch), + 224 => Some(Item::Glowstone), + 225 => Some(Item::JackOLantern), + 226 => Some(Item::OakTrapdoor), + 227 => Some(Item::SpruceTrapdoor), + 228 => Some(Item::BirchTrapdoor), + 229 => Some(Item::JungleTrapdoor), + 230 => Some(Item::AcaciaTrapdoor), + 231 => Some(Item::DarkOakTrapdoor), + 232 => Some(Item::CrimsonTrapdoor), + 233 => Some(Item::WarpedTrapdoor), + 234 => Some(Item::InfestedStone), + 235 => Some(Item::InfestedCobblestone), + 236 => Some(Item::InfestedStoneBricks), + 237 => Some(Item::InfestedMossyStoneBricks), + 238 => Some(Item::InfestedCrackedStoneBricks), + 239 => Some(Item::InfestedChiseledStoneBricks), + 240 => Some(Item::StoneBricks), + 241 => Some(Item::MossyStoneBricks), + 242 => Some(Item::CrackedStoneBricks), + 243 => Some(Item::ChiseledStoneBricks), + 244 => Some(Item::BrownMushroomBlock), + 245 => Some(Item::RedMushroomBlock), + 246 => Some(Item::MushroomStem), + 247 => Some(Item::IronBars), + 248 => Some(Item::Chain), + 249 => Some(Item::GlassPane), + 250 => Some(Item::Melon), + 251 => Some(Item::Vine), + 252 => Some(Item::OakFenceGate), + 253 => Some(Item::SpruceFenceGate), + 254 => Some(Item::BirchFenceGate), + 255 => Some(Item::JungleFenceGate), + 256 => Some(Item::AcaciaFenceGate), + 257 => Some(Item::DarkOakFenceGate), + 258 => Some(Item::CrimsonFenceGate), + 259 => Some(Item::WarpedFenceGate), + 260 => Some(Item::BrickStairs), + 261 => Some(Item::StoneBrickStairs), + 262 => Some(Item::Mycelium), + 263 => Some(Item::LilyPad), + 264 => Some(Item::NetherBricks), + 265 => Some(Item::CrackedNetherBricks), + 266 => Some(Item::ChiseledNetherBricks), + 267 => Some(Item::NetherBrickFence), + 268 => Some(Item::NetherBrickStairs), + 269 => Some(Item::EnchantingTable), + 270 => Some(Item::EndPortalFrame), + 271 => Some(Item::EndStone), + 272 => Some(Item::EndStoneBricks), + 273 => Some(Item::DragonEgg), + 274 => Some(Item::RedstoneLamp), + 275 => Some(Item::SandstoneStairs), + 276 => Some(Item::EmeraldOre), + 277 => Some(Item::EnderChest), + 278 => Some(Item::TripwireHook), + 279 => Some(Item::EmeraldBlock), + 280 => Some(Item::SpruceStairs), + 281 => Some(Item::BirchStairs), + 282 => Some(Item::JungleStairs), + 283 => Some(Item::CrimsonStairs), + 284 => Some(Item::WarpedStairs), + 285 => Some(Item::CommandBlock), + 286 => Some(Item::Beacon), + 287 => Some(Item::CobblestoneWall), + 288 => Some(Item::MossyCobblestoneWall), + 289 => Some(Item::BrickWall), + 290 => Some(Item::PrismarineWall), + 291 => Some(Item::RedSandstoneWall), + 292 => Some(Item::MossyStoneBrickWall), + 293 => Some(Item::GraniteWall), + 294 => Some(Item::StoneBrickWall), + 295 => Some(Item::NetherBrickWall), + 296 => Some(Item::AndesiteWall), + 297 => Some(Item::RedNetherBrickWall), + 298 => Some(Item::SandstoneWall), + 299 => Some(Item::EndStoneBrickWall), + 300 => Some(Item::DioriteWall), + 301 => Some(Item::BlackstoneWall), + 302 => Some(Item::PolishedBlackstoneWall), + 303 => Some(Item::PolishedBlackstoneBrickWall), + 304 => Some(Item::StoneButton), + 305 => Some(Item::OakButton), + 306 => Some(Item::SpruceButton), + 307 => Some(Item::BirchButton), + 308 => Some(Item::JungleButton), + 309 => Some(Item::AcaciaButton), + 310 => Some(Item::DarkOakButton), + 311 => Some(Item::CrimsonButton), + 312 => Some(Item::WarpedButton), + 313 => Some(Item::PolishedBlackstoneButton), + 314 => Some(Item::Anvil), + 315 => Some(Item::ChippedAnvil), + 316 => Some(Item::DamagedAnvil), + 317 => Some(Item::TrappedChest), + 318 => Some(Item::LightWeightedPressurePlate), + 319 => Some(Item::HeavyWeightedPressurePlate), + 320 => Some(Item::DaylightDetector), + 321 => Some(Item::RedstoneBlock), + 322 => Some(Item::NetherQuartzOre), + 323 => Some(Item::Hopper), + 324 => Some(Item::ChiseledQuartzBlock), + 325 => Some(Item::QuartzBlock), + 326 => Some(Item::QuartzBricks), + 327 => Some(Item::QuartzPillar), + 328 => Some(Item::QuartzStairs), + 329 => Some(Item::ActivatorRail), + 330 => Some(Item::Dropper), + 331 => Some(Item::WhiteTerracotta), + 332 => Some(Item::OrangeTerracotta), + 333 => Some(Item::MagentaTerracotta), + 334 => Some(Item::LightBlueTerracotta), + 335 => Some(Item::YellowTerracotta), + 336 => Some(Item::LimeTerracotta), + 337 => Some(Item::PinkTerracotta), + 338 => Some(Item::GrayTerracotta), + 339 => Some(Item::LightGrayTerracotta), + 340 => Some(Item::CyanTerracotta), + 341 => Some(Item::PurpleTerracotta), + 342 => Some(Item::BlueTerracotta), + 343 => Some(Item::BrownTerracotta), + 344 => Some(Item::GreenTerracotta), + 345 => Some(Item::RedTerracotta), + 346 => Some(Item::BlackTerracotta), + 347 => Some(Item::Barrier), + 348 => Some(Item::IronTrapdoor), + 349 => Some(Item::HayBlock), + 350 => Some(Item::WhiteCarpet), + 351 => Some(Item::OrangeCarpet), + 352 => Some(Item::MagentaCarpet), + 353 => Some(Item::LightBlueCarpet), + 354 => Some(Item::YellowCarpet), + 355 => Some(Item::LimeCarpet), + 356 => Some(Item::PinkCarpet), + 357 => Some(Item::GrayCarpet), + 358 => Some(Item::LightGrayCarpet), + 359 => Some(Item::CyanCarpet), + 360 => Some(Item::PurpleCarpet), + 361 => Some(Item::BlueCarpet), + 362 => Some(Item::BrownCarpet), + 363 => Some(Item::GreenCarpet), + 364 => Some(Item::RedCarpet), + 365 => Some(Item::BlackCarpet), + 366 => Some(Item::Terracotta), + 367 => Some(Item::CoalBlock), + 368 => Some(Item::PackedIce), + 369 => Some(Item::AcaciaStairs), + 370 => Some(Item::DarkOakStairs), + 371 => Some(Item::SlimeBlock), + 372 => Some(Item::GrassPath), + 373 => Some(Item::Sunflower), + 374 => Some(Item::Lilac), + 375 => Some(Item::RoseBush), + 376 => Some(Item::Peony), + 377 => Some(Item::TallGrass), + 378 => Some(Item::LargeFern), + 379 => Some(Item::WhiteStainedGlass), + 380 => Some(Item::OrangeStainedGlass), + 381 => Some(Item::MagentaStainedGlass), + 382 => Some(Item::LightBlueStainedGlass), + 383 => Some(Item::YellowStainedGlass), + 384 => Some(Item::LimeStainedGlass), + 385 => Some(Item::PinkStainedGlass), + 386 => Some(Item::GrayStainedGlass), + 387 => Some(Item::LightGrayStainedGlass), + 388 => Some(Item::CyanStainedGlass), + 389 => Some(Item::PurpleStainedGlass), + 390 => Some(Item::BlueStainedGlass), + 391 => Some(Item::BrownStainedGlass), + 392 => Some(Item::GreenStainedGlass), + 393 => Some(Item::RedStainedGlass), + 394 => Some(Item::BlackStainedGlass), + 395 => Some(Item::WhiteStainedGlassPane), + 396 => Some(Item::OrangeStainedGlassPane), + 397 => Some(Item::MagentaStainedGlassPane), + 398 => Some(Item::LightBlueStainedGlassPane), + 399 => Some(Item::YellowStainedGlassPane), + 400 => Some(Item::LimeStainedGlassPane), + 401 => Some(Item::PinkStainedGlassPane), + 402 => Some(Item::GrayStainedGlassPane), + 403 => Some(Item::LightGrayStainedGlassPane), + 404 => Some(Item::CyanStainedGlassPane), + 405 => Some(Item::PurpleStainedGlassPane), + 406 => Some(Item::BlueStainedGlassPane), + 407 => Some(Item::BrownStainedGlassPane), + 408 => Some(Item::GreenStainedGlassPane), + 409 => Some(Item::RedStainedGlassPane), + 410 => Some(Item::BlackStainedGlassPane), + 411 => Some(Item::Prismarine), + 412 => Some(Item::PrismarineBricks), + 413 => Some(Item::DarkPrismarine), + 414 => Some(Item::PrismarineStairs), + 415 => Some(Item::PrismarineBrickStairs), + 416 => Some(Item::DarkPrismarineStairs), + 417 => Some(Item::SeaLantern), + 418 => Some(Item::RedSandstone), + 419 => Some(Item::ChiseledRedSandstone), + 420 => Some(Item::CutRedSandstone), + 421 => Some(Item::RedSandstoneStairs), + 422 => Some(Item::RepeatingCommandBlock), + 423 => Some(Item::ChainCommandBlock), + 424 => Some(Item::MagmaBlock), + 425 => Some(Item::NetherWartBlock), + 426 => Some(Item::WarpedWartBlock), + 427 => Some(Item::RedNetherBricks), + 428 => Some(Item::BoneBlock), + 429 => Some(Item::StructureVoid), + 430 => Some(Item::Observer), + 431 => Some(Item::ShulkerBox), + 432 => Some(Item::WhiteShulkerBox), + 433 => Some(Item::OrangeShulkerBox), + 434 => Some(Item::MagentaShulkerBox), + 435 => Some(Item::LightBlueShulkerBox), + 436 => Some(Item::YellowShulkerBox), + 437 => Some(Item::LimeShulkerBox), + 438 => Some(Item::PinkShulkerBox), + 439 => Some(Item::GrayShulkerBox), + 440 => Some(Item::LightGrayShulkerBox), + 441 => Some(Item::CyanShulkerBox), + 442 => Some(Item::PurpleShulkerBox), + 443 => Some(Item::BlueShulkerBox), + 444 => Some(Item::BrownShulkerBox), + 445 => Some(Item::GreenShulkerBox), + 446 => Some(Item::RedShulkerBox), + 447 => Some(Item::BlackShulkerBox), + 448 => Some(Item::WhiteGlazedTerracotta), + 449 => Some(Item::OrangeGlazedTerracotta), + 450 => Some(Item::MagentaGlazedTerracotta), + 451 => Some(Item::LightBlueGlazedTerracotta), + 452 => Some(Item::YellowGlazedTerracotta), + 453 => Some(Item::LimeGlazedTerracotta), + 454 => Some(Item::PinkGlazedTerracotta), + 455 => Some(Item::GrayGlazedTerracotta), + 456 => Some(Item::LightGrayGlazedTerracotta), + 457 => Some(Item::CyanGlazedTerracotta), + 458 => Some(Item::PurpleGlazedTerracotta), + 459 => Some(Item::BlueGlazedTerracotta), + 460 => Some(Item::BrownGlazedTerracotta), + 461 => Some(Item::GreenGlazedTerracotta), + 462 => Some(Item::RedGlazedTerracotta), + 463 => Some(Item::BlackGlazedTerracotta), + 464 => Some(Item::WhiteConcrete), + 465 => Some(Item::OrangeConcrete), + 466 => Some(Item::MagentaConcrete), + 467 => Some(Item::LightBlueConcrete), + 468 => Some(Item::YellowConcrete), + 469 => Some(Item::LimeConcrete), + 470 => Some(Item::PinkConcrete), + 471 => Some(Item::GrayConcrete), + 472 => Some(Item::LightGrayConcrete), + 473 => Some(Item::CyanConcrete), + 474 => Some(Item::PurpleConcrete), + 475 => Some(Item::BlueConcrete), + 476 => Some(Item::BrownConcrete), + 477 => Some(Item::GreenConcrete), + 478 => Some(Item::RedConcrete), + 479 => Some(Item::BlackConcrete), + 480 => Some(Item::WhiteConcretePowder), + 481 => Some(Item::OrangeConcretePowder), + 482 => Some(Item::MagentaConcretePowder), + 483 => Some(Item::LightBlueConcretePowder), + 484 => Some(Item::YellowConcretePowder), + 485 => Some(Item::LimeConcretePowder), + 486 => Some(Item::PinkConcretePowder), + 487 => Some(Item::GrayConcretePowder), + 488 => Some(Item::LightGrayConcretePowder), + 489 => Some(Item::CyanConcretePowder), + 490 => Some(Item::PurpleConcretePowder), + 491 => Some(Item::BlueConcretePowder), + 492 => Some(Item::BrownConcretePowder), + 493 => Some(Item::GreenConcretePowder), + 494 => Some(Item::RedConcretePowder), + 495 => Some(Item::BlackConcretePowder), + 496 => Some(Item::TurtleEgg), + 497 => Some(Item::DeadTubeCoralBlock), + 498 => Some(Item::DeadBrainCoralBlock), + 499 => Some(Item::DeadBubbleCoralBlock), + 500 => Some(Item::DeadFireCoralBlock), + 501 => Some(Item::DeadHornCoralBlock), + 502 => Some(Item::TubeCoralBlock), + 503 => Some(Item::BrainCoralBlock), + 504 => Some(Item::BubbleCoralBlock), + 505 => Some(Item::FireCoralBlock), + 506 => Some(Item::HornCoralBlock), + 507 => Some(Item::TubeCoral), + 508 => Some(Item::BrainCoral), + 509 => Some(Item::BubbleCoral), + 510 => Some(Item::FireCoral), + 511 => Some(Item::HornCoral), + 512 => Some(Item::DeadBrainCoral), + 513 => Some(Item::DeadBubbleCoral), + 514 => Some(Item::DeadFireCoral), + 515 => Some(Item::DeadHornCoral), + 516 => Some(Item::DeadTubeCoral), + 517 => Some(Item::TubeCoralFan), + 518 => Some(Item::BrainCoralFan), + 519 => Some(Item::BubbleCoralFan), + 520 => Some(Item::FireCoralFan), + 521 => Some(Item::HornCoralFan), + 522 => Some(Item::DeadTubeCoralFan), + 523 => Some(Item::DeadBrainCoralFan), + 524 => Some(Item::DeadBubbleCoralFan), + 525 => Some(Item::DeadFireCoralFan), + 526 => Some(Item::DeadHornCoralFan), + 527 => Some(Item::BlueIce), + 528 => Some(Item::Conduit), + 529 => Some(Item::PolishedGraniteStairs), + 530 => Some(Item::SmoothRedSandstoneStairs), + 531 => Some(Item::MossyStoneBrickStairs), + 532 => Some(Item::PolishedDioriteStairs), + 533 => Some(Item::MossyCobblestoneStairs), + 534 => Some(Item::EndStoneBrickStairs), + 535 => Some(Item::StoneStairs), + 536 => Some(Item::SmoothSandstoneStairs), + 537 => Some(Item::SmoothQuartzStairs), + 538 => Some(Item::GraniteStairs), + 539 => Some(Item::AndesiteStairs), + 540 => Some(Item::RedNetherBrickStairs), + 541 => Some(Item::PolishedAndesiteStairs), + 542 => Some(Item::DioriteStairs), + 543 => Some(Item::PolishedGraniteSlab), + 544 => Some(Item::SmoothRedSandstoneSlab), + 545 => Some(Item::MossyStoneBrickSlab), + 546 => Some(Item::PolishedDioriteSlab), + 547 => Some(Item::MossyCobblestoneSlab), + 548 => Some(Item::EndStoneBrickSlab), + 549 => Some(Item::SmoothSandstoneSlab), + 550 => Some(Item::SmoothQuartzSlab), + 551 => Some(Item::GraniteSlab), + 552 => Some(Item::AndesiteSlab), + 553 => Some(Item::RedNetherBrickSlab), + 554 => Some(Item::PolishedAndesiteSlab), + 555 => Some(Item::DioriteSlab), + 556 => Some(Item::Scaffolding), + 557 => Some(Item::IronDoor), + 558 => Some(Item::OakDoor), + 559 => Some(Item::SpruceDoor), + 560 => Some(Item::BirchDoor), + 561 => Some(Item::JungleDoor), + 562 => Some(Item::AcaciaDoor), + 563 => Some(Item::DarkOakDoor), + 564 => Some(Item::CrimsonDoor), + 565 => Some(Item::WarpedDoor), + 566 => Some(Item::Repeater), + 567 => Some(Item::Comparator), + 568 => Some(Item::StructureBlock), + 569 => Some(Item::Jigsaw), + 570 => Some(Item::TurtleHelmet), + 571 => Some(Item::Scute), + 572 => Some(Item::FlintAndSteel), + 573 => Some(Item::Apple), + 574 => Some(Item::Bow), + 575 => Some(Item::Arrow), + 576 => Some(Item::Coal), + 577 => Some(Item::Charcoal), + 578 => Some(Item::Diamond), + 579 => Some(Item::IronIngot), + 580 => Some(Item::GoldIngot), + 581 => Some(Item::NetheriteIngot), + 582 => Some(Item::NetheriteScrap), + 583 => Some(Item::WoodenSword), + 584 => Some(Item::WoodenShovel), + 585 => Some(Item::WoodenPickaxe), + 586 => Some(Item::WoodenAxe), + 587 => Some(Item::WoodenHoe), + 588 => Some(Item::StoneSword), + 589 => Some(Item::StoneShovel), + 590 => Some(Item::StonePickaxe), + 591 => Some(Item::StoneAxe), + 592 => Some(Item::StoneHoe), + 593 => Some(Item::GoldenSword), + 594 => Some(Item::GoldenShovel), + 595 => Some(Item::GoldenPickaxe), + 596 => Some(Item::GoldenAxe), + 597 => Some(Item::GoldenHoe), + 598 => Some(Item::IronSword), + 599 => Some(Item::IronShovel), + 600 => Some(Item::IronPickaxe), + 601 => Some(Item::IronAxe), + 602 => Some(Item::IronHoe), + 603 => Some(Item::DiamondSword), + 604 => Some(Item::DiamondShovel), + 605 => Some(Item::DiamondPickaxe), + 606 => Some(Item::DiamondAxe), + 607 => Some(Item::DiamondHoe), + 608 => Some(Item::NetheriteSword), + 609 => Some(Item::NetheriteShovel), + 610 => Some(Item::NetheritePickaxe), + 611 => Some(Item::NetheriteAxe), + 612 => Some(Item::NetheriteHoe), + 613 => Some(Item::Stick), + 614 => Some(Item::Bowl), + 615 => Some(Item::MushroomStew), + 616 => Some(Item::String), + 617 => Some(Item::Feather), + 618 => Some(Item::Gunpowder), + 619 => Some(Item::WheatSeeds), + 620 => Some(Item::Wheat), + 621 => Some(Item::Bread), + 622 => Some(Item::LeatherHelmet), + 623 => Some(Item::LeatherChestplate), + 624 => Some(Item::LeatherLeggings), + 625 => Some(Item::LeatherBoots), + 626 => Some(Item::ChainmailHelmet), + 627 => Some(Item::ChainmailChestplate), + 628 => Some(Item::ChainmailLeggings), + 629 => Some(Item::ChainmailBoots), + 630 => Some(Item::IronHelmet), + 631 => Some(Item::IronChestplate), + 632 => Some(Item::IronLeggings), + 633 => Some(Item::IronBoots), + 634 => Some(Item::DiamondHelmet), + 635 => Some(Item::DiamondChestplate), + 636 => Some(Item::DiamondLeggings), + 637 => Some(Item::DiamondBoots), + 638 => Some(Item::GoldenHelmet), + 639 => Some(Item::GoldenChestplate), + 640 => Some(Item::GoldenLeggings), + 641 => Some(Item::GoldenBoots), + 642 => Some(Item::NetheriteHelmet), + 643 => Some(Item::NetheriteChestplate), + 644 => Some(Item::NetheriteLeggings), + 645 => Some(Item::NetheriteBoots), + 646 => Some(Item::Flint), + 647 => Some(Item::Porkchop), + 648 => Some(Item::CookedPorkchop), + 649 => Some(Item::Painting), + 650 => Some(Item::GoldenApple), + 651 => Some(Item::EnchantedGoldenApple), + 652 => Some(Item::OakSign), + 653 => Some(Item::SpruceSign), + 654 => Some(Item::BirchSign), + 655 => Some(Item::JungleSign), + 656 => Some(Item::AcaciaSign), + 657 => Some(Item::DarkOakSign), + 658 => Some(Item::CrimsonSign), + 659 => Some(Item::WarpedSign), + 660 => Some(Item::Bucket), + 661 => Some(Item::WaterBucket), + 662 => Some(Item::LavaBucket), + 663 => Some(Item::Minecart), + 664 => Some(Item::Saddle), + 665 => Some(Item::Redstone), + 666 => Some(Item::Snowball), + 667 => Some(Item::OakBoat), + 668 => Some(Item::Leather), + 669 => Some(Item::MilkBucket), + 670 => Some(Item::PufferfishBucket), + 671 => Some(Item::SalmonBucket), + 672 => Some(Item::CodBucket), + 673 => Some(Item::TropicalFishBucket), + 674 => Some(Item::Brick), + 675 => Some(Item::ClayBall), + 676 => Some(Item::DriedKelpBlock), + 677 => Some(Item::Paper), + 678 => Some(Item::Book), + 679 => Some(Item::SlimeBall), + 680 => Some(Item::ChestMinecart), + 681 => Some(Item::FurnaceMinecart), + 682 => Some(Item::Egg), + 683 => Some(Item::Compass), + 684 => Some(Item::FishingRod), + 685 => Some(Item::Clock), + 686 => Some(Item::GlowstoneDust), + 687 => Some(Item::Cod), + 688 => Some(Item::Salmon), + 689 => Some(Item::TropicalFish), + 690 => Some(Item::Pufferfish), + 691 => Some(Item::CookedCod), + 692 => Some(Item::CookedSalmon), + 693 => Some(Item::InkSac), + 694 => Some(Item::CocoaBeans), + 695 => Some(Item::LapisLazuli), + 696 => Some(Item::WhiteDye), + 697 => Some(Item::OrangeDye), + 698 => Some(Item::MagentaDye), + 699 => Some(Item::LightBlueDye), + 700 => Some(Item::YellowDye), + 701 => Some(Item::LimeDye), + 702 => Some(Item::PinkDye), + 703 => Some(Item::GrayDye), + 704 => Some(Item::LightGrayDye), + 705 => Some(Item::CyanDye), + 706 => Some(Item::PurpleDye), + 707 => Some(Item::BlueDye), + 708 => Some(Item::BrownDye), + 709 => Some(Item::GreenDye), + 710 => Some(Item::RedDye), + 711 => Some(Item::BlackDye), + 712 => Some(Item::BoneMeal), + 713 => Some(Item::Bone), + 714 => Some(Item::Sugar), + 715 => Some(Item::Cake), + 716 => Some(Item::WhiteBed), + 717 => Some(Item::OrangeBed), + 718 => Some(Item::MagentaBed), + 719 => Some(Item::LightBlueBed), + 720 => Some(Item::YellowBed), + 721 => Some(Item::LimeBed), + 722 => Some(Item::PinkBed), + 723 => Some(Item::GrayBed), + 724 => Some(Item::LightGrayBed), + 725 => Some(Item::CyanBed), + 726 => Some(Item::PurpleBed), + 727 => Some(Item::BlueBed), + 728 => Some(Item::BrownBed), + 729 => Some(Item::GreenBed), + 730 => Some(Item::RedBed), + 731 => Some(Item::BlackBed), + 732 => Some(Item::Cookie), + 733 => Some(Item::FilledMap), + 734 => Some(Item::Shears), + 735 => Some(Item::MelonSlice), + 736 => Some(Item::DriedKelp), + 737 => Some(Item::PumpkinSeeds), + 738 => Some(Item::MelonSeeds), + 739 => Some(Item::Beef), + 740 => Some(Item::CookedBeef), + 741 => Some(Item::Chicken), + 742 => Some(Item::CookedChicken), + 743 => Some(Item::RottenFlesh), + 744 => Some(Item::EnderPearl), + 745 => Some(Item::BlazeRod), + 746 => Some(Item::GhastTear), + 747 => Some(Item::GoldNugget), + 748 => Some(Item::NetherWart), + 749 => Some(Item::Potion), + 750 => Some(Item::GlassBottle), + 751 => Some(Item::SpiderEye), + 752 => Some(Item::FermentedSpiderEye), + 753 => Some(Item::BlazePowder), + 754 => Some(Item::MagmaCream), + 755 => Some(Item::BrewingStand), + 756 => Some(Item::Cauldron), + 757 => Some(Item::EnderEye), + 758 => Some(Item::GlisteringMelonSlice), + 759 => Some(Item::BatSpawnEgg), + 760 => Some(Item::BeeSpawnEgg), + 761 => Some(Item::BlazeSpawnEgg), + 762 => Some(Item::CatSpawnEgg), + 763 => Some(Item::CaveSpiderSpawnEgg), + 764 => Some(Item::ChickenSpawnEgg), + 765 => Some(Item::CodSpawnEgg), + 766 => Some(Item::CowSpawnEgg), + 767 => Some(Item::CreeperSpawnEgg), + 768 => Some(Item::DolphinSpawnEgg), + 769 => Some(Item::DonkeySpawnEgg), + 770 => Some(Item::DrownedSpawnEgg), + 771 => Some(Item::ElderGuardianSpawnEgg), + 772 => Some(Item::EndermanSpawnEgg), + 773 => Some(Item::EndermiteSpawnEgg), + 774 => Some(Item::EvokerSpawnEgg), + 775 => Some(Item::FoxSpawnEgg), + 776 => Some(Item::GhastSpawnEgg), + 777 => Some(Item::GuardianSpawnEgg), + 778 => Some(Item::HoglinSpawnEgg), + 779 => Some(Item::HorseSpawnEgg), + 780 => Some(Item::HuskSpawnEgg), + 781 => Some(Item::LlamaSpawnEgg), + 782 => Some(Item::MagmaCubeSpawnEgg), + 783 => Some(Item::MooshroomSpawnEgg), + 784 => Some(Item::MuleSpawnEgg), + 785 => Some(Item::OcelotSpawnEgg), + 786 => Some(Item::PandaSpawnEgg), + 787 => Some(Item::ParrotSpawnEgg), + 788 => Some(Item::PhantomSpawnEgg), + 789 => Some(Item::PigSpawnEgg), + 790 => Some(Item::PiglinSpawnEgg), + 791 => Some(Item::PiglinBruteSpawnEgg), + 792 => Some(Item::PillagerSpawnEgg), + 793 => Some(Item::PolarBearSpawnEgg), + 794 => Some(Item::PufferfishSpawnEgg), + 795 => Some(Item::RabbitSpawnEgg), + 796 => Some(Item::RavagerSpawnEgg), + 797 => Some(Item::SalmonSpawnEgg), + 798 => Some(Item::SheepSpawnEgg), + 799 => Some(Item::ShulkerSpawnEgg), + 800 => Some(Item::SilverfishSpawnEgg), + 801 => Some(Item::SkeletonSpawnEgg), + 802 => Some(Item::SkeletonHorseSpawnEgg), + 803 => Some(Item::SlimeSpawnEgg), + 804 => Some(Item::SpiderSpawnEgg), + 805 => Some(Item::SquidSpawnEgg), + 806 => Some(Item::StraySpawnEgg), + 807 => Some(Item::StriderSpawnEgg), + 808 => Some(Item::TraderLlamaSpawnEgg), + 809 => Some(Item::TropicalFishSpawnEgg), + 810 => Some(Item::TurtleSpawnEgg), + 811 => Some(Item::VexSpawnEgg), + 812 => Some(Item::VillagerSpawnEgg), + 813 => Some(Item::VindicatorSpawnEgg), + 814 => Some(Item::WanderingTraderSpawnEgg), + 815 => Some(Item::WitchSpawnEgg), + 816 => Some(Item::WitherSkeletonSpawnEgg), + 817 => Some(Item::WolfSpawnEgg), + 818 => Some(Item::ZoglinSpawnEgg), + 819 => Some(Item::ZombieSpawnEgg), + 820 => Some(Item::ZombieHorseSpawnEgg), + 821 => Some(Item::ZombieVillagerSpawnEgg), + 822 => Some(Item::ZombifiedPiglinSpawnEgg), + 823 => Some(Item::ExperienceBottle), + 824 => Some(Item::FireCharge), + 825 => Some(Item::WritableBook), + 826 => Some(Item::WrittenBook), + 827 => Some(Item::Emerald), + 828 => Some(Item::ItemFrame), + 829 => Some(Item::FlowerPot), + 830 => Some(Item::Carrot), + 831 => Some(Item::Potato), + 832 => Some(Item::BakedPotato), + 833 => Some(Item::PoisonousPotato), + 834 => Some(Item::Map), + 835 => Some(Item::GoldenCarrot), + 836 => Some(Item::SkeletonSkull), + 837 => Some(Item::WitherSkeletonSkull), + 838 => Some(Item::PlayerHead), + 839 => Some(Item::ZombieHead), + 840 => Some(Item::CreeperHead), + 841 => Some(Item::DragonHead), + 842 => Some(Item::CarrotOnAStick), + 843 => Some(Item::WarpedFungusOnAStick), + 844 => Some(Item::NetherStar), + 845 => Some(Item::PumpkinPie), + 846 => Some(Item::FireworkRocket), + 847 => Some(Item::FireworkStar), + 848 => Some(Item::EnchantedBook), + 849 => Some(Item::NetherBrick), + 850 => Some(Item::Quartz), + 851 => Some(Item::TntMinecart), + 852 => Some(Item::HopperMinecart), + 853 => Some(Item::PrismarineShard), + 854 => Some(Item::PrismarineCrystals), + 855 => Some(Item::Rabbit), + 856 => Some(Item::CookedRabbit), + 857 => Some(Item::RabbitStew), + 858 => Some(Item::RabbitFoot), + 859 => Some(Item::RabbitHide), + 860 => Some(Item::ArmorStand), + 861 => Some(Item::IronHorseArmor), + 862 => Some(Item::GoldenHorseArmor), + 863 => Some(Item::DiamondHorseArmor), + 864 => Some(Item::LeatherHorseArmor), + 865 => Some(Item::Lead), + 866 => Some(Item::NameTag), + 867 => Some(Item::CommandBlockMinecart), + 868 => Some(Item::Mutton), + 869 => Some(Item::CookedMutton), + 870 => Some(Item::WhiteBanner), + 871 => Some(Item::OrangeBanner), + 872 => Some(Item::MagentaBanner), + 873 => Some(Item::LightBlueBanner), + 874 => Some(Item::YellowBanner), + 875 => Some(Item::LimeBanner), + 876 => Some(Item::PinkBanner), + 877 => Some(Item::GrayBanner), + 878 => Some(Item::LightGrayBanner), + 879 => Some(Item::CyanBanner), + 880 => Some(Item::PurpleBanner), + 881 => Some(Item::BlueBanner), + 882 => Some(Item::BrownBanner), + 883 => Some(Item::GreenBanner), + 884 => Some(Item::RedBanner), + 885 => Some(Item::BlackBanner), + 886 => Some(Item::EndCrystal), + 887 => Some(Item::ChorusFruit), + 888 => Some(Item::PoppedChorusFruit), + 889 => Some(Item::Beetroot), + 890 => Some(Item::BeetrootSeeds), + 891 => Some(Item::BeetrootSoup), + 892 => Some(Item::DragonBreath), + 893 => Some(Item::SplashPotion), + 894 => Some(Item::SpectralArrow), + 895 => Some(Item::TippedArrow), + 896 => Some(Item::LingeringPotion), + 897 => Some(Item::Shield), + 898 => Some(Item::Elytra), + 899 => Some(Item::SpruceBoat), + 900 => Some(Item::BirchBoat), + 901 => Some(Item::JungleBoat), + 902 => Some(Item::AcaciaBoat), + 903 => Some(Item::DarkOakBoat), + 904 => Some(Item::TotemOfUndying), + 905 => Some(Item::ShulkerShell), + 906 => Some(Item::IronNugget), + 907 => Some(Item::KnowledgeBook), + 908 => Some(Item::DebugStick), + 909 => Some(Item::MusicDisc13), + 910 => Some(Item::MusicDiscCat), + 911 => Some(Item::MusicDiscBlocks), + 912 => Some(Item::MusicDiscChirp), + 913 => Some(Item::MusicDiscFar), + 914 => Some(Item::MusicDiscMall), + 915 => Some(Item::MusicDiscMellohi), + 916 => Some(Item::MusicDiscStal), + 917 => Some(Item::MusicDiscStrad), + 918 => Some(Item::MusicDiscWard), + 919 => Some(Item::MusicDisc11), + 920 => Some(Item::MusicDiscWait), + 921 => Some(Item::MusicDiscPigstep), + 922 => Some(Item::Trident), + 923 => Some(Item::PhantomMembrane), + 924 => Some(Item::NautilusShell), + 925 => Some(Item::HeartOfTheSea), + 926 => Some(Item::Crossbow), + 927 => Some(Item::SuspiciousStew), + 928 => Some(Item::Loom), + 929 => Some(Item::FlowerBannerPattern), + 930 => Some(Item::CreeperBannerPattern), + 931 => Some(Item::SkullBannerPattern), + 932 => Some(Item::MojangBannerPattern), + 933 => Some(Item::GlobeBannerPattern), + 934 => Some(Item::PiglinBannerPattern), + 935 => Some(Item::Composter), + 936 => Some(Item::Barrel), + 937 => Some(Item::Smoker), + 938 => Some(Item::BlastFurnace), + 939 => Some(Item::CartographyTable), + 940 => Some(Item::FletchingTable), + 941 => Some(Item::Grindstone), + 942 => Some(Item::Lectern), + 943 => Some(Item::SmithingTable), + 944 => Some(Item::Stonecutter), + 945 => Some(Item::Bell), + 946 => Some(Item::Lantern), + 947 => Some(Item::SoulLantern), + 948 => Some(Item::SweetBerries), + 949 => Some(Item::Campfire), + 950 => Some(Item::SoulCampfire), + 951 => Some(Item::Shroomlight), + 952 => Some(Item::Honeycomb), + 953 => Some(Item::BeeNest), + 954 => Some(Item::Beehive), + 955 => Some(Item::HoneyBottle), + 956 => Some(Item::HoneyBlock), + 957 => Some(Item::HoneycombBlock), + 958 => Some(Item::Lodestone), + 959 => Some(Item::NetheriteBlock), + 960 => Some(Item::AncientDebris), + 961 => Some(Item::Target), + 962 => Some(Item::CryingObsidian), + 963 => Some(Item::Blackstone), + 964 => Some(Item::BlackstoneSlab), + 965 => Some(Item::BlackstoneStairs), + 966 => Some(Item::GildedBlackstone), + 967 => Some(Item::PolishedBlackstone), + 968 => Some(Item::PolishedBlackstoneSlab), + 969 => Some(Item::PolishedBlackstoneStairs), + 970 => Some(Item::ChiseledPolishedBlackstone), + 971 => Some(Item::PolishedBlackstoneBricks), + 972 => Some(Item::PolishedBlackstoneBrickSlab), + 973 => Some(Item::PolishedBlackstoneBrickStairs), + 974 => Some(Item::CrackedPolishedBlackstoneBricks), + 975 => Some(Item::RespawnAnchor), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Item { + /// Returns the `name` property of this `Item`. + pub fn name(&self) -> &'static str { + match self { + Item::Air => "air", + Item::Stone => "stone", + Item::Granite => "granite", + Item::PolishedGranite => "polished_granite", + Item::Diorite => "diorite", + Item::PolishedDiorite => "polished_diorite", + Item::Andesite => "andesite", + Item::PolishedAndesite => "polished_andesite", + Item::GrassBlock => "grass_block", + Item::Dirt => "dirt", + Item::CoarseDirt => "coarse_dirt", + Item::Podzol => "podzol", + Item::CrimsonNylium => "crimson_nylium", + Item::WarpedNylium => "warped_nylium", + Item::Cobblestone => "cobblestone", + Item::OakPlanks => "oak_planks", + Item::SprucePlanks => "spruce_planks", + Item::BirchPlanks => "birch_planks", + Item::JunglePlanks => "jungle_planks", + Item::AcaciaPlanks => "acacia_planks", + Item::DarkOakPlanks => "dark_oak_planks", + Item::CrimsonPlanks => "crimson_planks", + Item::WarpedPlanks => "warped_planks", + Item::OakSapling => "oak_sapling", + Item::SpruceSapling => "spruce_sapling", + Item::BirchSapling => "birch_sapling", + Item::JungleSapling => "jungle_sapling", + Item::AcaciaSapling => "acacia_sapling", + Item::DarkOakSapling => "dark_oak_sapling", + Item::Bedrock => "bedrock", + Item::Sand => "sand", + Item::RedSand => "red_sand", + Item::Gravel => "gravel", + Item::GoldOre => "gold_ore", + Item::IronOre => "iron_ore", + Item::CoalOre => "coal_ore", + Item::NetherGoldOre => "nether_gold_ore", + Item::OakLog => "oak_log", + Item::SpruceLog => "spruce_log", + Item::BirchLog => "birch_log", + Item::JungleLog => "jungle_log", + Item::AcaciaLog => "acacia_log", + Item::DarkOakLog => "dark_oak_log", + Item::CrimsonStem => "crimson_stem", + Item::WarpedStem => "warped_stem", + Item::StrippedOakLog => "stripped_oak_log", + Item::StrippedSpruceLog => "stripped_spruce_log", + Item::StrippedBirchLog => "stripped_birch_log", + Item::StrippedJungleLog => "stripped_jungle_log", + Item::StrippedAcaciaLog => "stripped_acacia_log", + Item::StrippedDarkOakLog => "stripped_dark_oak_log", + Item::StrippedCrimsonStem => "stripped_crimson_stem", + Item::StrippedWarpedStem => "stripped_warped_stem", + Item::StrippedOakWood => "stripped_oak_wood", + Item::StrippedSpruceWood => "stripped_spruce_wood", + Item::StrippedBirchWood => "stripped_birch_wood", + Item::StrippedJungleWood => "stripped_jungle_wood", + Item::StrippedAcaciaWood => "stripped_acacia_wood", + Item::StrippedDarkOakWood => "stripped_dark_oak_wood", + Item::StrippedCrimsonHyphae => "stripped_crimson_hyphae", + Item::StrippedWarpedHyphae => "stripped_warped_hyphae", + Item::OakWood => "oak_wood", + Item::SpruceWood => "spruce_wood", + Item::BirchWood => "birch_wood", + Item::JungleWood => "jungle_wood", + Item::AcaciaWood => "acacia_wood", + Item::DarkOakWood => "dark_oak_wood", + Item::CrimsonHyphae => "crimson_hyphae", + Item::WarpedHyphae => "warped_hyphae", + Item::OakLeaves => "oak_leaves", + Item::SpruceLeaves => "spruce_leaves", + Item::BirchLeaves => "birch_leaves", + Item::JungleLeaves => "jungle_leaves", + Item::AcaciaLeaves => "acacia_leaves", + Item::DarkOakLeaves => "dark_oak_leaves", + Item::Sponge => "sponge", + Item::WetSponge => "wet_sponge", + Item::Glass => "glass", + Item::LapisOre => "lapis_ore", + Item::LapisBlock => "lapis_block", + Item::Dispenser => "dispenser", + Item::Sandstone => "sandstone", + Item::ChiseledSandstone => "chiseled_sandstone", + Item::CutSandstone => "cut_sandstone", + Item::NoteBlock => "note_block", + Item::PoweredRail => "powered_rail", + Item::DetectorRail => "detector_rail", + Item::StickyPiston => "sticky_piston", + Item::Cobweb => "cobweb", + Item::Grass => "grass", + Item::Fern => "fern", + Item::DeadBush => "dead_bush", + Item::Seagrass => "seagrass", + Item::SeaPickle => "sea_pickle", + Item::Piston => "piston", + Item::WhiteWool => "white_wool", + Item::OrangeWool => "orange_wool", + Item::MagentaWool => "magenta_wool", + Item::LightBlueWool => "light_blue_wool", + Item::YellowWool => "yellow_wool", + Item::LimeWool => "lime_wool", + Item::PinkWool => "pink_wool", + Item::GrayWool => "gray_wool", + Item::LightGrayWool => "light_gray_wool", + Item::CyanWool => "cyan_wool", + Item::PurpleWool => "purple_wool", + Item::BlueWool => "blue_wool", + Item::BrownWool => "brown_wool", + Item::GreenWool => "green_wool", + Item::RedWool => "red_wool", + Item::BlackWool => "black_wool", + Item::Dandelion => "dandelion", + Item::Poppy => "poppy", + Item::BlueOrchid => "blue_orchid", + Item::Allium => "allium", + Item::AzureBluet => "azure_bluet", + Item::RedTulip => "red_tulip", + Item::OrangeTulip => "orange_tulip", + Item::WhiteTulip => "white_tulip", + Item::PinkTulip => "pink_tulip", + Item::OxeyeDaisy => "oxeye_daisy", + Item::Cornflower => "cornflower", + Item::LilyOfTheValley => "lily_of_the_valley", + Item::WitherRose => "wither_rose", + Item::BrownMushroom => "brown_mushroom", + Item::RedMushroom => "red_mushroom", + Item::CrimsonFungus => "crimson_fungus", + Item::WarpedFungus => "warped_fungus", + Item::CrimsonRoots => "crimson_roots", + Item::WarpedRoots => "warped_roots", + Item::NetherSprouts => "nether_sprouts", + Item::WeepingVines => "weeping_vines", + Item::TwistingVines => "twisting_vines", + Item::SugarCane => "sugar_cane", + Item::Kelp => "kelp", + Item::Bamboo => "bamboo", + Item::GoldBlock => "gold_block", + Item::IronBlock => "iron_block", + Item::OakSlab => "oak_slab", + Item::SpruceSlab => "spruce_slab", + Item::BirchSlab => "birch_slab", + Item::JungleSlab => "jungle_slab", + Item::AcaciaSlab => "acacia_slab", + Item::DarkOakSlab => "dark_oak_slab", + Item::CrimsonSlab => "crimson_slab", + Item::WarpedSlab => "warped_slab", + Item::StoneSlab => "stone_slab", + Item::SmoothStoneSlab => "smooth_stone_slab", + Item::SandstoneSlab => "sandstone_slab", + Item::CutSandstoneSlab => "cut_sandstone_slab", + Item::PetrifiedOakSlab => "petrified_oak_slab", + Item::CobblestoneSlab => "cobblestone_slab", + Item::BrickSlab => "brick_slab", + Item::StoneBrickSlab => "stone_brick_slab", + Item::NetherBrickSlab => "nether_brick_slab", + Item::QuartzSlab => "quartz_slab", + Item::RedSandstoneSlab => "red_sandstone_slab", + Item::CutRedSandstoneSlab => "cut_red_sandstone_slab", + Item::PurpurSlab => "purpur_slab", + Item::PrismarineSlab => "prismarine_slab", + Item::PrismarineBrickSlab => "prismarine_brick_slab", + Item::DarkPrismarineSlab => "dark_prismarine_slab", + Item::SmoothQuartz => "smooth_quartz", + Item::SmoothRedSandstone => "smooth_red_sandstone", + Item::SmoothSandstone => "smooth_sandstone", + Item::SmoothStone => "smooth_stone", + Item::Bricks => "bricks", + Item::Tnt => "tnt", + Item::Bookshelf => "bookshelf", + Item::MossyCobblestone => "mossy_cobblestone", + Item::Obsidian => "obsidian", + Item::Torch => "torch", + Item::EndRod => "end_rod", + Item::ChorusPlant => "chorus_plant", + Item::ChorusFlower => "chorus_flower", + Item::PurpurBlock => "purpur_block", + Item::PurpurPillar => "purpur_pillar", + Item::PurpurStairs => "purpur_stairs", + Item::Spawner => "spawner", + Item::OakStairs => "oak_stairs", + Item::Chest => "chest", + Item::DiamondOre => "diamond_ore", + Item::DiamondBlock => "diamond_block", + Item::CraftingTable => "crafting_table", + Item::Farmland => "farmland", + Item::Furnace => "furnace", + Item::Ladder => "ladder", + Item::Rail => "rail", + Item::CobblestoneStairs => "cobblestone_stairs", + Item::Lever => "lever", + Item::StonePressurePlate => "stone_pressure_plate", + Item::OakPressurePlate => "oak_pressure_plate", + Item::SprucePressurePlate => "spruce_pressure_plate", + Item::BirchPressurePlate => "birch_pressure_plate", + Item::JunglePressurePlate => "jungle_pressure_plate", + Item::AcaciaPressurePlate => "acacia_pressure_plate", + Item::DarkOakPressurePlate => "dark_oak_pressure_plate", + Item::CrimsonPressurePlate => "crimson_pressure_plate", + Item::WarpedPressurePlate => "warped_pressure_plate", + Item::PolishedBlackstonePressurePlate => "polished_blackstone_pressure_plate", + Item::RedstoneOre => "redstone_ore", + Item::RedstoneTorch => "redstone_torch", + Item::Snow => "snow", + Item::Ice => "ice", + Item::SnowBlock => "snow_block", + Item::Cactus => "cactus", + Item::Clay => "clay", + Item::Jukebox => "jukebox", + Item::OakFence => "oak_fence", + Item::SpruceFence => "spruce_fence", + Item::BirchFence => "birch_fence", + Item::JungleFence => "jungle_fence", + Item::AcaciaFence => "acacia_fence", + Item::DarkOakFence => "dark_oak_fence", + Item::CrimsonFence => "crimson_fence", + Item::WarpedFence => "warped_fence", + Item::Pumpkin => "pumpkin", + Item::CarvedPumpkin => "carved_pumpkin", + Item::Netherrack => "netherrack", + Item::SoulSand => "soul_sand", + Item::SoulSoil => "soul_soil", + Item::Basalt => "basalt", + Item::PolishedBasalt => "polished_basalt", + Item::SoulTorch => "soul_torch", + Item::Glowstone => "glowstone", + Item::JackOLantern => "jack_o_lantern", + Item::OakTrapdoor => "oak_trapdoor", + Item::SpruceTrapdoor => "spruce_trapdoor", + Item::BirchTrapdoor => "birch_trapdoor", + Item::JungleTrapdoor => "jungle_trapdoor", + Item::AcaciaTrapdoor => "acacia_trapdoor", + Item::DarkOakTrapdoor => "dark_oak_trapdoor", + Item::CrimsonTrapdoor => "crimson_trapdoor", + Item::WarpedTrapdoor => "warped_trapdoor", + Item::InfestedStone => "infested_stone", + Item::InfestedCobblestone => "infested_cobblestone", + Item::InfestedStoneBricks => "infested_stone_bricks", + Item::InfestedMossyStoneBricks => "infested_mossy_stone_bricks", + Item::InfestedCrackedStoneBricks => "infested_cracked_stone_bricks", + Item::InfestedChiseledStoneBricks => "infested_chiseled_stone_bricks", + Item::StoneBricks => "stone_bricks", + Item::MossyStoneBricks => "mossy_stone_bricks", + Item::CrackedStoneBricks => "cracked_stone_bricks", + Item::ChiseledStoneBricks => "chiseled_stone_bricks", + Item::BrownMushroomBlock => "brown_mushroom_block", + Item::RedMushroomBlock => "red_mushroom_block", + Item::MushroomStem => "mushroom_stem", + Item::IronBars => "iron_bars", + Item::Chain => "chain", + Item::GlassPane => "glass_pane", + Item::Melon => "melon", + Item::Vine => "vine", + Item::OakFenceGate => "oak_fence_gate", + Item::SpruceFenceGate => "spruce_fence_gate", + Item::BirchFenceGate => "birch_fence_gate", + Item::JungleFenceGate => "jungle_fence_gate", + Item::AcaciaFenceGate => "acacia_fence_gate", + Item::DarkOakFenceGate => "dark_oak_fence_gate", + Item::CrimsonFenceGate => "crimson_fence_gate", + Item::WarpedFenceGate => "warped_fence_gate", + Item::BrickStairs => "brick_stairs", + Item::StoneBrickStairs => "stone_brick_stairs", + Item::Mycelium => "mycelium", + Item::LilyPad => "lily_pad", + Item::NetherBricks => "nether_bricks", + Item::CrackedNetherBricks => "cracked_nether_bricks", + Item::ChiseledNetherBricks => "chiseled_nether_bricks", + Item::NetherBrickFence => "nether_brick_fence", + Item::NetherBrickStairs => "nether_brick_stairs", + Item::EnchantingTable => "enchanting_table", + Item::EndPortalFrame => "end_portal_frame", + Item::EndStone => "end_stone", + Item::EndStoneBricks => "end_stone_bricks", + Item::DragonEgg => "dragon_egg", + Item::RedstoneLamp => "redstone_lamp", + Item::SandstoneStairs => "sandstone_stairs", + Item::EmeraldOre => "emerald_ore", + Item::EnderChest => "ender_chest", + Item::TripwireHook => "tripwire_hook", + Item::EmeraldBlock => "emerald_block", + Item::SpruceStairs => "spruce_stairs", + Item::BirchStairs => "birch_stairs", + Item::JungleStairs => "jungle_stairs", + Item::CrimsonStairs => "crimson_stairs", + Item::WarpedStairs => "warped_stairs", + Item::CommandBlock => "command_block", + Item::Beacon => "beacon", + Item::CobblestoneWall => "cobblestone_wall", + Item::MossyCobblestoneWall => "mossy_cobblestone_wall", + Item::BrickWall => "brick_wall", + Item::PrismarineWall => "prismarine_wall", + Item::RedSandstoneWall => "red_sandstone_wall", + Item::MossyStoneBrickWall => "mossy_stone_brick_wall", + Item::GraniteWall => "granite_wall", + Item::StoneBrickWall => "stone_brick_wall", + Item::NetherBrickWall => "nether_brick_wall", + Item::AndesiteWall => "andesite_wall", + Item::RedNetherBrickWall => "red_nether_brick_wall", + Item::SandstoneWall => "sandstone_wall", + Item::EndStoneBrickWall => "end_stone_brick_wall", + Item::DioriteWall => "diorite_wall", + Item::BlackstoneWall => "blackstone_wall", + Item::PolishedBlackstoneWall => "polished_blackstone_wall", + Item::PolishedBlackstoneBrickWall => "polished_blackstone_brick_wall", + Item::StoneButton => "stone_button", + Item::OakButton => "oak_button", + Item::SpruceButton => "spruce_button", + Item::BirchButton => "birch_button", + Item::JungleButton => "jungle_button", + Item::AcaciaButton => "acacia_button", + Item::DarkOakButton => "dark_oak_button", + Item::CrimsonButton => "crimson_button", + Item::WarpedButton => "warped_button", + Item::PolishedBlackstoneButton => "polished_blackstone_button", + Item::Anvil => "anvil", + Item::ChippedAnvil => "chipped_anvil", + Item::DamagedAnvil => "damaged_anvil", + Item::TrappedChest => "trapped_chest", + Item::LightWeightedPressurePlate => "light_weighted_pressure_plate", + Item::HeavyWeightedPressurePlate => "heavy_weighted_pressure_plate", + Item::DaylightDetector => "daylight_detector", + Item::RedstoneBlock => "redstone_block", + Item::NetherQuartzOre => "nether_quartz_ore", + Item::Hopper => "hopper", + Item::ChiseledQuartzBlock => "chiseled_quartz_block", + Item::QuartzBlock => "quartz_block", + Item::QuartzBricks => "quartz_bricks", + Item::QuartzPillar => "quartz_pillar", + Item::QuartzStairs => "quartz_stairs", + Item::ActivatorRail => "activator_rail", + Item::Dropper => "dropper", + Item::WhiteTerracotta => "white_terracotta", + Item::OrangeTerracotta => "orange_terracotta", + Item::MagentaTerracotta => "magenta_terracotta", + Item::LightBlueTerracotta => "light_blue_terracotta", + Item::YellowTerracotta => "yellow_terracotta", + Item::LimeTerracotta => "lime_terracotta", + Item::PinkTerracotta => "pink_terracotta", + Item::GrayTerracotta => "gray_terracotta", + Item::LightGrayTerracotta => "light_gray_terracotta", + Item::CyanTerracotta => "cyan_terracotta", + Item::PurpleTerracotta => "purple_terracotta", + Item::BlueTerracotta => "blue_terracotta", + Item::BrownTerracotta => "brown_terracotta", + Item::GreenTerracotta => "green_terracotta", + Item::RedTerracotta => "red_terracotta", + Item::BlackTerracotta => "black_terracotta", + Item::Barrier => "barrier", + Item::IronTrapdoor => "iron_trapdoor", + Item::HayBlock => "hay_block", + Item::WhiteCarpet => "white_carpet", + Item::OrangeCarpet => "orange_carpet", + Item::MagentaCarpet => "magenta_carpet", + Item::LightBlueCarpet => "light_blue_carpet", + Item::YellowCarpet => "yellow_carpet", + Item::LimeCarpet => "lime_carpet", + Item::PinkCarpet => "pink_carpet", + Item::GrayCarpet => "gray_carpet", + Item::LightGrayCarpet => "light_gray_carpet", + Item::CyanCarpet => "cyan_carpet", + Item::PurpleCarpet => "purple_carpet", + Item::BlueCarpet => "blue_carpet", + Item::BrownCarpet => "brown_carpet", + Item::GreenCarpet => "green_carpet", + Item::RedCarpet => "red_carpet", + Item::BlackCarpet => "black_carpet", + Item::Terracotta => "terracotta", + Item::CoalBlock => "coal_block", + Item::PackedIce => "packed_ice", + Item::AcaciaStairs => "acacia_stairs", + Item::DarkOakStairs => "dark_oak_stairs", + Item::SlimeBlock => "slime_block", + Item::GrassPath => "grass_path", + Item::Sunflower => "sunflower", + Item::Lilac => "lilac", + Item::RoseBush => "rose_bush", + Item::Peony => "peony", + Item::TallGrass => "tall_grass", + Item::LargeFern => "large_fern", + Item::WhiteStainedGlass => "white_stained_glass", + Item::OrangeStainedGlass => "orange_stained_glass", + Item::MagentaStainedGlass => "magenta_stained_glass", + Item::LightBlueStainedGlass => "light_blue_stained_glass", + Item::YellowStainedGlass => "yellow_stained_glass", + Item::LimeStainedGlass => "lime_stained_glass", + Item::PinkStainedGlass => "pink_stained_glass", + Item::GrayStainedGlass => "gray_stained_glass", + Item::LightGrayStainedGlass => "light_gray_stained_glass", + Item::CyanStainedGlass => "cyan_stained_glass", + Item::PurpleStainedGlass => "purple_stained_glass", + Item::BlueStainedGlass => "blue_stained_glass", + Item::BrownStainedGlass => "brown_stained_glass", + Item::GreenStainedGlass => "green_stained_glass", + Item::RedStainedGlass => "red_stained_glass", + Item::BlackStainedGlass => "black_stained_glass", + Item::WhiteStainedGlassPane => "white_stained_glass_pane", + Item::OrangeStainedGlassPane => "orange_stained_glass_pane", + Item::MagentaStainedGlassPane => "magenta_stained_glass_pane", + Item::LightBlueStainedGlassPane => "light_blue_stained_glass_pane", + Item::YellowStainedGlassPane => "yellow_stained_glass_pane", + Item::LimeStainedGlassPane => "lime_stained_glass_pane", + Item::PinkStainedGlassPane => "pink_stained_glass_pane", + Item::GrayStainedGlassPane => "gray_stained_glass_pane", + Item::LightGrayStainedGlassPane => "light_gray_stained_glass_pane", + Item::CyanStainedGlassPane => "cyan_stained_glass_pane", + Item::PurpleStainedGlassPane => "purple_stained_glass_pane", + Item::BlueStainedGlassPane => "blue_stained_glass_pane", + Item::BrownStainedGlassPane => "brown_stained_glass_pane", + Item::GreenStainedGlassPane => "green_stained_glass_pane", + Item::RedStainedGlassPane => "red_stained_glass_pane", + Item::BlackStainedGlassPane => "black_stained_glass_pane", + Item::Prismarine => "prismarine", + Item::PrismarineBricks => "prismarine_bricks", + Item::DarkPrismarine => "dark_prismarine", + Item::PrismarineStairs => "prismarine_stairs", + Item::PrismarineBrickStairs => "prismarine_brick_stairs", + Item::DarkPrismarineStairs => "dark_prismarine_stairs", + Item::SeaLantern => "sea_lantern", + Item::RedSandstone => "red_sandstone", + Item::ChiseledRedSandstone => "chiseled_red_sandstone", + Item::CutRedSandstone => "cut_red_sandstone", + Item::RedSandstoneStairs => "red_sandstone_stairs", + Item::RepeatingCommandBlock => "repeating_command_block", + Item::ChainCommandBlock => "chain_command_block", + Item::MagmaBlock => "magma_block", + Item::NetherWartBlock => "nether_wart_block", + Item::WarpedWartBlock => "warped_wart_block", + Item::RedNetherBricks => "red_nether_bricks", + Item::BoneBlock => "bone_block", + Item::StructureVoid => "structure_void", + Item::Observer => "observer", + Item::ShulkerBox => "shulker_box", + Item::WhiteShulkerBox => "white_shulker_box", + Item::OrangeShulkerBox => "orange_shulker_box", + Item::MagentaShulkerBox => "magenta_shulker_box", + Item::LightBlueShulkerBox => "light_blue_shulker_box", + Item::YellowShulkerBox => "yellow_shulker_box", + Item::LimeShulkerBox => "lime_shulker_box", + Item::PinkShulkerBox => "pink_shulker_box", + Item::GrayShulkerBox => "gray_shulker_box", + Item::LightGrayShulkerBox => "light_gray_shulker_box", + Item::CyanShulkerBox => "cyan_shulker_box", + Item::PurpleShulkerBox => "purple_shulker_box", + Item::BlueShulkerBox => "blue_shulker_box", + Item::BrownShulkerBox => "brown_shulker_box", + Item::GreenShulkerBox => "green_shulker_box", + Item::RedShulkerBox => "red_shulker_box", + Item::BlackShulkerBox => "black_shulker_box", + Item::WhiteGlazedTerracotta => "white_glazed_terracotta", + Item::OrangeGlazedTerracotta => "orange_glazed_terracotta", + Item::MagentaGlazedTerracotta => "magenta_glazed_terracotta", + Item::LightBlueGlazedTerracotta => "light_blue_glazed_terracotta", + Item::YellowGlazedTerracotta => "yellow_glazed_terracotta", + Item::LimeGlazedTerracotta => "lime_glazed_terracotta", + Item::PinkGlazedTerracotta => "pink_glazed_terracotta", + Item::GrayGlazedTerracotta => "gray_glazed_terracotta", + Item::LightGrayGlazedTerracotta => "light_gray_glazed_terracotta", + Item::CyanGlazedTerracotta => "cyan_glazed_terracotta", + Item::PurpleGlazedTerracotta => "purple_glazed_terracotta", + Item::BlueGlazedTerracotta => "blue_glazed_terracotta", + Item::BrownGlazedTerracotta => "brown_glazed_terracotta", + Item::GreenGlazedTerracotta => "green_glazed_terracotta", + Item::RedGlazedTerracotta => "red_glazed_terracotta", + Item::BlackGlazedTerracotta => "black_glazed_terracotta", + Item::WhiteConcrete => "white_concrete", + Item::OrangeConcrete => "orange_concrete", + Item::MagentaConcrete => "magenta_concrete", + Item::LightBlueConcrete => "light_blue_concrete", + Item::YellowConcrete => "yellow_concrete", + Item::LimeConcrete => "lime_concrete", + Item::PinkConcrete => "pink_concrete", + Item::GrayConcrete => "gray_concrete", + Item::LightGrayConcrete => "light_gray_concrete", + Item::CyanConcrete => "cyan_concrete", + Item::PurpleConcrete => "purple_concrete", + Item::BlueConcrete => "blue_concrete", + Item::BrownConcrete => "brown_concrete", + Item::GreenConcrete => "green_concrete", + Item::RedConcrete => "red_concrete", + Item::BlackConcrete => "black_concrete", + Item::WhiteConcretePowder => "white_concrete_powder", + Item::OrangeConcretePowder => "orange_concrete_powder", + Item::MagentaConcretePowder => "magenta_concrete_powder", + Item::LightBlueConcretePowder => "light_blue_concrete_powder", + Item::YellowConcretePowder => "yellow_concrete_powder", + Item::LimeConcretePowder => "lime_concrete_powder", + Item::PinkConcretePowder => "pink_concrete_powder", + Item::GrayConcretePowder => "gray_concrete_powder", + Item::LightGrayConcretePowder => "light_gray_concrete_powder", + Item::CyanConcretePowder => "cyan_concrete_powder", + Item::PurpleConcretePowder => "purple_concrete_powder", + Item::BlueConcretePowder => "blue_concrete_powder", + Item::BrownConcretePowder => "brown_concrete_powder", + Item::GreenConcretePowder => "green_concrete_powder", + Item::RedConcretePowder => "red_concrete_powder", + Item::BlackConcretePowder => "black_concrete_powder", + Item::TurtleEgg => "turtle_egg", + Item::DeadTubeCoralBlock => "dead_tube_coral_block", + Item::DeadBrainCoralBlock => "dead_brain_coral_block", + Item::DeadBubbleCoralBlock => "dead_bubble_coral_block", + Item::DeadFireCoralBlock => "dead_fire_coral_block", + Item::DeadHornCoralBlock => "dead_horn_coral_block", + Item::TubeCoralBlock => "tube_coral_block", + Item::BrainCoralBlock => "brain_coral_block", + Item::BubbleCoralBlock => "bubble_coral_block", + Item::FireCoralBlock => "fire_coral_block", + Item::HornCoralBlock => "horn_coral_block", + Item::TubeCoral => "tube_coral", + Item::BrainCoral => "brain_coral", + Item::BubbleCoral => "bubble_coral", + Item::FireCoral => "fire_coral", + Item::HornCoral => "horn_coral", + Item::DeadBrainCoral => "dead_brain_coral", + Item::DeadBubbleCoral => "dead_bubble_coral", + Item::DeadFireCoral => "dead_fire_coral", + Item::DeadHornCoral => "dead_horn_coral", + Item::DeadTubeCoral => "dead_tube_coral", + Item::TubeCoralFan => "tube_coral_fan", + Item::BrainCoralFan => "brain_coral_fan", + Item::BubbleCoralFan => "bubble_coral_fan", + Item::FireCoralFan => "fire_coral_fan", + Item::HornCoralFan => "horn_coral_fan", + Item::DeadTubeCoralFan => "dead_tube_coral_fan", + Item::DeadBrainCoralFan => "dead_brain_coral_fan", + Item::DeadBubbleCoralFan => "dead_bubble_coral_fan", + Item::DeadFireCoralFan => "dead_fire_coral_fan", + Item::DeadHornCoralFan => "dead_horn_coral_fan", + Item::BlueIce => "blue_ice", + Item::Conduit => "conduit", + Item::PolishedGraniteStairs => "polished_granite_stairs", + Item::SmoothRedSandstoneStairs => "smooth_red_sandstone_stairs", + Item::MossyStoneBrickStairs => "mossy_stone_brick_stairs", + Item::PolishedDioriteStairs => "polished_diorite_stairs", + Item::MossyCobblestoneStairs => "mossy_cobblestone_stairs", + Item::EndStoneBrickStairs => "end_stone_brick_stairs", + Item::StoneStairs => "stone_stairs", + Item::SmoothSandstoneStairs => "smooth_sandstone_stairs", + Item::SmoothQuartzStairs => "smooth_quartz_stairs", + Item::GraniteStairs => "granite_stairs", + Item::AndesiteStairs => "andesite_stairs", + Item::RedNetherBrickStairs => "red_nether_brick_stairs", + Item::PolishedAndesiteStairs => "polished_andesite_stairs", + Item::DioriteStairs => "diorite_stairs", + Item::PolishedGraniteSlab => "polished_granite_slab", + Item::SmoothRedSandstoneSlab => "smooth_red_sandstone_slab", + Item::MossyStoneBrickSlab => "mossy_stone_brick_slab", + Item::PolishedDioriteSlab => "polished_diorite_slab", + Item::MossyCobblestoneSlab => "mossy_cobblestone_slab", + Item::EndStoneBrickSlab => "end_stone_brick_slab", + Item::SmoothSandstoneSlab => "smooth_sandstone_slab", + Item::SmoothQuartzSlab => "smooth_quartz_slab", + Item::GraniteSlab => "granite_slab", + Item::AndesiteSlab => "andesite_slab", + Item::RedNetherBrickSlab => "red_nether_brick_slab", + Item::PolishedAndesiteSlab => "polished_andesite_slab", + Item::DioriteSlab => "diorite_slab", + Item::Scaffolding => "scaffolding", + Item::IronDoor => "iron_door", + Item::OakDoor => "oak_door", + Item::SpruceDoor => "spruce_door", + Item::BirchDoor => "birch_door", + Item::JungleDoor => "jungle_door", + Item::AcaciaDoor => "acacia_door", + Item::DarkOakDoor => "dark_oak_door", + Item::CrimsonDoor => "crimson_door", + Item::WarpedDoor => "warped_door", + Item::Repeater => "repeater", + Item::Comparator => "comparator", + Item::StructureBlock => "structure_block", + Item::Jigsaw => "jigsaw", + Item::TurtleHelmet => "turtle_helmet", + Item::Scute => "scute", + Item::FlintAndSteel => "flint_and_steel", + Item::Apple => "apple", + Item::Bow => "bow", + Item::Arrow => "arrow", + Item::Coal => "coal", + Item::Charcoal => "charcoal", + Item::Diamond => "diamond", + Item::IronIngot => "iron_ingot", + Item::GoldIngot => "gold_ingot", + Item::NetheriteIngot => "netherite_ingot", + Item::NetheriteScrap => "netherite_scrap", + Item::WoodenSword => "wooden_sword", + Item::WoodenShovel => "wooden_shovel", + Item::WoodenPickaxe => "wooden_pickaxe", + Item::WoodenAxe => "wooden_axe", + Item::WoodenHoe => "wooden_hoe", + Item::StoneSword => "stone_sword", + Item::StoneShovel => "stone_shovel", + Item::StonePickaxe => "stone_pickaxe", + Item::StoneAxe => "stone_axe", + Item::StoneHoe => "stone_hoe", + Item::GoldenSword => "golden_sword", + Item::GoldenShovel => "golden_shovel", + Item::GoldenPickaxe => "golden_pickaxe", + Item::GoldenAxe => "golden_axe", + Item::GoldenHoe => "golden_hoe", + Item::IronSword => "iron_sword", + Item::IronShovel => "iron_shovel", + Item::IronPickaxe => "iron_pickaxe", + Item::IronAxe => "iron_axe", + Item::IronHoe => "iron_hoe", + Item::DiamondSword => "diamond_sword", + Item::DiamondShovel => "diamond_shovel", + Item::DiamondPickaxe => "diamond_pickaxe", + Item::DiamondAxe => "diamond_axe", + Item::DiamondHoe => "diamond_hoe", + Item::NetheriteSword => "netherite_sword", + Item::NetheriteShovel => "netherite_shovel", + Item::NetheritePickaxe => "netherite_pickaxe", + Item::NetheriteAxe => "netherite_axe", + Item::NetheriteHoe => "netherite_hoe", + Item::Stick => "stick", + Item::Bowl => "bowl", + Item::MushroomStew => "mushroom_stew", + Item::String => "string", + Item::Feather => "feather", + Item::Gunpowder => "gunpowder", + Item::WheatSeeds => "wheat_seeds", + Item::Wheat => "wheat", + Item::Bread => "bread", + Item::LeatherHelmet => "leather_helmet", + Item::LeatherChestplate => "leather_chestplate", + Item::LeatherLeggings => "leather_leggings", + Item::LeatherBoots => "leather_boots", + Item::ChainmailHelmet => "chainmail_helmet", + Item::ChainmailChestplate => "chainmail_chestplate", + Item::ChainmailLeggings => "chainmail_leggings", + Item::ChainmailBoots => "chainmail_boots", + Item::IronHelmet => "iron_helmet", + Item::IronChestplate => "iron_chestplate", + Item::IronLeggings => "iron_leggings", + Item::IronBoots => "iron_boots", + Item::DiamondHelmet => "diamond_helmet", + Item::DiamondChestplate => "diamond_chestplate", + Item::DiamondLeggings => "diamond_leggings", + Item::DiamondBoots => "diamond_boots", + Item::GoldenHelmet => "golden_helmet", + Item::GoldenChestplate => "golden_chestplate", + Item::GoldenLeggings => "golden_leggings", + Item::GoldenBoots => "golden_boots", + Item::NetheriteHelmet => "netherite_helmet", + Item::NetheriteChestplate => "netherite_chestplate", + Item::NetheriteLeggings => "netherite_leggings", + Item::NetheriteBoots => "netherite_boots", + Item::Flint => "flint", + Item::Porkchop => "porkchop", + Item::CookedPorkchop => "cooked_porkchop", + Item::Painting => "painting", + Item::GoldenApple => "golden_apple", + Item::EnchantedGoldenApple => "enchanted_golden_apple", + Item::OakSign => "oak_sign", + Item::SpruceSign => "spruce_sign", + Item::BirchSign => "birch_sign", + Item::JungleSign => "jungle_sign", + Item::AcaciaSign => "acacia_sign", + Item::DarkOakSign => "dark_oak_sign", + Item::CrimsonSign => "crimson_sign", + Item::WarpedSign => "warped_sign", + Item::Bucket => "bucket", + Item::WaterBucket => "water_bucket", + Item::LavaBucket => "lava_bucket", + Item::Minecart => "minecart", + Item::Saddle => "saddle", + Item::Redstone => "redstone", + Item::Snowball => "snowball", + Item::OakBoat => "oak_boat", + Item::Leather => "leather", + Item::MilkBucket => "milk_bucket", + Item::PufferfishBucket => "pufferfish_bucket", + Item::SalmonBucket => "salmon_bucket", + Item::CodBucket => "cod_bucket", + Item::TropicalFishBucket => "tropical_fish_bucket", + Item::Brick => "brick", + Item::ClayBall => "clay_ball", + Item::DriedKelpBlock => "dried_kelp_block", + Item::Paper => "paper", + Item::Book => "book", + Item::SlimeBall => "slime_ball", + Item::ChestMinecart => "chest_minecart", + Item::FurnaceMinecart => "furnace_minecart", + Item::Egg => "egg", + Item::Compass => "compass", + Item::FishingRod => "fishing_rod", + Item::Clock => "clock", + Item::GlowstoneDust => "glowstone_dust", + Item::Cod => "cod", + Item::Salmon => "salmon", + Item::TropicalFish => "tropical_fish", + Item::Pufferfish => "pufferfish", + Item::CookedCod => "cooked_cod", + Item::CookedSalmon => "cooked_salmon", + Item::InkSac => "ink_sac", + Item::CocoaBeans => "cocoa_beans", + Item::LapisLazuli => "lapis_lazuli", + Item::WhiteDye => "white_dye", + Item::OrangeDye => "orange_dye", + Item::MagentaDye => "magenta_dye", + Item::LightBlueDye => "light_blue_dye", + Item::YellowDye => "yellow_dye", + Item::LimeDye => "lime_dye", + Item::PinkDye => "pink_dye", + Item::GrayDye => "gray_dye", + Item::LightGrayDye => "light_gray_dye", + Item::CyanDye => "cyan_dye", + Item::PurpleDye => "purple_dye", + Item::BlueDye => "blue_dye", + Item::BrownDye => "brown_dye", + Item::GreenDye => "green_dye", + Item::RedDye => "red_dye", + Item::BlackDye => "black_dye", + Item::BoneMeal => "bone_meal", + Item::Bone => "bone", + Item::Sugar => "sugar", + Item::Cake => "cake", + Item::WhiteBed => "white_bed", + Item::OrangeBed => "orange_bed", + Item::MagentaBed => "magenta_bed", + Item::LightBlueBed => "light_blue_bed", + Item::YellowBed => "yellow_bed", + Item::LimeBed => "lime_bed", + Item::PinkBed => "pink_bed", + Item::GrayBed => "gray_bed", + Item::LightGrayBed => "light_gray_bed", + Item::CyanBed => "cyan_bed", + Item::PurpleBed => "purple_bed", + Item::BlueBed => "blue_bed", + Item::BrownBed => "brown_bed", + Item::GreenBed => "green_bed", + Item::RedBed => "red_bed", + Item::BlackBed => "black_bed", + Item::Cookie => "cookie", + Item::FilledMap => "filled_map", + Item::Shears => "shears", + Item::MelonSlice => "melon_slice", + Item::DriedKelp => "dried_kelp", + Item::PumpkinSeeds => "pumpkin_seeds", + Item::MelonSeeds => "melon_seeds", + Item::Beef => "beef", + Item::CookedBeef => "cooked_beef", + Item::Chicken => "chicken", + Item::CookedChicken => "cooked_chicken", + Item::RottenFlesh => "rotten_flesh", + Item::EnderPearl => "ender_pearl", + Item::BlazeRod => "blaze_rod", + Item::GhastTear => "ghast_tear", + Item::GoldNugget => "gold_nugget", + Item::NetherWart => "nether_wart", + Item::Potion => "potion", + Item::GlassBottle => "glass_bottle", + Item::SpiderEye => "spider_eye", + Item::FermentedSpiderEye => "fermented_spider_eye", + Item::BlazePowder => "blaze_powder", + Item::MagmaCream => "magma_cream", + Item::BrewingStand => "brewing_stand", + Item::Cauldron => "cauldron", + Item::EnderEye => "ender_eye", + Item::GlisteringMelonSlice => "glistering_melon_slice", + Item::BatSpawnEgg => "bat_spawn_egg", + Item::BeeSpawnEgg => "bee_spawn_egg", + Item::BlazeSpawnEgg => "blaze_spawn_egg", + Item::CatSpawnEgg => "cat_spawn_egg", + Item::CaveSpiderSpawnEgg => "cave_spider_spawn_egg", + Item::ChickenSpawnEgg => "chicken_spawn_egg", + Item::CodSpawnEgg => "cod_spawn_egg", + Item::CowSpawnEgg => "cow_spawn_egg", + Item::CreeperSpawnEgg => "creeper_spawn_egg", + Item::DolphinSpawnEgg => "dolphin_spawn_egg", + Item::DonkeySpawnEgg => "donkey_spawn_egg", + Item::DrownedSpawnEgg => "drowned_spawn_egg", + Item::ElderGuardianSpawnEgg => "elder_guardian_spawn_egg", + Item::EndermanSpawnEgg => "enderman_spawn_egg", + Item::EndermiteSpawnEgg => "endermite_spawn_egg", + Item::EvokerSpawnEgg => "evoker_spawn_egg", + Item::FoxSpawnEgg => "fox_spawn_egg", + Item::GhastSpawnEgg => "ghast_spawn_egg", + Item::GuardianSpawnEgg => "guardian_spawn_egg", + Item::HoglinSpawnEgg => "hoglin_spawn_egg", + Item::HorseSpawnEgg => "horse_spawn_egg", + Item::HuskSpawnEgg => "husk_spawn_egg", + Item::LlamaSpawnEgg => "llama_spawn_egg", + Item::MagmaCubeSpawnEgg => "magma_cube_spawn_egg", + Item::MooshroomSpawnEgg => "mooshroom_spawn_egg", + Item::MuleSpawnEgg => "mule_spawn_egg", + Item::OcelotSpawnEgg => "ocelot_spawn_egg", + Item::PandaSpawnEgg => "panda_spawn_egg", + Item::ParrotSpawnEgg => "parrot_spawn_egg", + Item::PhantomSpawnEgg => "phantom_spawn_egg", + Item::PigSpawnEgg => "pig_spawn_egg", + Item::PiglinSpawnEgg => "piglin_spawn_egg", + Item::PiglinBruteSpawnEgg => "piglin_brute_spawn_egg", + Item::PillagerSpawnEgg => "pillager_spawn_egg", + Item::PolarBearSpawnEgg => "polar_bear_spawn_egg", + Item::PufferfishSpawnEgg => "pufferfish_spawn_egg", + Item::RabbitSpawnEgg => "rabbit_spawn_egg", + Item::RavagerSpawnEgg => "ravager_spawn_egg", + Item::SalmonSpawnEgg => "salmon_spawn_egg", + Item::SheepSpawnEgg => "sheep_spawn_egg", + Item::ShulkerSpawnEgg => "shulker_spawn_egg", + Item::SilverfishSpawnEgg => "silverfish_spawn_egg", + Item::SkeletonSpawnEgg => "skeleton_spawn_egg", + Item::SkeletonHorseSpawnEgg => "skeleton_horse_spawn_egg", + Item::SlimeSpawnEgg => "slime_spawn_egg", + Item::SpiderSpawnEgg => "spider_spawn_egg", + Item::SquidSpawnEgg => "squid_spawn_egg", + Item::StraySpawnEgg => "stray_spawn_egg", + Item::StriderSpawnEgg => "strider_spawn_egg", + Item::TraderLlamaSpawnEgg => "trader_llama_spawn_egg", + Item::TropicalFishSpawnEgg => "tropical_fish_spawn_egg", + Item::TurtleSpawnEgg => "turtle_spawn_egg", + Item::VexSpawnEgg => "vex_spawn_egg", + Item::VillagerSpawnEgg => "villager_spawn_egg", + Item::VindicatorSpawnEgg => "vindicator_spawn_egg", + Item::WanderingTraderSpawnEgg => "wandering_trader_spawn_egg", + Item::WitchSpawnEgg => "witch_spawn_egg", + Item::WitherSkeletonSpawnEgg => "wither_skeleton_spawn_egg", + Item::WolfSpawnEgg => "wolf_spawn_egg", + Item::ZoglinSpawnEgg => "zoglin_spawn_egg", + Item::ZombieSpawnEgg => "zombie_spawn_egg", + Item::ZombieHorseSpawnEgg => "zombie_horse_spawn_egg", + Item::ZombieVillagerSpawnEgg => "zombie_villager_spawn_egg", + Item::ZombifiedPiglinSpawnEgg => "zombified_piglin_spawn_egg", + Item::ExperienceBottle => "experience_bottle", + Item::FireCharge => "fire_charge", + Item::WritableBook => "writable_book", + Item::WrittenBook => "written_book", + Item::Emerald => "emerald", + Item::ItemFrame => "item_frame", + Item::FlowerPot => "flower_pot", + Item::Carrot => "carrot", + Item::Potato => "potato", + Item::BakedPotato => "baked_potato", + Item::PoisonousPotato => "poisonous_potato", + Item::Map => "map", + Item::GoldenCarrot => "golden_carrot", + Item::SkeletonSkull => "skeleton_skull", + Item::WitherSkeletonSkull => "wither_skeleton_skull", + Item::PlayerHead => "player_head", + Item::ZombieHead => "zombie_head", + Item::CreeperHead => "creeper_head", + Item::DragonHead => "dragon_head", + Item::CarrotOnAStick => "carrot_on_a_stick", + Item::WarpedFungusOnAStick => "warped_fungus_on_a_stick", + Item::NetherStar => "nether_star", + Item::PumpkinPie => "pumpkin_pie", + Item::FireworkRocket => "firework_rocket", + Item::FireworkStar => "firework_star", + Item::EnchantedBook => "enchanted_book", + Item::NetherBrick => "nether_brick", + Item::Quartz => "quartz", + Item::TntMinecart => "tnt_minecart", + Item::HopperMinecart => "hopper_minecart", + Item::PrismarineShard => "prismarine_shard", + Item::PrismarineCrystals => "prismarine_crystals", + Item::Rabbit => "rabbit", + Item::CookedRabbit => "cooked_rabbit", + Item::RabbitStew => "rabbit_stew", + Item::RabbitFoot => "rabbit_foot", + Item::RabbitHide => "rabbit_hide", + Item::ArmorStand => "armor_stand", + Item::IronHorseArmor => "iron_horse_armor", + Item::GoldenHorseArmor => "golden_horse_armor", + Item::DiamondHorseArmor => "diamond_horse_armor", + Item::LeatherHorseArmor => "leather_horse_armor", + Item::Lead => "lead", + Item::NameTag => "name_tag", + Item::CommandBlockMinecart => "command_block_minecart", + Item::Mutton => "mutton", + Item::CookedMutton => "cooked_mutton", + Item::WhiteBanner => "white_banner", + Item::OrangeBanner => "orange_banner", + Item::MagentaBanner => "magenta_banner", + Item::LightBlueBanner => "light_blue_banner", + Item::YellowBanner => "yellow_banner", + Item::LimeBanner => "lime_banner", + Item::PinkBanner => "pink_banner", + Item::GrayBanner => "gray_banner", + Item::LightGrayBanner => "light_gray_banner", + Item::CyanBanner => "cyan_banner", + Item::PurpleBanner => "purple_banner", + Item::BlueBanner => "blue_banner", + Item::BrownBanner => "brown_banner", + Item::GreenBanner => "green_banner", + Item::RedBanner => "red_banner", + Item::BlackBanner => "black_banner", + Item::EndCrystal => "end_crystal", + Item::ChorusFruit => "chorus_fruit", + Item::PoppedChorusFruit => "popped_chorus_fruit", + Item::Beetroot => "beetroot", + Item::BeetrootSeeds => "beetroot_seeds", + Item::BeetrootSoup => "beetroot_soup", + Item::DragonBreath => "dragon_breath", + Item::SplashPotion => "splash_potion", + Item::SpectralArrow => "spectral_arrow", + Item::TippedArrow => "tipped_arrow", + Item::LingeringPotion => "lingering_potion", + Item::Shield => "shield", + Item::Elytra => "elytra", + Item::SpruceBoat => "spruce_boat", + Item::BirchBoat => "birch_boat", + Item::JungleBoat => "jungle_boat", + Item::AcaciaBoat => "acacia_boat", + Item::DarkOakBoat => "dark_oak_boat", + Item::TotemOfUndying => "totem_of_undying", + Item::ShulkerShell => "shulker_shell", + Item::IronNugget => "iron_nugget", + Item::KnowledgeBook => "knowledge_book", + Item::DebugStick => "debug_stick", + Item::MusicDisc13 => "music_disc_13", + Item::MusicDiscCat => "music_disc_cat", + Item::MusicDiscBlocks => "music_disc_blocks", + Item::MusicDiscChirp => "music_disc_chirp", + Item::MusicDiscFar => "music_disc_far", + Item::MusicDiscMall => "music_disc_mall", + Item::MusicDiscMellohi => "music_disc_mellohi", + Item::MusicDiscStal => "music_disc_stal", + Item::MusicDiscStrad => "music_disc_strad", + Item::MusicDiscWard => "music_disc_ward", + Item::MusicDisc11 => "music_disc_11", + Item::MusicDiscWait => "music_disc_wait", + Item::MusicDiscPigstep => "music_disc_pigstep", + Item::Trident => "trident", + Item::PhantomMembrane => "phantom_membrane", + Item::NautilusShell => "nautilus_shell", + Item::HeartOfTheSea => "heart_of_the_sea", + Item::Crossbow => "crossbow", + Item::SuspiciousStew => "suspicious_stew", + Item::Loom => "loom", + Item::FlowerBannerPattern => "flower_banner_pattern", + Item::CreeperBannerPattern => "creeper_banner_pattern", + Item::SkullBannerPattern => "skull_banner_pattern", + Item::MojangBannerPattern => "mojang_banner_pattern", + Item::GlobeBannerPattern => "globe_banner_pattern", + Item::PiglinBannerPattern => "piglin_banner_pattern", + Item::Composter => "composter", + Item::Barrel => "barrel", + Item::Smoker => "smoker", + Item::BlastFurnace => "blast_furnace", + Item::CartographyTable => "cartography_table", + Item::FletchingTable => "fletching_table", + Item::Grindstone => "grindstone", + Item::Lectern => "lectern", + Item::SmithingTable => "smithing_table", + Item::Stonecutter => "stonecutter", + Item::Bell => "bell", + Item::Lantern => "lantern", + Item::SoulLantern => "soul_lantern", + Item::SweetBerries => "sweet_berries", + Item::Campfire => "campfire", + Item::SoulCampfire => "soul_campfire", + Item::Shroomlight => "shroomlight", + Item::Honeycomb => "honeycomb", + Item::BeeNest => "bee_nest", + Item::Beehive => "beehive", + Item::HoneyBottle => "honey_bottle", + Item::HoneyBlock => "honey_block", + Item::HoneycombBlock => "honeycomb_block", + Item::Lodestone => "lodestone", + Item::NetheriteBlock => "netherite_block", + Item::AncientDebris => "ancient_debris", + Item::Target => "target", + Item::CryingObsidian => "crying_obsidian", + Item::Blackstone => "blackstone", + Item::BlackstoneSlab => "blackstone_slab", + Item::BlackstoneStairs => "blackstone_stairs", + Item::GildedBlackstone => "gilded_blackstone", + Item::PolishedBlackstone => "polished_blackstone", + Item::PolishedBlackstoneSlab => "polished_blackstone_slab", + Item::PolishedBlackstoneStairs => "polished_blackstone_stairs", + Item::ChiseledPolishedBlackstone => "chiseled_polished_blackstone", + Item::PolishedBlackstoneBricks => "polished_blackstone_bricks", + Item::PolishedBlackstoneBrickSlab => "polished_blackstone_brick_slab", + Item::PolishedBlackstoneBrickStairs => "polished_blackstone_brick_stairs", + Item::CrackedPolishedBlackstoneBricks => "cracked_polished_blackstone_bricks", + Item::RespawnAnchor => "respawn_anchor", + } + } + + /// Gets a `Item` by its `name`. + pub fn from_name(name: &str) -> Option<Self> { + match name { + "air" => Some(Item::Air), + "stone" => Some(Item::Stone), + "granite" => Some(Item::Granite), + "polished_granite" => Some(Item::PolishedGranite), + "diorite" => Some(Item::Diorite), + "polished_diorite" => Some(Item::PolishedDiorite), + "andesite" => Some(Item::Andesite), + "polished_andesite" => Some(Item::PolishedAndesite), + "grass_block" => Some(Item::GrassBlock), + "dirt" => Some(Item::Dirt), + "coarse_dirt" => Some(Item::CoarseDirt), + "podzol" => Some(Item::Podzol), + "crimson_nylium" => Some(Item::CrimsonNylium), + "warped_nylium" => Some(Item::WarpedNylium), + "cobblestone" => Some(Item::Cobblestone), + "oak_planks" => Some(Item::OakPlanks), + "spruce_planks" => Some(Item::SprucePlanks), + "birch_planks" => Some(Item::BirchPlanks), + "jungle_planks" => Some(Item::JunglePlanks), + "acacia_planks" => Some(Item::AcaciaPlanks), + "dark_oak_planks" => Some(Item::DarkOakPlanks), + "crimson_planks" => Some(Item::CrimsonPlanks), + "warped_planks" => Some(Item::WarpedPlanks), + "oak_sapling" => Some(Item::OakSapling), + "spruce_sapling" => Some(Item::SpruceSapling), + "birch_sapling" => Some(Item::BirchSapling), + "jungle_sapling" => Some(Item::JungleSapling), + "acacia_sapling" => Some(Item::AcaciaSapling), + "dark_oak_sapling" => Some(Item::DarkOakSapling), + "bedrock" => Some(Item::Bedrock), + "sand" => Some(Item::Sand), + "red_sand" => Some(Item::RedSand), + "gravel" => Some(Item::Gravel), + "gold_ore" => Some(Item::GoldOre), + "iron_ore" => Some(Item::IronOre), + "coal_ore" => Some(Item::CoalOre), + "nether_gold_ore" => Some(Item::NetherGoldOre), + "oak_log" => Some(Item::OakLog), + "spruce_log" => Some(Item::SpruceLog), + "birch_log" => Some(Item::BirchLog), + "jungle_log" => Some(Item::JungleLog), + "acacia_log" => Some(Item::AcaciaLog), + "dark_oak_log" => Some(Item::DarkOakLog), + "crimson_stem" => Some(Item::CrimsonStem), + "warped_stem" => Some(Item::WarpedStem), + "stripped_oak_log" => Some(Item::StrippedOakLog), + "stripped_spruce_log" => Some(Item::StrippedSpruceLog), + "stripped_birch_log" => Some(Item::StrippedBirchLog), + "stripped_jungle_log" => Some(Item::StrippedJungleLog), + "stripped_acacia_log" => Some(Item::StrippedAcaciaLog), + "stripped_dark_oak_log" => Some(Item::StrippedDarkOakLog), + "stripped_crimson_stem" => Some(Item::StrippedCrimsonStem), + "stripped_warped_stem" => Some(Item::StrippedWarpedStem), + "stripped_oak_wood" => Some(Item::StrippedOakWood), + "stripped_spruce_wood" => Some(Item::StrippedSpruceWood), + "stripped_birch_wood" => Some(Item::StrippedBirchWood), + "stripped_jungle_wood" => Some(Item::StrippedJungleWood), + "stripped_acacia_wood" => Some(Item::StrippedAcaciaWood), + "stripped_dark_oak_wood" => Some(Item::StrippedDarkOakWood), + "stripped_crimson_hyphae" => Some(Item::StrippedCrimsonHyphae), + "stripped_warped_hyphae" => Some(Item::StrippedWarpedHyphae), + "oak_wood" => Some(Item::OakWood), + "spruce_wood" => Some(Item::SpruceWood), + "birch_wood" => Some(Item::BirchWood), + "jungle_wood" => Some(Item::JungleWood), + "acacia_wood" => Some(Item::AcaciaWood), + "dark_oak_wood" => Some(Item::DarkOakWood), + "crimson_hyphae" => Some(Item::CrimsonHyphae), + "warped_hyphae" => Some(Item::WarpedHyphae), + "oak_leaves" => Some(Item::OakLeaves), + "spruce_leaves" => Some(Item::SpruceLeaves), + "birch_leaves" => Some(Item::BirchLeaves), + "jungle_leaves" => Some(Item::JungleLeaves), + "acacia_leaves" => Some(Item::AcaciaLeaves), + "dark_oak_leaves" => Some(Item::DarkOakLeaves), + "sponge" => Some(Item::Sponge), + "wet_sponge" => Some(Item::WetSponge), + "glass" => Some(Item::Glass), + "lapis_ore" => Some(Item::LapisOre), + "lapis_block" => Some(Item::LapisBlock), + "dispenser" => Some(Item::Dispenser), + "sandstone" => Some(Item::Sandstone), + "chiseled_sandstone" => Some(Item::ChiseledSandstone), + "cut_sandstone" => Some(Item::CutSandstone), + "note_block" => Some(Item::NoteBlock), + "powered_rail" => Some(Item::PoweredRail), + "detector_rail" => Some(Item::DetectorRail), + "sticky_piston" => Some(Item::StickyPiston), + "cobweb" => Some(Item::Cobweb), + "grass" => Some(Item::Grass), + "fern" => Some(Item::Fern), + "dead_bush" => Some(Item::DeadBush), + "seagrass" => Some(Item::Seagrass), + "sea_pickle" => Some(Item::SeaPickle), + "piston" => Some(Item::Piston), + "white_wool" => Some(Item::WhiteWool), + "orange_wool" => Some(Item::OrangeWool), + "magenta_wool" => Some(Item::MagentaWool), + "light_blue_wool" => Some(Item::LightBlueWool), + "yellow_wool" => Some(Item::YellowWool), + "lime_wool" => Some(Item::LimeWool), + "pink_wool" => Some(Item::PinkWool), + "gray_wool" => Some(Item::GrayWool), + "light_gray_wool" => Some(Item::LightGrayWool), + "cyan_wool" => Some(Item::CyanWool), + "purple_wool" => Some(Item::PurpleWool), + "blue_wool" => Some(Item::BlueWool), + "brown_wool" => Some(Item::BrownWool), + "green_wool" => Some(Item::GreenWool), + "red_wool" => Some(Item::RedWool), + "black_wool" => Some(Item::BlackWool), + "dandelion" => Some(Item::Dandelion), + "poppy" => Some(Item::Poppy), + "blue_orchid" => Some(Item::BlueOrchid), + "allium" => Some(Item::Allium), + "azure_bluet" => Some(Item::AzureBluet), + "red_tulip" => Some(Item::RedTulip), + "orange_tulip" => Some(Item::OrangeTulip), + "white_tulip" => Some(Item::WhiteTulip), + "pink_tulip" => Some(Item::PinkTulip), + "oxeye_daisy" => Some(Item::OxeyeDaisy), + "cornflower" => Some(Item::Cornflower), + "lily_of_the_valley" => Some(Item::LilyOfTheValley), + "wither_rose" => Some(Item::WitherRose), + "brown_mushroom" => Some(Item::BrownMushroom), + "red_mushroom" => Some(Item::RedMushroom), + "crimson_fungus" => Some(Item::CrimsonFungus), + "warped_fungus" => Some(Item::WarpedFungus), + "crimson_roots" => Some(Item::CrimsonRoots), + "warped_roots" => Some(Item::WarpedRoots), + "nether_sprouts" => Some(Item::NetherSprouts), + "weeping_vines" => Some(Item::WeepingVines), + "twisting_vines" => Some(Item::TwistingVines), + "sugar_cane" => Some(Item::SugarCane), + "kelp" => Some(Item::Kelp), + "bamboo" => Some(Item::Bamboo), + "gold_block" => Some(Item::GoldBlock), + "iron_block" => Some(Item::IronBlock), + "oak_slab" => Some(Item::OakSlab), + "spruce_slab" => Some(Item::SpruceSlab), + "birch_slab" => Some(Item::BirchSlab), + "jungle_slab" => Some(Item::JungleSlab), + "acacia_slab" => Some(Item::AcaciaSlab), + "dark_oak_slab" => Some(Item::DarkOakSlab), + "crimson_slab" => Some(Item::CrimsonSlab), + "warped_slab" => Some(Item::WarpedSlab), + "stone_slab" => Some(Item::StoneSlab), + "smooth_stone_slab" => Some(Item::SmoothStoneSlab), + "sandstone_slab" => Some(Item::SandstoneSlab), + "cut_sandstone_slab" => Some(Item::CutSandstoneSlab), + "petrified_oak_slab" => Some(Item::PetrifiedOakSlab), + "cobblestone_slab" => Some(Item::CobblestoneSlab), + "brick_slab" => Some(Item::BrickSlab), + "stone_brick_slab" => Some(Item::StoneBrickSlab), + "nether_brick_slab" => Some(Item::NetherBrickSlab), + "quartz_slab" => Some(Item::QuartzSlab), + "red_sandstone_slab" => Some(Item::RedSandstoneSlab), + "cut_red_sandstone_slab" => Some(Item::CutRedSandstoneSlab), + "purpur_slab" => Some(Item::PurpurSlab), + "prismarine_slab" => Some(Item::PrismarineSlab), + "prismarine_brick_slab" => Some(Item::PrismarineBrickSlab), + "dark_prismarine_slab" => Some(Item::DarkPrismarineSlab), + "smooth_quartz" => Some(Item::SmoothQuartz), + "smooth_red_sandstone" => Some(Item::SmoothRedSandstone), + "smooth_sandstone" => Some(Item::SmoothSandstone), + "smooth_stone" => Some(Item::SmoothStone), + "bricks" => Some(Item::Bricks), + "tnt" => Some(Item::Tnt), + "bookshelf" => Some(Item::Bookshelf), + "mossy_cobblestone" => Some(Item::MossyCobblestone), + "obsidian" => Some(Item::Obsidian), + "torch" => Some(Item::Torch), + "end_rod" => Some(Item::EndRod), + "chorus_plant" => Some(Item::ChorusPlant), + "chorus_flower" => Some(Item::ChorusFlower), + "purpur_block" => Some(Item::PurpurBlock), + "purpur_pillar" => Some(Item::PurpurPillar), + "purpur_stairs" => Some(Item::PurpurStairs), + "spawner" => Some(Item::Spawner), + "oak_stairs" => Some(Item::OakStairs), + "chest" => Some(Item::Chest), + "diamond_ore" => Some(Item::DiamondOre), + "diamond_block" => Some(Item::DiamondBlock), + "crafting_table" => Some(Item::CraftingTable), + "farmland" => Some(Item::Farmland), + "furnace" => Some(Item::Furnace), + "ladder" => Some(Item::Ladder), + "rail" => Some(Item::Rail), + "cobblestone_stairs" => Some(Item::CobblestoneStairs), + "lever" => Some(Item::Lever), + "stone_pressure_plate" => Some(Item::StonePressurePlate), + "oak_pressure_plate" => Some(Item::OakPressurePlate), + "spruce_pressure_plate" => Some(Item::SprucePressurePlate), + "birch_pressure_plate" => Some(Item::BirchPressurePlate), + "jungle_pressure_plate" => Some(Item::JunglePressurePlate), + "acacia_pressure_plate" => Some(Item::AcaciaPressurePlate), + "dark_oak_pressure_plate" => Some(Item::DarkOakPressurePlate), + "crimson_pressure_plate" => Some(Item::CrimsonPressurePlate), + "warped_pressure_plate" => Some(Item::WarpedPressurePlate), + "polished_blackstone_pressure_plate" => Some(Item::PolishedBlackstonePressurePlate), + "redstone_ore" => Some(Item::RedstoneOre), + "redstone_torch" => Some(Item::RedstoneTorch), + "snow" => Some(Item::Snow), + "ice" => Some(Item::Ice), + "snow_block" => Some(Item::SnowBlock), + "cactus" => Some(Item::Cactus), + "clay" => Some(Item::Clay), + "jukebox" => Some(Item::Jukebox), + "oak_fence" => Some(Item::OakFence), + "spruce_fence" => Some(Item::SpruceFence), + "birch_fence" => Some(Item::BirchFence), + "jungle_fence" => Some(Item::JungleFence), + "acacia_fence" => Some(Item::AcaciaFence), + "dark_oak_fence" => Some(Item::DarkOakFence), + "crimson_fence" => Some(Item::CrimsonFence), + "warped_fence" => Some(Item::WarpedFence), + "pumpkin" => Some(Item::Pumpkin), + "carved_pumpkin" => Some(Item::CarvedPumpkin), + "netherrack" => Some(Item::Netherrack), + "soul_sand" => Some(Item::SoulSand), + "soul_soil" => Some(Item::SoulSoil), + "basalt" => Some(Item::Basalt), + "polished_basalt" => Some(Item::PolishedBasalt), + "soul_torch" => Some(Item::SoulTorch), + "glowstone" => Some(Item::Glowstone), + "jack_o_lantern" => Some(Item::JackOLantern), + "oak_trapdoor" => Some(Item::OakTrapdoor), + "spruce_trapdoor" => Some(Item::SpruceTrapdoor), + "birch_trapdoor" => Some(Item::BirchTrapdoor), + "jungle_trapdoor" => Some(Item::JungleTrapdoor), + "acacia_trapdoor" => Some(Item::AcaciaTrapdoor), + "dark_oak_trapdoor" => Some(Item::DarkOakTrapdoor), + "crimson_trapdoor" => Some(Item::CrimsonTrapdoor), + "warped_trapdoor" => Some(Item::WarpedTrapdoor), + "infested_stone" => Some(Item::InfestedStone), + "infested_cobblestone" => Some(Item::InfestedCobblestone), + "infested_stone_bricks" => Some(Item::InfestedStoneBricks), + "infested_mossy_stone_bricks" => Some(Item::InfestedMossyStoneBricks), + "infested_cracked_stone_bricks" => Some(Item::InfestedCrackedStoneBricks), + "infested_chiseled_stone_bricks" => Some(Item::InfestedChiseledStoneBricks), + "stone_bricks" => Some(Item::StoneBricks), + "mossy_stone_bricks" => Some(Item::MossyStoneBricks), + "cracked_stone_bricks" => Some(Item::CrackedStoneBricks), + "chiseled_stone_bricks" => Some(Item::ChiseledStoneBricks), + "brown_mushroom_block" => Some(Item::BrownMushroomBlock), + "red_mushroom_block" => Some(Item::RedMushroomBlock), + "mushroom_stem" => Some(Item::MushroomStem), + "iron_bars" => Some(Item::IronBars), + "chain" => Some(Item::Chain), + "glass_pane" => Some(Item::GlassPane), + "melon" => Some(Item::Melon), + "vine" => Some(Item::Vine), + "oak_fence_gate" => Some(Item::OakFenceGate), + "spruce_fence_gate" => Some(Item::SpruceFenceGate), + "birch_fence_gate" => Some(Item::BirchFenceGate), + "jungle_fence_gate" => Some(Item::JungleFenceGate), + "acacia_fence_gate" => Some(Item::AcaciaFenceGate), + "dark_oak_fence_gate" => Some(Item::DarkOakFenceGate), + "crimson_fence_gate" => Some(Item::CrimsonFenceGate), + "warped_fence_gate" => Some(Item::WarpedFenceGate), + "brick_stairs" => Some(Item::BrickStairs), + "stone_brick_stairs" => Some(Item::StoneBrickStairs), + "mycelium" => Some(Item::Mycelium), + "lily_pad" => Some(Item::LilyPad), + "nether_bricks" => Some(Item::NetherBricks), + "cracked_nether_bricks" => Some(Item::CrackedNetherBricks), + "chiseled_nether_bricks" => Some(Item::ChiseledNetherBricks), + "nether_brick_fence" => Some(Item::NetherBrickFence), + "nether_brick_stairs" => Some(Item::NetherBrickStairs), + "enchanting_table" => Some(Item::EnchantingTable), + "end_portal_frame" => Some(Item::EndPortalFrame), + "end_stone" => Some(Item::EndStone), + "end_stone_bricks" => Some(Item::EndStoneBricks), + "dragon_egg" => Some(Item::DragonEgg), + "redstone_lamp" => Some(Item::RedstoneLamp), + "sandstone_stairs" => Some(Item::SandstoneStairs), + "emerald_ore" => Some(Item::EmeraldOre), + "ender_chest" => Some(Item::EnderChest), + "tripwire_hook" => Some(Item::TripwireHook), + "emerald_block" => Some(Item::EmeraldBlock), + "spruce_stairs" => Some(Item::SpruceStairs), + "birch_stairs" => Some(Item::BirchStairs), + "jungle_stairs" => Some(Item::JungleStairs), + "crimson_stairs" => Some(Item::CrimsonStairs), + "warped_stairs" => Some(Item::WarpedStairs), + "command_block" => Some(Item::CommandBlock), + "beacon" => Some(Item::Beacon), + "cobblestone_wall" => Some(Item::CobblestoneWall), + "mossy_cobblestone_wall" => Some(Item::MossyCobblestoneWall), + "brick_wall" => Some(Item::BrickWall), + "prismarine_wall" => Some(Item::PrismarineWall), + "red_sandstone_wall" => Some(Item::RedSandstoneWall), + "mossy_stone_brick_wall" => Some(Item::MossyStoneBrickWall), + "granite_wall" => Some(Item::GraniteWall), + "stone_brick_wall" => Some(Item::StoneBrickWall), + "nether_brick_wall" => Some(Item::NetherBrickWall), + "andesite_wall" => Some(Item::AndesiteWall), + "red_nether_brick_wall" => Some(Item::RedNetherBrickWall), + "sandstone_wall" => Some(Item::SandstoneWall), + "end_stone_brick_wall" => Some(Item::EndStoneBrickWall), + "diorite_wall" => Some(Item::DioriteWall), + "blackstone_wall" => Some(Item::BlackstoneWall), + "polished_blackstone_wall" => Some(Item::PolishedBlackstoneWall), + "polished_blackstone_brick_wall" => Some(Item::PolishedBlackstoneBrickWall), + "stone_button" => Some(Item::StoneButton), + "oak_button" => Some(Item::OakButton), + "spruce_button" => Some(Item::SpruceButton), + "birch_button" => Some(Item::BirchButton), + "jungle_button" => Some(Item::JungleButton), + "acacia_button" => Some(Item::AcaciaButton), + "dark_oak_button" => Some(Item::DarkOakButton), + "crimson_button" => Some(Item::CrimsonButton), + "warped_button" => Some(Item::WarpedButton), + "polished_blackstone_button" => Some(Item::PolishedBlackstoneButton), + "anvil" => Some(Item::Anvil), + "chipped_anvil" => Some(Item::ChippedAnvil), + "damaged_anvil" => Some(Item::DamagedAnvil), + "trapped_chest" => Some(Item::TrappedChest), + "light_weighted_pressure_plate" => Some(Item::LightWeightedPressurePlate), + "heavy_weighted_pressure_plate" => Some(Item::HeavyWeightedPressurePlate), + "daylight_detector" => Some(Item::DaylightDetector), + "redstone_block" => Some(Item::RedstoneBlock), + "nether_quartz_ore" => Some(Item::NetherQuartzOre), + "hopper" => Some(Item::Hopper), + "chiseled_quartz_block" => Some(Item::ChiseledQuartzBlock), + "quartz_block" => Some(Item::QuartzBlock), + "quartz_bricks" => Some(Item::QuartzBricks), + "quartz_pillar" => Some(Item::QuartzPillar), + "quartz_stairs" => Some(Item::QuartzStairs), + "activator_rail" => Some(Item::ActivatorRail), + "dropper" => Some(Item::Dropper), + "white_terracotta" => Some(Item::WhiteTerracotta), + "orange_terracotta" => Some(Item::OrangeTerracotta), + "magenta_terracotta" => Some(Item::MagentaTerracotta), + "light_blue_terracotta" => Some(Item::LightBlueTerracotta), + "yellow_terracotta" => Some(Item::YellowTerracotta), + "lime_terracotta" => Some(Item::LimeTerracotta), + "pink_terracotta" => Some(Item::PinkTerracotta), + "gray_terracotta" => Some(Item::GrayTerracotta), + "light_gray_terracotta" => Some(Item::LightGrayTerracotta), + "cyan_terracotta" => Some(Item::CyanTerracotta), + "purple_terracotta" => Some(Item::PurpleTerracotta), + "blue_terracotta" => Some(Item::BlueTerracotta), + "brown_terracotta" => Some(Item::BrownTerracotta), + "green_terracotta" => Some(Item::GreenTerracotta), + "red_terracotta" => Some(Item::RedTerracotta), + "black_terracotta" => Some(Item::BlackTerracotta), + "barrier" => Some(Item::Barrier), + "iron_trapdoor" => Some(Item::IronTrapdoor), + "hay_block" => Some(Item::HayBlock), + "white_carpet" => Some(Item::WhiteCarpet), + "orange_carpet" => Some(Item::OrangeCarpet), + "magenta_carpet" => Some(Item::MagentaCarpet), + "light_blue_carpet" => Some(Item::LightBlueCarpet), + "yellow_carpet" => Some(Item::YellowCarpet), + "lime_carpet" => Some(Item::LimeCarpet), + "pink_carpet" => Some(Item::PinkCarpet), + "gray_carpet" => Some(Item::GrayCarpet), + "light_gray_carpet" => Some(Item::LightGrayCarpet), + "cyan_carpet" => Some(Item::CyanCarpet), + "purple_carpet" => Some(Item::PurpleCarpet), + "blue_carpet" => Some(Item::BlueCarpet), + "brown_carpet" => Some(Item::BrownCarpet), + "green_carpet" => Some(Item::GreenCarpet), + "red_carpet" => Some(Item::RedCarpet), + "black_carpet" => Some(Item::BlackCarpet), + "terracotta" => Some(Item::Terracotta), + "coal_block" => Some(Item::CoalBlock), + "packed_ice" => Some(Item::PackedIce), + "acacia_stairs" => Some(Item::AcaciaStairs), + "dark_oak_stairs" => Some(Item::DarkOakStairs), + "slime_block" => Some(Item::SlimeBlock), + "grass_path" => Some(Item::GrassPath), + "sunflower" => Some(Item::Sunflower), + "lilac" => Some(Item::Lilac), + "rose_bush" => Some(Item::RoseBush), + "peony" => Some(Item::Peony), + "tall_grass" => Some(Item::TallGrass), + "large_fern" => Some(Item::LargeFern), + "white_stained_glass" => Some(Item::WhiteStainedGlass), + "orange_stained_glass" => Some(Item::OrangeStainedGlass), + "magenta_stained_glass" => Some(Item::MagentaStainedGlass), + "light_blue_stained_glass" => Some(Item::LightBlueStainedGlass), + "yellow_stained_glass" => Some(Item::YellowStainedGlass), + "lime_stained_glass" => Some(Item::LimeStainedGlass), + "pink_stained_glass" => Some(Item::PinkStainedGlass), + "gray_stained_glass" => Some(Item::GrayStainedGlass), + "light_gray_stained_glass" => Some(Item::LightGrayStainedGlass), + "cyan_stained_glass" => Some(Item::CyanStainedGlass), + "purple_stained_glass" => Some(Item::PurpleStainedGlass), + "blue_stained_glass" => Some(Item::BlueStainedGlass), + "brown_stained_glass" => Some(Item::BrownStainedGlass), + "green_stained_glass" => Some(Item::GreenStainedGlass), + "red_stained_glass" => Some(Item::RedStainedGlass), + "black_stained_glass" => Some(Item::BlackStainedGlass), + "white_stained_glass_pane" => Some(Item::WhiteStainedGlassPane), + "orange_stained_glass_pane" => Some(Item::OrangeStainedGlassPane), + "magenta_stained_glass_pane" => Some(Item::MagentaStainedGlassPane), + "light_blue_stained_glass_pane" => Some(Item::LightBlueStainedGlassPane), + "yellow_stained_glass_pane" => Some(Item::YellowStainedGlassPane), + "lime_stained_glass_pane" => Some(Item::LimeStainedGlassPane), + "pink_stained_glass_pane" => Some(Item::PinkStainedGlassPane), + "gray_stained_glass_pane" => Some(Item::GrayStainedGlassPane), + "light_gray_stained_glass_pane" => Some(Item::LightGrayStainedGlassPane), + "cyan_stained_glass_pane" => Some(Item::CyanStainedGlassPane), + "purple_stained_glass_pane" => Some(Item::PurpleStainedGlassPane), + "blue_stained_glass_pane" => Some(Item::BlueStainedGlassPane), + "brown_stained_glass_pane" => Some(Item::BrownStainedGlassPane), + "green_stained_glass_pane" => Some(Item::GreenStainedGlassPane), + "red_stained_glass_pane" => Some(Item::RedStainedGlassPane), + "black_stained_glass_pane" => Some(Item::BlackStainedGlassPane), + "prismarine" => Some(Item::Prismarine), + "prismarine_bricks" => Some(Item::PrismarineBricks), + "dark_prismarine" => Some(Item::DarkPrismarine), + "prismarine_stairs" => Some(Item::PrismarineStairs), + "prismarine_brick_stairs" => Some(Item::PrismarineBrickStairs), + "dark_prismarine_stairs" => Some(Item::DarkPrismarineStairs), + "sea_lantern" => Some(Item::SeaLantern), + "red_sandstone" => Some(Item::RedSandstone), + "chiseled_red_sandstone" => Some(Item::ChiseledRedSandstone), + "cut_red_sandstone" => Some(Item::CutRedSandstone), + "red_sandstone_stairs" => Some(Item::RedSandstoneStairs), + "repeating_command_block" => Some(Item::RepeatingCommandBlock), + "chain_command_block" => Some(Item::ChainCommandBlock), + "magma_block" => Some(Item::MagmaBlock), + "nether_wart_block" => Some(Item::NetherWartBlock), + "warped_wart_block" => Some(Item::WarpedWartBlock), + "red_nether_bricks" => Some(Item::RedNetherBricks), + "bone_block" => Some(Item::BoneBlock), + "structure_void" => Some(Item::StructureVoid), + "observer" => Some(Item::Observer), + "shulker_box" => Some(Item::ShulkerBox), + "white_shulker_box" => Some(Item::WhiteShulkerBox), + "orange_shulker_box" => Some(Item::OrangeShulkerBox), + "magenta_shulker_box" => Some(Item::MagentaShulkerBox), + "light_blue_shulker_box" => Some(Item::LightBlueShulkerBox), + "yellow_shulker_box" => Some(Item::YellowShulkerBox), + "lime_shulker_box" => Some(Item::LimeShulkerBox), + "pink_shulker_box" => Some(Item::PinkShulkerBox), + "gray_shulker_box" => Some(Item::GrayShulkerBox), + "light_gray_shulker_box" => Some(Item::LightGrayShulkerBox), + "cyan_shulker_box" => Some(Item::CyanShulkerBox), + "purple_shulker_box" => Some(Item::PurpleShulkerBox), + "blue_shulker_box" => Some(Item::BlueShulkerBox), + "brown_shulker_box" => Some(Item::BrownShulkerBox), + "green_shulker_box" => Some(Item::GreenShulkerBox), + "red_shulker_box" => Some(Item::RedShulkerBox), + "black_shulker_box" => Some(Item::BlackShulkerBox), + "white_glazed_terracotta" => Some(Item::WhiteGlazedTerracotta), + "orange_glazed_terracotta" => Some(Item::OrangeGlazedTerracotta), + "magenta_glazed_terracotta" => Some(Item::MagentaGlazedTerracotta), + "light_blue_glazed_terracotta" => Some(Item::LightBlueGlazedTerracotta), + "yellow_glazed_terracotta" => Some(Item::YellowGlazedTerracotta), + "lime_glazed_terracotta" => Some(Item::LimeGlazedTerracotta), + "pink_glazed_terracotta" => Some(Item::PinkGlazedTerracotta), + "gray_glazed_terracotta" => Some(Item::GrayGlazedTerracotta), + "light_gray_glazed_terracotta" => Some(Item::LightGrayGlazedTerracotta), + "cyan_glazed_terracotta" => Some(Item::CyanGlazedTerracotta), + "purple_glazed_terracotta" => Some(Item::PurpleGlazedTerracotta), + "blue_glazed_terracotta" => Some(Item::BlueGlazedTerracotta), + "brown_glazed_terracotta" => Some(Item::BrownGlazedTerracotta), + "green_glazed_terracotta" => Some(Item::GreenGlazedTerracotta), + "red_glazed_terracotta" => Some(Item::RedGlazedTerracotta), + "black_glazed_terracotta" => Some(Item::BlackGlazedTerracotta), + "white_concrete" => Some(Item::WhiteConcrete), + "orange_concrete" => Some(Item::OrangeConcrete), + "magenta_concrete" => Some(Item::MagentaConcrete), + "light_blue_concrete" => Some(Item::LightBlueConcrete), + "yellow_concrete" => Some(Item::YellowConcrete), + "lime_concrete" => Some(Item::LimeConcrete), + "pink_concrete" => Some(Item::PinkConcrete), + "gray_concrete" => Some(Item::GrayConcrete), + "light_gray_concrete" => Some(Item::LightGrayConcrete), + "cyan_concrete" => Some(Item::CyanConcrete), + "purple_concrete" => Some(Item::PurpleConcrete), + "blue_concrete" => Some(Item::BlueConcrete), + "brown_concrete" => Some(Item::BrownConcrete), + "green_concrete" => Some(Item::GreenConcrete), + "red_concrete" => Some(Item::RedConcrete), + "black_concrete" => Some(Item::BlackConcrete), + "white_concrete_powder" => Some(Item::WhiteConcretePowder), + "orange_concrete_powder" => Some(Item::OrangeConcretePowder), + "magenta_concrete_powder" => Some(Item::MagentaConcretePowder), + "light_blue_concrete_powder" => Some(Item::LightBlueConcretePowder), + "yellow_concrete_powder" => Some(Item::YellowConcretePowder), + "lime_concrete_powder" => Some(Item::LimeConcretePowder), + "pink_concrete_powder" => Some(Item::PinkConcretePowder), + "gray_concrete_powder" => Some(Item::GrayConcretePowder), + "light_gray_concrete_powder" => Some(Item::LightGrayConcretePowder), + "cyan_concrete_powder" => Some(Item::CyanConcretePowder), + "purple_concrete_powder" => Some(Item::PurpleConcretePowder), + "blue_concrete_powder" => Some(Item::BlueConcretePowder), + "brown_concrete_powder" => Some(Item::BrownConcretePowder), + "green_concrete_powder" => Some(Item::GreenConcretePowder), + "red_concrete_powder" => Some(Item::RedConcretePowder), + "black_concrete_powder" => Some(Item::BlackConcretePowder), + "turtle_egg" => Some(Item::TurtleEgg), + "dead_tube_coral_block" => Some(Item::DeadTubeCoralBlock), + "dead_brain_coral_block" => Some(Item::DeadBrainCoralBlock), + "dead_bubble_coral_block" => Some(Item::DeadBubbleCoralBlock), + "dead_fire_coral_block" => Some(Item::DeadFireCoralBlock), + "dead_horn_coral_block" => Some(Item::DeadHornCoralBlock), + "tube_coral_block" => Some(Item::TubeCoralBlock), + "brain_coral_block" => Some(Item::BrainCoralBlock), + "bubble_coral_block" => Some(Item::BubbleCoralBlock), + "fire_coral_block" => Some(Item::FireCoralBlock), + "horn_coral_block" => Some(Item::HornCoralBlock), + "tube_coral" => Some(Item::TubeCoral), + "brain_coral" => Some(Item::BrainCoral), + "bubble_coral" => Some(Item::BubbleCoral), + "fire_coral" => Some(Item::FireCoral), + "horn_coral" => Some(Item::HornCoral), + "dead_brain_coral" => Some(Item::DeadBrainCoral), + "dead_bubble_coral" => Some(Item::DeadBubbleCoral), + "dead_fire_coral" => Some(Item::DeadFireCoral), + "dead_horn_coral" => Some(Item::DeadHornCoral), + "dead_tube_coral" => Some(Item::DeadTubeCoral), + "tube_coral_fan" => Some(Item::TubeCoralFan), + "brain_coral_fan" => Some(Item::BrainCoralFan), + "bubble_coral_fan" => Some(Item::BubbleCoralFan), + "fire_coral_fan" => Some(Item::FireCoralFan), + "horn_coral_fan" => Some(Item::HornCoralFan), + "dead_tube_coral_fan" => Some(Item::DeadTubeCoralFan), + "dead_brain_coral_fan" => Some(Item::DeadBrainCoralFan), + "dead_bubble_coral_fan" => Some(Item::DeadBubbleCoralFan), + "dead_fire_coral_fan" => Some(Item::DeadFireCoralFan), + "dead_horn_coral_fan" => Some(Item::DeadHornCoralFan), + "blue_ice" => Some(Item::BlueIce), + "conduit" => Some(Item::Conduit), + "polished_granite_stairs" => Some(Item::PolishedGraniteStairs), + "smooth_red_sandstone_stairs" => Some(Item::SmoothRedSandstoneStairs), + "mossy_stone_brick_stairs" => Some(Item::MossyStoneBrickStairs), + "polished_diorite_stairs" => Some(Item::PolishedDioriteStairs), + "mossy_cobblestone_stairs" => Some(Item::MossyCobblestoneStairs), + "end_stone_brick_stairs" => Some(Item::EndStoneBrickStairs), + "stone_stairs" => Some(Item::StoneStairs), + "smooth_sandstone_stairs" => Some(Item::SmoothSandstoneStairs), + "smooth_quartz_stairs" => Some(Item::SmoothQuartzStairs), + "granite_stairs" => Some(Item::GraniteStairs), + "andesite_stairs" => Some(Item::AndesiteStairs), + "red_nether_brick_stairs" => Some(Item::RedNetherBrickStairs), + "polished_andesite_stairs" => Some(Item::PolishedAndesiteStairs), + "diorite_stairs" => Some(Item::DioriteStairs), + "polished_granite_slab" => Some(Item::PolishedGraniteSlab), + "smooth_red_sandstone_slab" => Some(Item::SmoothRedSandstoneSlab), + "mossy_stone_brick_slab" => Some(Item::MossyStoneBrickSlab), + "polished_diorite_slab" => Some(Item::PolishedDioriteSlab), + "mossy_cobblestone_slab" => Some(Item::MossyCobblestoneSlab), + "end_stone_brick_slab" => Some(Item::EndStoneBrickSlab), + "smooth_sandstone_slab" => Some(Item::SmoothSandstoneSlab), + "smooth_quartz_slab" => Some(Item::SmoothQuartzSlab), + "granite_slab" => Some(Item::GraniteSlab), + "andesite_slab" => Some(Item::AndesiteSlab), + "red_nether_brick_slab" => Some(Item::RedNetherBrickSlab), + "polished_andesite_slab" => Some(Item::PolishedAndesiteSlab), + "diorite_slab" => Some(Item::DioriteSlab), + "scaffolding" => Some(Item::Scaffolding), + "iron_door" => Some(Item::IronDoor), + "oak_door" => Some(Item::OakDoor), + "spruce_door" => Some(Item::SpruceDoor), + "birch_door" => Some(Item::BirchDoor), + "jungle_door" => Some(Item::JungleDoor), + "acacia_door" => Some(Item::AcaciaDoor), + "dark_oak_door" => Some(Item::DarkOakDoor), + "crimson_door" => Some(Item::CrimsonDoor), + "warped_door" => Some(Item::WarpedDoor), + "repeater" => Some(Item::Repeater), + "comparator" => Some(Item::Comparator), + "structure_block" => Some(Item::StructureBlock), + "jigsaw" => Some(Item::Jigsaw), + "turtle_helmet" => Some(Item::TurtleHelmet), + "scute" => Some(Item::Scute), + "flint_and_steel" => Some(Item::FlintAndSteel), + "apple" => Some(Item::Apple), + "bow" => Some(Item::Bow), + "arrow" => Some(Item::Arrow), + "coal" => Some(Item::Coal), + "charcoal" => Some(Item::Charcoal), + "diamond" => Some(Item::Diamond), + "iron_ingot" => Some(Item::IronIngot), + "gold_ingot" => Some(Item::GoldIngot), + "netherite_ingot" => Some(Item::NetheriteIngot), + "netherite_scrap" => Some(Item::NetheriteScrap), + "wooden_sword" => Some(Item::WoodenSword), + "wooden_shovel" => Some(Item::WoodenShovel), + "wooden_pickaxe" => Some(Item::WoodenPickaxe), + "wooden_axe" => Some(Item::WoodenAxe), + "wooden_hoe" => Some(Item::WoodenHoe), + "stone_sword" => Some(Item::StoneSword), + "stone_shovel" => Some(Item::StoneShovel), + "stone_pickaxe" => Some(Item::StonePickaxe), + "stone_axe" => Some(Item::StoneAxe), + "stone_hoe" => Some(Item::StoneHoe), + "golden_sword" => Some(Item::GoldenSword), + "golden_shovel" => Some(Item::GoldenShovel), + "golden_pickaxe" => Some(Item::GoldenPickaxe), + "golden_axe" => Some(Item::GoldenAxe), + "golden_hoe" => Some(Item::GoldenHoe), + "iron_sword" => Some(Item::IronSword), + "iron_shovel" => Some(Item::IronShovel), + "iron_pickaxe" => Some(Item::IronPickaxe), + "iron_axe" => Some(Item::IronAxe), + "iron_hoe" => Some(Item::IronHoe), + "diamond_sword" => Some(Item::DiamondSword), + "diamond_shovel" => Some(Item::DiamondShovel), + "diamond_pickaxe" => Some(Item::DiamondPickaxe), + "diamond_axe" => Some(Item::DiamondAxe), + "diamond_hoe" => Some(Item::DiamondHoe), + "netherite_sword" => Some(Item::NetheriteSword), + "netherite_shovel" => Some(Item::NetheriteShovel), + "netherite_pickaxe" => Some(Item::NetheritePickaxe), + "netherite_axe" => Some(Item::NetheriteAxe), + "netherite_hoe" => Some(Item::NetheriteHoe), + "stick" => Some(Item::Stick), + "bowl" => Some(Item::Bowl), + "mushroom_stew" => Some(Item::MushroomStew), + "string" => Some(Item::String), + "feather" => Some(Item::Feather), + "gunpowder" => Some(Item::Gunpowder), + "wheat_seeds" => Some(Item::WheatSeeds), + "wheat" => Some(Item::Wheat), + "bread" => Some(Item::Bread), + "leather_helmet" => Some(Item::LeatherHelmet), + "leather_chestplate" => Some(Item::LeatherChestplate), + "leather_leggings" => Some(Item::LeatherLeggings), + "leather_boots" => Some(Item::LeatherBoots), + "chainmail_helmet" => Some(Item::ChainmailHelmet), + "chainmail_chestplate" => Some(Item::ChainmailChestplate), + "chainmail_leggings" => Some(Item::ChainmailLeggings), + "chainmail_boots" => Some(Item::ChainmailBoots), + "iron_helmet" => Some(Item::IronHelmet), + "iron_chestplate" => Some(Item::IronChestplate), + "iron_leggings" => Some(Item::IronLeggings), + "iron_boots" => Some(Item::IronBoots), + "diamond_helmet" => Some(Item::DiamondHelmet), + "diamond_chestplate" => Some(Item::DiamondChestplate), + "diamond_leggings" => Some(Item::DiamondLeggings), + "diamond_boots" => Some(Item::DiamondBoots), + "golden_helmet" => Some(Item::GoldenHelmet), + "golden_chestplate" => Some(Item::GoldenChestplate), + "golden_leggings" => Some(Item::GoldenLeggings), + "golden_boots" => Some(Item::GoldenBoots), + "netherite_helmet" => Some(Item::NetheriteHelmet), + "netherite_chestplate" => Some(Item::NetheriteChestplate), + "netherite_leggings" => Some(Item::NetheriteLeggings), + "netherite_boots" => Some(Item::NetheriteBoots), + "flint" => Some(Item::Flint), + "porkchop" => Some(Item::Porkchop), + "cooked_porkchop" => Some(Item::CookedPorkchop), + "painting" => Some(Item::Painting), + "golden_apple" => Some(Item::GoldenApple), + "enchanted_golden_apple" => Some(Item::EnchantedGoldenApple), + "oak_sign" => Some(Item::OakSign), + "spruce_sign" => Some(Item::SpruceSign), + "birch_sign" => Some(Item::BirchSign), + "jungle_sign" => Some(Item::JungleSign), + "acacia_sign" => Some(Item::AcaciaSign), + "dark_oak_sign" => Some(Item::DarkOakSign), + "crimson_sign" => Some(Item::CrimsonSign), + "warped_sign" => Some(Item::WarpedSign), + "bucket" => Some(Item::Bucket), + "water_bucket" => Some(Item::WaterBucket), + "lava_bucket" => Some(Item::LavaBucket), + "minecart" => Some(Item::Minecart), + "saddle" => Some(Item::Saddle), + "redstone" => Some(Item::Redstone), + "snowball" => Some(Item::Snowball), + "oak_boat" => Some(Item::OakBoat), + "leather" => Some(Item::Leather), + "milk_bucket" => Some(Item::MilkBucket), + "pufferfish_bucket" => Some(Item::PufferfishBucket), + "salmon_bucket" => Some(Item::SalmonBucket), + "cod_bucket" => Some(Item::CodBucket), + "tropical_fish_bucket" => Some(Item::TropicalFishBucket), + "brick" => Some(Item::Brick), + "clay_ball" => Some(Item::ClayBall), + "dried_kelp_block" => Some(Item::DriedKelpBlock), + "paper" => Some(Item::Paper), + "book" => Some(Item::Book), + "slime_ball" => Some(Item::SlimeBall), + "chest_minecart" => Some(Item::ChestMinecart), + "furnace_minecart" => Some(Item::FurnaceMinecart), + "egg" => Some(Item::Egg), + "compass" => Some(Item::Compass), + "fishing_rod" => Some(Item::FishingRod), + "clock" => Some(Item::Clock), + "glowstone_dust" => Some(Item::GlowstoneDust), + "cod" => Some(Item::Cod), + "salmon" => Some(Item::Salmon), + "tropical_fish" => Some(Item::TropicalFish), + "pufferfish" => Some(Item::Pufferfish), + "cooked_cod" => Some(Item::CookedCod), + "cooked_salmon" => Some(Item::CookedSalmon), + "ink_sac" => Some(Item::InkSac), + "cocoa_beans" => Some(Item::CocoaBeans), + "lapis_lazuli" => Some(Item::LapisLazuli), + "white_dye" => Some(Item::WhiteDye), + "orange_dye" => Some(Item::OrangeDye), + "magenta_dye" => Some(Item::MagentaDye), + "light_blue_dye" => Some(Item::LightBlueDye), + "yellow_dye" => Some(Item::YellowDye), + "lime_dye" => Some(Item::LimeDye), + "pink_dye" => Some(Item::PinkDye), + "gray_dye" => Some(Item::GrayDye), + "light_gray_dye" => Some(Item::LightGrayDye), + "cyan_dye" => Some(Item::CyanDye), + "purple_dye" => Some(Item::PurpleDye), + "blue_dye" => Some(Item::BlueDye), + "brown_dye" => Some(Item::BrownDye), + "green_dye" => Some(Item::GreenDye), + "red_dye" => Some(Item::RedDye), + "black_dye" => Some(Item::BlackDye), + "bone_meal" => Some(Item::BoneMeal), + "bone" => Some(Item::Bone), + "sugar" => Some(Item::Sugar), + "cake" => Some(Item::Cake), + "white_bed" => Some(Item::WhiteBed), + "orange_bed" => Some(Item::OrangeBed), + "magenta_bed" => Some(Item::MagentaBed), + "light_blue_bed" => Some(Item::LightBlueBed), + "yellow_bed" => Some(Item::YellowBed), + "lime_bed" => Some(Item::LimeBed), + "pink_bed" => Some(Item::PinkBed), + "gray_bed" => Some(Item::GrayBed), + "light_gray_bed" => Some(Item::LightGrayBed), + "cyan_bed" => Some(Item::CyanBed), + "purple_bed" => Some(Item::PurpleBed), + "blue_bed" => Some(Item::BlueBed), + "brown_bed" => Some(Item::BrownBed), + "green_bed" => Some(Item::GreenBed), + "red_bed" => Some(Item::RedBed), + "black_bed" => Some(Item::BlackBed), + "cookie" => Some(Item::Cookie), + "filled_map" => Some(Item::FilledMap), + "shears" => Some(Item::Shears), + "melon_slice" => Some(Item::MelonSlice), + "dried_kelp" => Some(Item::DriedKelp), + "pumpkin_seeds" => Some(Item::PumpkinSeeds), + "melon_seeds" => Some(Item::MelonSeeds), + "beef" => Some(Item::Beef), + "cooked_beef" => Some(Item::CookedBeef), + "chicken" => Some(Item::Chicken), + "cooked_chicken" => Some(Item::CookedChicken), + "rotten_flesh" => Some(Item::RottenFlesh), + "ender_pearl" => Some(Item::EnderPearl), + "blaze_rod" => Some(Item::BlazeRod), + "ghast_tear" => Some(Item::GhastTear), + "gold_nugget" => Some(Item::GoldNugget), + "nether_wart" => Some(Item::NetherWart), + "potion" => Some(Item::Potion), + "glass_bottle" => Some(Item::GlassBottle), + "spider_eye" => Some(Item::SpiderEye), + "fermented_spider_eye" => Some(Item::FermentedSpiderEye), + "blaze_powder" => Some(Item::BlazePowder), + "magma_cream" => Some(Item::MagmaCream), + "brewing_stand" => Some(Item::BrewingStand), + "cauldron" => Some(Item::Cauldron), + "ender_eye" => Some(Item::EnderEye), + "glistering_melon_slice" => Some(Item::GlisteringMelonSlice), + "bat_spawn_egg" => Some(Item::BatSpawnEgg), + "bee_spawn_egg" => Some(Item::BeeSpawnEgg), + "blaze_spawn_egg" => Some(Item::BlazeSpawnEgg), + "cat_spawn_egg" => Some(Item::CatSpawnEgg), + "cave_spider_spawn_egg" => Some(Item::CaveSpiderSpawnEgg), + "chicken_spawn_egg" => Some(Item::ChickenSpawnEgg), + "cod_spawn_egg" => Some(Item::CodSpawnEgg), + "cow_spawn_egg" => Some(Item::CowSpawnEgg), + "creeper_spawn_egg" => Some(Item::CreeperSpawnEgg), + "dolphin_spawn_egg" => Some(Item::DolphinSpawnEgg), + "donkey_spawn_egg" => Some(Item::DonkeySpawnEgg), + "drowned_spawn_egg" => Some(Item::DrownedSpawnEgg), + "elder_guardian_spawn_egg" => Some(Item::ElderGuardianSpawnEgg), + "enderman_spawn_egg" => Some(Item::EndermanSpawnEgg), + "endermite_spawn_egg" => Some(Item::EndermiteSpawnEgg), + "evoker_spawn_egg" => Some(Item::EvokerSpawnEgg), + "fox_spawn_egg" => Some(Item::FoxSpawnEgg), + "ghast_spawn_egg" => Some(Item::GhastSpawnEgg), + "guardian_spawn_egg" => Some(Item::GuardianSpawnEgg), + "hoglin_spawn_egg" => Some(Item::HoglinSpawnEgg), + "horse_spawn_egg" => Some(Item::HorseSpawnEgg), + "husk_spawn_egg" => Some(Item::HuskSpawnEgg), + "llama_spawn_egg" => Some(Item::LlamaSpawnEgg), + "magma_cube_spawn_egg" => Some(Item::MagmaCubeSpawnEgg), + "mooshroom_spawn_egg" => Some(Item::MooshroomSpawnEgg), + "mule_spawn_egg" => Some(Item::MuleSpawnEgg), + "ocelot_spawn_egg" => Some(Item::OcelotSpawnEgg), + "panda_spawn_egg" => Some(Item::PandaSpawnEgg), + "parrot_spawn_egg" => Some(Item::ParrotSpawnEgg), + "phantom_spawn_egg" => Some(Item::PhantomSpawnEgg), + "pig_spawn_egg" => Some(Item::PigSpawnEgg), + "piglin_spawn_egg" => Some(Item::PiglinSpawnEgg), + "piglin_brute_spawn_egg" => Some(Item::PiglinBruteSpawnEgg), + "pillager_spawn_egg" => Some(Item::PillagerSpawnEgg), + "polar_bear_spawn_egg" => Some(Item::PolarBearSpawnEgg), + "pufferfish_spawn_egg" => Some(Item::PufferfishSpawnEgg), + "rabbit_spawn_egg" => Some(Item::RabbitSpawnEgg), + "ravager_spawn_egg" => Some(Item::RavagerSpawnEgg), + "salmon_spawn_egg" => Some(Item::SalmonSpawnEgg), + "sheep_spawn_egg" => Some(Item::SheepSpawnEgg), + "shulker_spawn_egg" => Some(Item::ShulkerSpawnEgg), + "silverfish_spawn_egg" => Some(Item::SilverfishSpawnEgg), + "skeleton_spawn_egg" => Some(Item::SkeletonSpawnEgg), + "skeleton_horse_spawn_egg" => Some(Item::SkeletonHorseSpawnEgg), + "slime_spawn_egg" => Some(Item::SlimeSpawnEgg), + "spider_spawn_egg" => Some(Item::SpiderSpawnEgg), + "squid_spawn_egg" => Some(Item::SquidSpawnEgg), + "stray_spawn_egg" => Some(Item::StraySpawnEgg), + "strider_spawn_egg" => Some(Item::StriderSpawnEgg), + "trader_llama_spawn_egg" => Some(Item::TraderLlamaSpawnEgg), + "tropical_fish_spawn_egg" => Some(Item::TropicalFishSpawnEgg), + "turtle_spawn_egg" => Some(Item::TurtleSpawnEgg), + "vex_spawn_egg" => Some(Item::VexSpawnEgg), + "villager_spawn_egg" => Some(Item::VillagerSpawnEgg), + "vindicator_spawn_egg" => Some(Item::VindicatorSpawnEgg), + "wandering_trader_spawn_egg" => Some(Item::WanderingTraderSpawnEgg), + "witch_spawn_egg" => Some(Item::WitchSpawnEgg), + "wither_skeleton_spawn_egg" => Some(Item::WitherSkeletonSpawnEgg), + "wolf_spawn_egg" => Some(Item::WolfSpawnEgg), + "zoglin_spawn_egg" => Some(Item::ZoglinSpawnEgg), + "zombie_spawn_egg" => Some(Item::ZombieSpawnEgg), + "zombie_horse_spawn_egg" => Some(Item::ZombieHorseSpawnEgg), + "zombie_villager_spawn_egg" => Some(Item::ZombieVillagerSpawnEgg), + "zombified_piglin_spawn_egg" => Some(Item::ZombifiedPiglinSpawnEgg), + "experience_bottle" => Some(Item::ExperienceBottle), + "fire_charge" => Some(Item::FireCharge), + "writable_book" => Some(Item::WritableBook), + "written_book" => Some(Item::WrittenBook), + "emerald" => Some(Item::Emerald), + "item_frame" => Some(Item::ItemFrame), + "flower_pot" => Some(Item::FlowerPot), + "carrot" => Some(Item::Carrot), + "potato" => Some(Item::Potato), + "baked_potato" => Some(Item::BakedPotato), + "poisonous_potato" => Some(Item::PoisonousPotato), + "map" => Some(Item::Map), + "golden_carrot" => Some(Item::GoldenCarrot), + "skeleton_skull" => Some(Item::SkeletonSkull), + "wither_skeleton_skull" => Some(Item::WitherSkeletonSkull), + "player_head" => Some(Item::PlayerHead), + "zombie_head" => Some(Item::ZombieHead), + "creeper_head" => Some(Item::CreeperHead), + "dragon_head" => Some(Item::DragonHead), + "carrot_on_a_stick" => Some(Item::CarrotOnAStick), + "warped_fungus_on_a_stick" => Some(Item::WarpedFungusOnAStick), + "nether_star" => Some(Item::NetherStar), + "pumpkin_pie" => Some(Item::PumpkinPie), + "firework_rocket" => Some(Item::FireworkRocket), + "firework_star" => Some(Item::FireworkStar), + "enchanted_book" => Some(Item::EnchantedBook), + "nether_brick" => Some(Item::NetherBrick), + "quartz" => Some(Item::Quartz), + "tnt_minecart" => Some(Item::TntMinecart), + "hopper_minecart" => Some(Item::HopperMinecart), + "prismarine_shard" => Some(Item::PrismarineShard), + "prismarine_crystals" => Some(Item::PrismarineCrystals), + "rabbit" => Some(Item::Rabbit), + "cooked_rabbit" => Some(Item::CookedRabbit), + "rabbit_stew" => Some(Item::RabbitStew), + "rabbit_foot" => Some(Item::RabbitFoot), + "rabbit_hide" => Some(Item::RabbitHide), + "armor_stand" => Some(Item::ArmorStand), + "iron_horse_armor" => Some(Item::IronHorseArmor), + "golden_horse_armor" => Some(Item::GoldenHorseArmor), + "diamond_horse_armor" => Some(Item::DiamondHorseArmor), + "leather_horse_armor" => Some(Item::LeatherHorseArmor), + "lead" => Some(Item::Lead), + "name_tag" => Some(Item::NameTag), + "command_block_minecart" => Some(Item::CommandBlockMinecart), + "mutton" => Some(Item::Mutton), + "cooked_mutton" => Some(Item::CookedMutton), + "white_banner" => Some(Item::WhiteBanner), + "orange_banner" => Some(Item::OrangeBanner), + "magenta_banner" => Some(Item::MagentaBanner), + "light_blue_banner" => Some(Item::LightBlueBanner), + "yellow_banner" => Some(Item::YellowBanner), + "lime_banner" => Some(Item::LimeBanner), + "pink_banner" => Some(Item::PinkBanner), + "gray_banner" => Some(Item::GrayBanner), + "light_gray_banner" => Some(Item::LightGrayBanner), + "cyan_banner" => Some(Item::CyanBanner), + "purple_banner" => Some(Item::PurpleBanner), + "blue_banner" => Some(Item::BlueBanner), + "brown_banner" => Some(Item::BrownBanner), + "green_banner" => Some(Item::GreenBanner), + "red_banner" => Some(Item::RedBanner), + "black_banner" => Some(Item::BlackBanner), + "end_crystal" => Some(Item::EndCrystal), + "chorus_fruit" => Some(Item::ChorusFruit), + "popped_chorus_fruit" => Some(Item::PoppedChorusFruit), + "beetroot" => Some(Item::Beetroot), + "beetroot_seeds" => Some(Item::BeetrootSeeds), + "beetroot_soup" => Some(Item::BeetrootSoup), + "dragon_breath" => Some(Item::DragonBreath), + "splash_potion" => Some(Item::SplashPotion), + "spectral_arrow" => Some(Item::SpectralArrow), + "tipped_arrow" => Some(Item::TippedArrow), + "lingering_potion" => Some(Item::LingeringPotion), + "shield" => Some(Item::Shield), + "elytra" => Some(Item::Elytra), + "spruce_boat" => Some(Item::SpruceBoat), + "birch_boat" => Some(Item::BirchBoat), + "jungle_boat" => Some(Item::JungleBoat), + "acacia_boat" => Some(Item::AcaciaBoat), + "dark_oak_boat" => Some(Item::DarkOakBoat), + "totem_of_undying" => Some(Item::TotemOfUndying), + "shulker_shell" => Some(Item::ShulkerShell), + "iron_nugget" => Some(Item::IronNugget), + "knowledge_book" => Some(Item::KnowledgeBook), + "debug_stick" => Some(Item::DebugStick), + "music_disc_13" => Some(Item::MusicDisc13), + "music_disc_cat" => Some(Item::MusicDiscCat), + "music_disc_blocks" => Some(Item::MusicDiscBlocks), + "music_disc_chirp" => Some(Item::MusicDiscChirp), + "music_disc_far" => Some(Item::MusicDiscFar), + "music_disc_mall" => Some(Item::MusicDiscMall), + "music_disc_mellohi" => Some(Item::MusicDiscMellohi), + "music_disc_stal" => Some(Item::MusicDiscStal), + "music_disc_strad" => Some(Item::MusicDiscStrad), + "music_disc_ward" => Some(Item::MusicDiscWard), + "music_disc_11" => Some(Item::MusicDisc11), + "music_disc_wait" => Some(Item::MusicDiscWait), + "music_disc_pigstep" => Some(Item::MusicDiscPigstep), + "trident" => Some(Item::Trident), + "phantom_membrane" => Some(Item::PhantomMembrane), + "nautilus_shell" => Some(Item::NautilusShell), + "heart_of_the_sea" => Some(Item::HeartOfTheSea), + "crossbow" => Some(Item::Crossbow), + "suspicious_stew" => Some(Item::SuspiciousStew), + "loom" => Some(Item::Loom), + "flower_banner_pattern" => Some(Item::FlowerBannerPattern), + "creeper_banner_pattern" => Some(Item::CreeperBannerPattern), + "skull_banner_pattern" => Some(Item::SkullBannerPattern), + "mojang_banner_pattern" => Some(Item::MojangBannerPattern), + "globe_banner_pattern" => Some(Item::GlobeBannerPattern), + "piglin_banner_pattern" => Some(Item::PiglinBannerPattern), + "composter" => Some(Item::Composter), + "barrel" => Some(Item::Barrel), + "smoker" => Some(Item::Smoker), + "blast_furnace" => Some(Item::BlastFurnace), + "cartography_table" => Some(Item::CartographyTable), + "fletching_table" => Some(Item::FletchingTable), + "grindstone" => Some(Item::Grindstone), + "lectern" => Some(Item::Lectern), + "smithing_table" => Some(Item::SmithingTable), + "stonecutter" => Some(Item::Stonecutter), + "bell" => Some(Item::Bell), + "lantern" => Some(Item::Lantern), + "soul_lantern" => Some(Item::SoulLantern), + "sweet_berries" => Some(Item::SweetBerries), + "campfire" => Some(Item::Campfire), + "soul_campfire" => Some(Item::SoulCampfire), + "shroomlight" => Some(Item::Shroomlight), + "honeycomb" => Some(Item::Honeycomb), + "bee_nest" => Some(Item::BeeNest), + "beehive" => Some(Item::Beehive), + "honey_bottle" => Some(Item::HoneyBottle), + "honey_block" => Some(Item::HoneyBlock), + "honeycomb_block" => Some(Item::HoneycombBlock), + "lodestone" => Some(Item::Lodestone), + "netherite_block" => Some(Item::NetheriteBlock), + "ancient_debris" => Some(Item::AncientDebris), + "target" => Some(Item::Target), + "crying_obsidian" => Some(Item::CryingObsidian), + "blackstone" => Some(Item::Blackstone), + "blackstone_slab" => Some(Item::BlackstoneSlab), + "blackstone_stairs" => Some(Item::BlackstoneStairs), + "gilded_blackstone" => Some(Item::GildedBlackstone), + "polished_blackstone" => Some(Item::PolishedBlackstone), + "polished_blackstone_slab" => Some(Item::PolishedBlackstoneSlab), + "polished_blackstone_stairs" => Some(Item::PolishedBlackstoneStairs), + "chiseled_polished_blackstone" => Some(Item::ChiseledPolishedBlackstone), + "polished_blackstone_bricks" => Some(Item::PolishedBlackstoneBricks), + "polished_blackstone_brick_slab" => Some(Item::PolishedBlackstoneBrickSlab), + "polished_blackstone_brick_stairs" => Some(Item::PolishedBlackstoneBrickStairs), + "cracked_polished_blackstone_bricks" => Some(Item::CrackedPolishedBlackstoneBricks), + "respawn_anchor" => Some(Item::RespawnAnchor), + _ => None, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Item { + /// Returns the `display_name` property of this `Item`. + pub fn display_name(&self) -> &'static str { + match self { + Item::Air => "Air", + Item::Stone => "Stone", + Item::Granite => "Granite", + Item::PolishedGranite => "Polished Granite", + Item::Diorite => "Diorite", + Item::PolishedDiorite => "Polished Diorite", + Item::Andesite => "Andesite", + Item::PolishedAndesite => "Polished Andesite", + Item::GrassBlock => "Grass Block", + Item::Dirt => "Dirt", + Item::CoarseDirt => "Coarse Dirt", + Item::Podzol => "Podzol", + Item::CrimsonNylium => "Crimson Nylium", + Item::WarpedNylium => "Warped Nylium", + Item::Cobblestone => "Cobblestone", + Item::OakPlanks => "Oak Planks", + Item::SprucePlanks => "Spruce Planks", + Item::BirchPlanks => "Birch Planks", + Item::JunglePlanks => "Jungle Planks", + Item::AcaciaPlanks => "Acacia Planks", + Item::DarkOakPlanks => "Dark Oak Planks", + Item::CrimsonPlanks => "Crimson Planks", + Item::WarpedPlanks => "Warped Planks", + Item::OakSapling => "Oak Sapling", + Item::SpruceSapling => "Spruce Sapling", + Item::BirchSapling => "Birch Sapling", + Item::JungleSapling => "Jungle Sapling", + Item::AcaciaSapling => "Acacia Sapling", + Item::DarkOakSapling => "Dark Oak Sapling", + Item::Bedrock => "Bedrock", + Item::Sand => "Sand", + Item::RedSand => "Red Sand", + Item::Gravel => "Gravel", + Item::GoldOre => "Gold Ore", + Item::IronOre => "Iron Ore", + Item::CoalOre => "Coal Ore", + Item::NetherGoldOre => "Nether Gold Ore", + Item::OakLog => "Oak Log", + Item::SpruceLog => "Spruce Log", + Item::BirchLog => "Birch Log", + Item::JungleLog => "Jungle Log", + Item::AcaciaLog => "Acacia Log", + Item::DarkOakLog => "Dark Oak Log", + Item::CrimsonStem => "Crimson Stem", + Item::WarpedStem => "Warped Stem", + Item::StrippedOakLog => "Stripped Oak Log", + Item::StrippedSpruceLog => "Stripped Spruce Log", + Item::StrippedBirchLog => "Stripped Birch Log", + Item::StrippedJungleLog => "Stripped Jungle Log", + Item::StrippedAcaciaLog => "Stripped Acacia Log", + Item::StrippedDarkOakLog => "Stripped Dark Oak Log", + Item::StrippedCrimsonStem => "Stripped Crimson Stem", + Item::StrippedWarpedStem => "Stripped Warped Stem", + Item::StrippedOakWood => "Stripped Oak Wood", + Item::StrippedSpruceWood => "Stripped Spruce Wood", + Item::StrippedBirchWood => "Stripped Birch Wood", + Item::StrippedJungleWood => "Stripped Jungle Wood", + Item::StrippedAcaciaWood => "Stripped Acacia Wood", + Item::StrippedDarkOakWood => "Stripped Dark Oak Wood", + Item::StrippedCrimsonHyphae => "Stripped Crimson Hyphae", + Item::StrippedWarpedHyphae => "Stripped Warped Hyphae", + Item::OakWood => "Oak Wood", + Item::SpruceWood => "Spruce Wood", + Item::BirchWood => "Birch Wood", + Item::JungleWood => "Jungle Wood", + Item::AcaciaWood => "Acacia Wood", + Item::DarkOakWood => "Dark Oak Wood", + Item::CrimsonHyphae => "Crimson Hyphae", + Item::WarpedHyphae => "Warped Hyphae", + Item::OakLeaves => "Oak Leaves", + Item::SpruceLeaves => "Spruce Leaves", + Item::BirchLeaves => "Birch Leaves", + Item::JungleLeaves => "Jungle Leaves", + Item::AcaciaLeaves => "Acacia Leaves", + Item::DarkOakLeaves => "Dark Oak Leaves", + Item::Sponge => "Sponge", + Item::WetSponge => "Wet Sponge", + Item::Glass => "Glass", + Item::LapisOre => "Lapis Lazuli Ore", + Item::LapisBlock => "Lapis Lazuli Block", + Item::Dispenser => "Dispenser", + Item::Sandstone => "Sandstone", + Item::ChiseledSandstone => "Chiseled Sandstone", + Item::CutSandstone => "Cut Sandstone", + Item::NoteBlock => "Note Block", + Item::PoweredRail => "Powered Rail", + Item::DetectorRail => "Detector Rail", + Item::StickyPiston => "Sticky Piston", + Item::Cobweb => "Cobweb", + Item::Grass => "Grass", + Item::Fern => "Fern", + Item::DeadBush => "Dead Bush", + Item::Seagrass => "Seagrass", + Item::SeaPickle => "Sea Pickle", + Item::Piston => "Piston", + Item::WhiteWool => "White Wool", + Item::OrangeWool => "Orange Wool", + Item::MagentaWool => "Magenta Wool", + Item::LightBlueWool => "Light Blue Wool", + Item::YellowWool => "Yellow Wool", + Item::LimeWool => "Lime Wool", + Item::PinkWool => "Pink Wool", + Item::GrayWool => "Gray Wool", + Item::LightGrayWool => "Light Gray Wool", + Item::CyanWool => "Cyan Wool", + Item::PurpleWool => "Purple Wool", + Item::BlueWool => "Blue Wool", + Item::BrownWool => "Brown Wool", + Item::GreenWool => "Green Wool", + Item::RedWool => "Red Wool", + Item::BlackWool => "Black Wool", + Item::Dandelion => "Dandelion", + Item::Poppy => "Poppy", + Item::BlueOrchid => "Blue Orchid", + Item::Allium => "Allium", + Item::AzureBluet => "Azure Bluet", + Item::RedTulip => "Red Tulip", + Item::OrangeTulip => "Orange Tulip", + Item::WhiteTulip => "White Tulip", + Item::PinkTulip => "Pink Tulip", + Item::OxeyeDaisy => "Oxeye Daisy", + Item::Cornflower => "Cornflower", + Item::LilyOfTheValley => "Lily of the Valley", + Item::WitherRose => "Wither Rose", + Item::BrownMushroom => "Brown Mushroom", + Item::RedMushroom => "Red Mushroom", + Item::CrimsonFungus => "Crimson Fungus", + Item::WarpedFungus => "Warped Fungus", + Item::CrimsonRoots => "Crimson Roots", + Item::WarpedRoots => "Warped Roots", + Item::NetherSprouts => "Nether Sprouts", + Item::WeepingVines => "Weeping Vines", + Item::TwistingVines => "Twisting Vines", + Item::SugarCane => "Sugar Cane", + Item::Kelp => "Kelp", + Item::Bamboo => "Bamboo", + Item::GoldBlock => "Block of Gold", + Item::IronBlock => "Block of Iron", + Item::OakSlab => "Oak Slab", + Item::SpruceSlab => "Spruce Slab", + Item::BirchSlab => "Birch Slab", + Item::JungleSlab => "Jungle Slab", + Item::AcaciaSlab => "Acacia Slab", + Item::DarkOakSlab => "Dark Oak Slab", + Item::CrimsonSlab => "Crimson Slab", + Item::WarpedSlab => "Warped Slab", + Item::StoneSlab => "Stone Slab", + Item::SmoothStoneSlab => "Smooth Stone Slab", + Item::SandstoneSlab => "Sandstone Slab", + Item::CutSandstoneSlab => "Cut Sandstone Slab", + Item::PetrifiedOakSlab => "Petrified Oak Slab", + Item::CobblestoneSlab => "Cobblestone Slab", + Item::BrickSlab => "Brick Slab", + Item::StoneBrickSlab => "Stone Brick Slab", + Item::NetherBrickSlab => "Nether Brick Slab", + Item::QuartzSlab => "Quartz Slab", + Item::RedSandstoneSlab => "Red Sandstone Slab", + Item::CutRedSandstoneSlab => "Cut Red Sandstone Slab", + Item::PurpurSlab => "Purpur Slab", + Item::PrismarineSlab => "Prismarine Slab", + Item::PrismarineBrickSlab => "Prismarine Brick Slab", + Item::DarkPrismarineSlab => "Dark Prismarine Slab", + Item::SmoothQuartz => "Smooth Quartz Block", + Item::SmoothRedSandstone => "Smooth Red Sandstone", + Item::SmoothSandstone => "Smooth Sandstone", + Item::SmoothStone => "Smooth Stone", + Item::Bricks => "Bricks", + Item::Tnt => "TNT", + Item::Bookshelf => "Bookshelf", + Item::MossyCobblestone => "Mossy Cobblestone", + Item::Obsidian => "Obsidian", + Item::Torch => "Torch", + Item::EndRod => "End Rod", + Item::ChorusPlant => "Chorus Plant", + Item::ChorusFlower => "Chorus Flower", + Item::PurpurBlock => "Purpur Block", + Item::PurpurPillar => "Purpur Pillar", + Item::PurpurStairs => "Purpur Stairs", + Item::Spawner => "Spawner", + Item::OakStairs => "Oak Stairs", + Item::Chest => "Chest", + Item::DiamondOre => "Diamond Ore", + Item::DiamondBlock => "Block of Diamond", + Item::CraftingTable => "Crafting Table", + Item::Farmland => "Farmland", + Item::Furnace => "Furnace", + Item::Ladder => "Ladder", + Item::Rail => "Rail", + Item::CobblestoneStairs => "Cobblestone Stairs", + Item::Lever => "Lever", + Item::StonePressurePlate => "Stone Pressure Plate", + Item::OakPressurePlate => "Oak Pressure Plate", + Item::SprucePressurePlate => "Spruce Pressure Plate", + Item::BirchPressurePlate => "Birch Pressure Plate", + Item::JunglePressurePlate => "Jungle Pressure Plate", + Item::AcaciaPressurePlate => "Acacia Pressure Plate", + Item::DarkOakPressurePlate => "Dark Oak Pressure Plate", + Item::CrimsonPressurePlate => "Crimson Pressure Plate", + Item::WarpedPressurePlate => "Warped Pressure Plate", + Item::PolishedBlackstonePressurePlate => "Polished Blackstone Pressure Plate", + Item::RedstoneOre => "Redstone Ore", + Item::RedstoneTorch => "Redstone Torch", + Item::Snow => "Snow", + Item::Ice => "Ice", + Item::SnowBlock => "Snow Block", + Item::Cactus => "Cactus", + Item::Clay => "Clay", + Item::Jukebox => "Jukebox", + Item::OakFence => "Oak Fence", + Item::SpruceFence => "Spruce Fence", + Item::BirchFence => "Birch Fence", + Item::JungleFence => "Jungle Fence", + Item::AcaciaFence => "Acacia Fence", + Item::DarkOakFence => "Dark Oak Fence", + Item::CrimsonFence => "Crimson Fence", + Item::WarpedFence => "Warped Fence", + Item::Pumpkin => "Pumpkin", + Item::CarvedPumpkin => "Carved Pumpkin", + Item::Netherrack => "Netherrack", + Item::SoulSand => "Soul Sand", + Item::SoulSoil => "Soul Soil", + Item::Basalt => "Basalt", + Item::PolishedBasalt => "Polished Basalt", + Item::SoulTorch => "Soul Torch", + Item::Glowstone => "Glowstone", + Item::JackOLantern => "Jack o'Lantern", + Item::OakTrapdoor => "Oak Trapdoor", + Item::SpruceTrapdoor => "Spruce Trapdoor", + Item::BirchTrapdoor => "Birch Trapdoor", + Item::JungleTrapdoor => "Jungle Trapdoor", + Item::AcaciaTrapdoor => "Acacia Trapdoor", + Item::DarkOakTrapdoor => "Dark Oak Trapdoor", + Item::CrimsonTrapdoor => "Crimson Trapdoor", + Item::WarpedTrapdoor => "Warped Trapdoor", + Item::InfestedStone => "Infested Stone", + Item::InfestedCobblestone => "Infested Cobblestone", + Item::InfestedStoneBricks => "Infested Stone Bricks", + Item::InfestedMossyStoneBricks => "Infested Mossy Stone Bricks", + Item::InfestedCrackedStoneBricks => "Infested Cracked Stone Bricks", + Item::InfestedChiseledStoneBricks => "Infested Chiseled Stone Bricks", + Item::StoneBricks => "Stone Bricks", + Item::MossyStoneBricks => "Mossy Stone Bricks", + Item::CrackedStoneBricks => "Cracked Stone Bricks", + Item::ChiseledStoneBricks => "Chiseled Stone Bricks", + Item::BrownMushroomBlock => "Brown Mushroom Block", + Item::RedMushroomBlock => "Red Mushroom Block", + Item::MushroomStem => "Mushroom Stem", + Item::IronBars => "Iron Bars", + Item::Chain => "Chain", + Item::GlassPane => "Glass Pane", + Item::Melon => "Melon", + Item::Vine => "Vines", + Item::OakFenceGate => "Oak Fence Gate", + Item::SpruceFenceGate => "Spruce Fence Gate", + Item::BirchFenceGate => "Birch Fence Gate", + Item::JungleFenceGate => "Jungle Fence Gate", + Item::AcaciaFenceGate => "Acacia Fence Gate", + Item::DarkOakFenceGate => "Dark Oak Fence Gate", + Item::CrimsonFenceGate => "Crimson Fence Gate", + Item::WarpedFenceGate => "Warped Fence Gate", + Item::BrickStairs => "Brick Stairs", + Item::StoneBrickStairs => "Stone Brick Stairs", + Item::Mycelium => "Mycelium", + Item::LilyPad => "Lily Pad", + Item::NetherBricks => "Nether Bricks", + Item::CrackedNetherBricks => "Cracked Nether Bricks", + Item::ChiseledNetherBricks => "Chiseled Nether Bricks", + Item::NetherBrickFence => "Nether Brick Fence", + Item::NetherBrickStairs => "Nether Brick Stairs", + Item::EnchantingTable => "Enchanting Table", + Item::EndPortalFrame => "End Portal Frame", + Item::EndStone => "End Stone", + Item::EndStoneBricks => "End Stone Bricks", + Item::DragonEgg => "Dragon Egg", + Item::RedstoneLamp => "Redstone Lamp", + Item::SandstoneStairs => "Sandstone Stairs", + Item::EmeraldOre => "Emerald Ore", + Item::EnderChest => "Ender Chest", + Item::TripwireHook => "Tripwire Hook", + Item::EmeraldBlock => "Block of Emerald", + Item::SpruceStairs => "Spruce Stairs", + Item::BirchStairs => "Birch Stairs", + Item::JungleStairs => "Jungle Stairs", + Item::CrimsonStairs => "Crimson Stairs", + Item::WarpedStairs => "Warped Stairs", + Item::CommandBlock => "Command Block", + Item::Beacon => "Beacon", + Item::CobblestoneWall => "Cobblestone Wall", + Item::MossyCobblestoneWall => "Mossy Cobblestone Wall", + Item::BrickWall => "Brick Wall", + Item::PrismarineWall => "Prismarine Wall", + Item::RedSandstoneWall => "Red Sandstone Wall", + Item::MossyStoneBrickWall => "Mossy Stone Brick Wall", + Item::GraniteWall => "Granite Wall", + Item::StoneBrickWall => "Stone Brick Wall", + Item::NetherBrickWall => "Nether Brick Wall", + Item::AndesiteWall => "Andesite Wall", + Item::RedNetherBrickWall => "Red Nether Brick Wall", + Item::SandstoneWall => "Sandstone Wall", + Item::EndStoneBrickWall => "End Stone Brick Wall", + Item::DioriteWall => "Diorite Wall", + Item::BlackstoneWall => "Blackstone Wall", + Item::PolishedBlackstoneWall => "Polished Blackstone Wall", + Item::PolishedBlackstoneBrickWall => "Polished Blackstone Brick Wall", + Item::StoneButton => "Stone Button", + Item::OakButton => "Oak Button", + Item::SpruceButton => "Spruce Button", + Item::BirchButton => "Birch Button", + Item::JungleButton => "Jungle Button", + Item::AcaciaButton => "Acacia Button", + Item::DarkOakButton => "Dark Oak Button", + Item::CrimsonButton => "Crimson Button", + Item::WarpedButton => "Warped Button", + Item::PolishedBlackstoneButton => "Polished Blackstone Button", + Item::Anvil => "Anvil", + Item::ChippedAnvil => "Chipped Anvil", + Item::DamagedAnvil => "Damaged Anvil", + Item::TrappedChest => "Trapped Chest", + Item::LightWeightedPressurePlate => "Light Weighted Pressure Plate", + Item::HeavyWeightedPressurePlate => "Heavy Weighted Pressure Plate", + Item::DaylightDetector => "Daylight Detector", + Item::RedstoneBlock => "Block of Redstone", + Item::NetherQuartzOre => "Nether Quartz Ore", + Item::Hopper => "Hopper", + Item::ChiseledQuartzBlock => "Chiseled Quartz Block", + Item::QuartzBlock => "Block of Quartz", + Item::QuartzBricks => "Quartz Bricks", + Item::QuartzPillar => "Quartz Pillar", + Item::QuartzStairs => "Quartz Stairs", + Item::ActivatorRail => "Activator Rail", + Item::Dropper => "Dropper", + Item::WhiteTerracotta => "White Terracotta", + Item::OrangeTerracotta => "Orange Terracotta", + Item::MagentaTerracotta => "Magenta Terracotta", + Item::LightBlueTerracotta => "Light Blue Terracotta", + Item::YellowTerracotta => "Yellow Terracotta", + Item::LimeTerracotta => "Lime Terracotta", + Item::PinkTerracotta => "Pink Terracotta", + Item::GrayTerracotta => "Gray Terracotta", + Item::LightGrayTerracotta => "Light Gray Terracotta", + Item::CyanTerracotta => "Cyan Terracotta", + Item::PurpleTerracotta => "Purple Terracotta", + Item::BlueTerracotta => "Blue Terracotta", + Item::BrownTerracotta => "Brown Terracotta", + Item::GreenTerracotta => "Green Terracotta", + Item::RedTerracotta => "Red Terracotta", + Item::BlackTerracotta => "Black Terracotta", + Item::Barrier => "Barrier", + Item::IronTrapdoor => "Iron Trapdoor", + Item::HayBlock => "Hay Bale", + Item::WhiteCarpet => "White Carpet", + Item::OrangeCarpet => "Orange Carpet", + Item::MagentaCarpet => "Magenta Carpet", + Item::LightBlueCarpet => "Light Blue Carpet", + Item::YellowCarpet => "Yellow Carpet", + Item::LimeCarpet => "Lime Carpet", + Item::PinkCarpet => "Pink Carpet", + Item::GrayCarpet => "Gray Carpet", + Item::LightGrayCarpet => "Light Gray Carpet", + Item::CyanCarpet => "Cyan Carpet", + Item::PurpleCarpet => "Purple Carpet", + Item::BlueCarpet => "Blue Carpet", + Item::BrownCarpet => "Brown Carpet", + Item::GreenCarpet => "Green Carpet", + Item::RedCarpet => "Red Carpet", + Item::BlackCarpet => "Black Carpet", + Item::Terracotta => "Terracotta", + Item::CoalBlock => "Block of Coal", + Item::PackedIce => "Packed Ice", + Item::AcaciaStairs => "Acacia Stairs", + Item::DarkOakStairs => "Dark Oak Stairs", + Item::SlimeBlock => "Slime Block", + Item::GrassPath => "Grass Path", + Item::Sunflower => "Sunflower", + Item::Lilac => "Lilac", + Item::RoseBush => "Rose Bush", + Item::Peony => "Peony", + Item::TallGrass => "Tall Grass", + Item::LargeFern => "Large Fern", + Item::WhiteStainedGlass => "White Stained Glass", + Item::OrangeStainedGlass => "Orange Stained Glass", + Item::MagentaStainedGlass => "Magenta Stained Glass", + Item::LightBlueStainedGlass => "Light Blue Stained Glass", + Item::YellowStainedGlass => "Yellow Stained Glass", + Item::LimeStainedGlass => "Lime Stained Glass", + Item::PinkStainedGlass => "Pink Stained Glass", + Item::GrayStainedGlass => "Gray Stained Glass", + Item::LightGrayStainedGlass => "Light Gray Stained Glass", + Item::CyanStainedGlass => "Cyan Stained Glass", + Item::PurpleStainedGlass => "Purple Stained Glass", + Item::BlueStainedGlass => "Blue Stained Glass", + Item::BrownStainedGlass => "Brown Stained Glass", + Item::GreenStainedGlass => "Green Stained Glass", + Item::RedStainedGlass => "Red Stained Glass", + Item::BlackStainedGlass => "Black Stained Glass", + Item::WhiteStainedGlassPane => "White Stained Glass Pane", + Item::OrangeStainedGlassPane => "Orange Stained Glass Pane", + Item::MagentaStainedGlassPane => "Magenta Stained Glass Pane", + Item::LightBlueStainedGlassPane => "Light Blue Stained Glass Pane", + Item::YellowStainedGlassPane => "Yellow Stained Glass Pane", + Item::LimeStainedGlassPane => "Lime Stained Glass Pane", + Item::PinkStainedGlassPane => "Pink Stained Glass Pane", + Item::GrayStainedGlassPane => "Gray Stained Glass Pane", + Item::LightGrayStainedGlassPane => "Light Gray Stained Glass Pane", + Item::CyanStainedGlassPane => "Cyan Stained Glass Pane", + Item::PurpleStainedGlassPane => "Purple Stained Glass Pane", + Item::BlueStainedGlassPane => "Blue Stained Glass Pane", + Item::BrownStainedGlassPane => "Brown Stained Glass Pane", + Item::GreenStainedGlassPane => "Green Stained Glass Pane", + Item::RedStainedGlassPane => "Red Stained Glass Pane", + Item::BlackStainedGlassPane => "Black Stained Glass Pane", + Item::Prismarine => "Prismarine", + Item::PrismarineBricks => "Prismarine Bricks", + Item::DarkPrismarine => "Dark Prismarine", + Item::PrismarineStairs => "Prismarine Stairs", + Item::PrismarineBrickStairs => "Prismarine Brick Stairs", + Item::DarkPrismarineStairs => "Dark Prismarine Stairs", + Item::SeaLantern => "Sea Lantern", + Item::RedSandstone => "Red Sandstone", + Item::ChiseledRedSandstone => "Chiseled Red Sandstone", + Item::CutRedSandstone => "Cut Red Sandstone", + Item::RedSandstoneStairs => "Red Sandstone Stairs", + Item::RepeatingCommandBlock => "Repeating Command Block", + Item::ChainCommandBlock => "Chain Command Block", + Item::MagmaBlock => "Magma Block", + Item::NetherWartBlock => "Nether Wart Block", + Item::WarpedWartBlock => "Warped Wart Block", + Item::RedNetherBricks => "Red Nether Bricks", + Item::BoneBlock => "Bone Block", + Item::StructureVoid => "Structure Void", + Item::Observer => "Observer", + Item::ShulkerBox => "Shulker Box", + Item::WhiteShulkerBox => "White Shulker Box", + Item::OrangeShulkerBox => "Orange Shulker Box", + Item::MagentaShulkerBox => "Magenta Shulker Box", + Item::LightBlueShulkerBox => "Light Blue Shulker Box", + Item::YellowShulkerBox => "Yellow Shulker Box", + Item::LimeShulkerBox => "Lime Shulker Box", + Item::PinkShulkerBox => "Pink Shulker Box", + Item::GrayShulkerBox => "Gray Shulker Box", + Item::LightGrayShulkerBox => "Light Gray Shulker Box", + Item::CyanShulkerBox => "Cyan Shulker Box", + Item::PurpleShulkerBox => "Purple Shulker Box", + Item::BlueShulkerBox => "Blue Shulker Box", + Item::BrownShulkerBox => "Brown Shulker Box", + Item::GreenShulkerBox => "Green Shulker Box", + Item::RedShulkerBox => "Red Shulker Box", + Item::BlackShulkerBox => "Black Shulker Box", + Item::WhiteGlazedTerracotta => "White Glazed Terracotta", + Item::OrangeGlazedTerracotta => "Orange Glazed Terracotta", + Item::MagentaGlazedTerracotta => "Magenta Glazed Terracotta", + Item::LightBlueGlazedTerracotta => "Light Blue Glazed Terracotta", + Item::YellowGlazedTerracotta => "Yellow Glazed Terracotta", + Item::LimeGlazedTerracotta => "Lime Glazed Terracotta", + Item::PinkGlazedTerracotta => "Pink Glazed Terracotta", + Item::GrayGlazedTerracotta => "Gray Glazed Terracotta", + Item::LightGrayGlazedTerracotta => "Light Gray Glazed Terracotta", + Item::CyanGlazedTerracotta => "Cyan Glazed Terracotta", + Item::PurpleGlazedTerracotta => "Purple Glazed Terracotta", + Item::BlueGlazedTerracotta => "Blue Glazed Terracotta", + Item::BrownGlazedTerracotta => "Brown Glazed Terracotta", + Item::GreenGlazedTerracotta => "Green Glazed Terracotta", + Item::RedGlazedTerracotta => "Red Glazed Terracotta", + Item::BlackGlazedTerracotta => "Black Glazed Terracotta", + Item::WhiteConcrete => "White Concrete", + Item::OrangeConcrete => "Orange Concrete", + Item::MagentaConcrete => "Magenta Concrete", + Item::LightBlueConcrete => "Light Blue Concrete", + Item::YellowConcrete => "Yellow Concrete", + Item::LimeConcrete => "Lime Concrete", + Item::PinkConcrete => "Pink Concrete", + Item::GrayConcrete => "Gray Concrete", + Item::LightGrayConcrete => "Light Gray Concrete", + Item::CyanConcrete => "Cyan Concrete", + Item::PurpleConcrete => "Purple Concrete", + Item::BlueConcrete => "Blue Concrete", + Item::BrownConcrete => "Brown Concrete", + Item::GreenConcrete => "Green Concrete", + Item::RedConcrete => "Red Concrete", + Item::BlackConcrete => "Black Concrete", + Item::WhiteConcretePowder => "White Concrete Powder", + Item::OrangeConcretePowder => "Orange Concrete Powder", + Item::MagentaConcretePowder => "Magenta Concrete Powder", + Item::LightBlueConcretePowder => "Light Blue Concrete Powder", + Item::YellowConcretePowder => "Yellow Concrete Powder", + Item::LimeConcretePowder => "Lime Concrete Powder", + Item::PinkConcretePowder => "Pink Concrete Powder", + Item::GrayConcretePowder => "Gray Concrete Powder", + Item::LightGrayConcretePowder => "Light Gray Concrete Powder", + Item::CyanConcretePowder => "Cyan Concrete Powder", + Item::PurpleConcretePowder => "Purple Concrete Powder", + Item::BlueConcretePowder => "Blue Concrete Powder", + Item::BrownConcretePowder => "Brown Concrete Powder", + Item::GreenConcretePowder => "Green Concrete Powder", + Item::RedConcretePowder => "Red Concrete Powder", + Item::BlackConcretePowder => "Black Concrete Powder", + Item::TurtleEgg => "Turtle Egg", + Item::DeadTubeCoralBlock => "Dead Tube Coral Block", + Item::DeadBrainCoralBlock => "Dead Brain Coral Block", + Item::DeadBubbleCoralBlock => "Dead Bubble Coral Block", + Item::DeadFireCoralBlock => "Dead Fire Coral Block", + Item::DeadHornCoralBlock => "Dead Horn Coral Block", + Item::TubeCoralBlock => "Tube Coral Block", + Item::BrainCoralBlock => "Brain Coral Block", + Item::BubbleCoralBlock => "Bubble Coral Block", + Item::FireCoralBlock => "Fire Coral Block", + Item::HornCoralBlock => "Horn Coral Block", + Item::TubeCoral => "Tube Coral", + Item::BrainCoral => "Brain Coral", + Item::BubbleCoral => "Bubble Coral", + Item::FireCoral => "Fire Coral", + Item::HornCoral => "Horn Coral", + Item::DeadBrainCoral => "Dead Brain Coral", + Item::DeadBubbleCoral => "Dead Bubble Coral", + Item::DeadFireCoral => "Dead Fire Coral", + Item::DeadHornCoral => "Dead Horn Coral", + Item::DeadTubeCoral => "Dead Tube Coral", + Item::TubeCoralFan => "Tube Coral Fan", + Item::BrainCoralFan => "Brain Coral Fan", + Item::BubbleCoralFan => "Bubble Coral Fan", + Item::FireCoralFan => "Fire Coral Fan", + Item::HornCoralFan => "Horn Coral Fan", + Item::DeadTubeCoralFan => "Dead Tube Coral Fan", + Item::DeadBrainCoralFan => "Dead Brain Coral Fan", + Item::DeadBubbleCoralFan => "Dead Bubble Coral Fan", + Item::DeadFireCoralFan => "Dead Fire Coral Fan", + Item::DeadHornCoralFan => "Dead Horn Coral Fan", + Item::BlueIce => "Blue Ice", + Item::Conduit => "Conduit", + Item::PolishedGraniteStairs => "Polished Granite Stairs", + Item::SmoothRedSandstoneStairs => "Smooth Red Sandstone Stairs", + Item::MossyStoneBrickStairs => "Mossy Stone Brick Stairs", + Item::PolishedDioriteStairs => "Polished Diorite Stairs", + Item::MossyCobblestoneStairs => "Mossy Cobblestone Stairs", + Item::EndStoneBrickStairs => "End Stone Brick Stairs", + Item::StoneStairs => "Stone Stairs", + Item::SmoothSandstoneStairs => "Smooth Sandstone Stairs", + Item::SmoothQuartzStairs => "Smooth Quartz Stairs", + Item::GraniteStairs => "Granite Stairs", + Item::AndesiteStairs => "Andesite Stairs", + Item::RedNetherBrickStairs => "Red Nether Brick Stairs", + Item::PolishedAndesiteStairs => "Polished Andesite Stairs", + Item::DioriteStairs => "Diorite Stairs", + Item::PolishedGraniteSlab => "Polished Granite Slab", + Item::SmoothRedSandstoneSlab => "Smooth Red Sandstone Slab", + Item::MossyStoneBrickSlab => "Mossy Stone Brick Slab", + Item::PolishedDioriteSlab => "Polished Diorite Slab", + Item::MossyCobblestoneSlab => "Mossy Cobblestone Slab", + Item::EndStoneBrickSlab => "End Stone Brick Slab", + Item::SmoothSandstoneSlab => "Smooth Sandstone Slab", + Item::SmoothQuartzSlab => "Smooth Quartz Slab", + Item::GraniteSlab => "Granite Slab", + Item::AndesiteSlab => "Andesite Slab", + Item::RedNetherBrickSlab => "Red Nether Brick Slab", + Item::PolishedAndesiteSlab => "Polished Andesite Slab", + Item::DioriteSlab => "Diorite Slab", + Item::Scaffolding => "Scaffolding", + Item::IronDoor => "Iron Door", + Item::OakDoor => "Oak Door", + Item::SpruceDoor => "Spruce Door", + Item::BirchDoor => "Birch Door", + Item::JungleDoor => "Jungle Door", + Item::AcaciaDoor => "Acacia Door", + Item::DarkOakDoor => "Dark Oak Door", + Item::CrimsonDoor => "Crimson Door", + Item::WarpedDoor => "Warped Door", + Item::Repeater => "Redstone Repeater", + Item::Comparator => "Redstone Comparator", + Item::StructureBlock => "Structure Block", + Item::Jigsaw => "Jigsaw Block", + Item::TurtleHelmet => "Turtle Shell", + Item::Scute => "Scute", + Item::FlintAndSteel => "Flint and Steel", + Item::Apple => "Apple", + Item::Bow => "Bow", + Item::Arrow => "Arrow", + Item::Coal => "Coal", + Item::Charcoal => "Charcoal", + Item::Diamond => "Diamond", + Item::IronIngot => "Iron Ingot", + Item::GoldIngot => "Gold Ingot", + Item::NetheriteIngot => "Netherite Ingot", + Item::NetheriteScrap => "Netherite Scrap", + Item::WoodenSword => "Wooden Sword", + Item::WoodenShovel => "Wooden Shovel", + Item::WoodenPickaxe => "Wooden Pickaxe", + Item::WoodenAxe => "Wooden Axe", + Item::WoodenHoe => "Wooden Hoe", + Item::StoneSword => "Stone Sword", + Item::StoneShovel => "Stone Shovel", + Item::StonePickaxe => "Stone Pickaxe", + Item::StoneAxe => "Stone Axe", + Item::StoneHoe => "Stone Hoe", + Item::GoldenSword => "Golden Sword", + Item::GoldenShovel => "Golden Shovel", + Item::GoldenPickaxe => "Golden Pickaxe", + Item::GoldenAxe => "Golden Axe", + Item::GoldenHoe => "Golden Hoe", + Item::IronSword => "Iron Sword", + Item::IronShovel => "Iron Shovel", + Item::IronPickaxe => "Iron Pickaxe", + Item::IronAxe => "Iron Axe", + Item::IronHoe => "Iron Hoe", + Item::DiamondSword => "Diamond Sword", + Item::DiamondShovel => "Diamond Shovel", + Item::DiamondPickaxe => "Diamond Pickaxe", + Item::DiamondAxe => "Diamond Axe", + Item::DiamondHoe => "Diamond Hoe", + Item::NetheriteSword => "Netherite Sword", + Item::NetheriteShovel => "Netherite Shovel", + Item::NetheritePickaxe => "Netherite Pickaxe", + Item::NetheriteAxe => "Netherite Axe", + Item::NetheriteHoe => "Netherite Hoe", + Item::Stick => "Stick", + Item::Bowl => "Bowl", + Item::MushroomStew => "Mushroom Stew", + Item::String => "String", + Item::Feather => "Feather", + Item::Gunpowder => "Gunpowder", + Item::WheatSeeds => "Wheat Seeds", + Item::Wheat => "Wheat", + Item::Bread => "Bread", + Item::LeatherHelmet => "Leather Cap", + Item::LeatherChestplate => "Leather Tunic", + Item::LeatherLeggings => "Leather Pants", + Item::LeatherBoots => "Leather Boots", + Item::ChainmailHelmet => "Chainmail Helmet", + Item::ChainmailChestplate => "Chainmail Chestplate", + Item::ChainmailLeggings => "Chainmail Leggings", + Item::ChainmailBoots => "Chainmail Boots", + Item::IronHelmet => "Iron Helmet", + Item::IronChestplate => "Iron Chestplate", + Item::IronLeggings => "Iron Leggings", + Item::IronBoots => "Iron Boots", + Item::DiamondHelmet => "Diamond Helmet", + Item::DiamondChestplate => "Diamond Chestplate", + Item::DiamondLeggings => "Diamond Leggings", + Item::DiamondBoots => "Diamond Boots", + Item::GoldenHelmet => "Golden Helmet", + Item::GoldenChestplate => "Golden Chestplate", + Item::GoldenLeggings => "Golden Leggings", + Item::GoldenBoots => "Golden Boots", + Item::NetheriteHelmet => "Netherite Helmet", + Item::NetheriteChestplate => "Netherite Chestplate", + Item::NetheriteLeggings => "Netherite Leggings", + Item::NetheriteBoots => "Netherite Boots", + Item::Flint => "Flint", + Item::Porkchop => "Raw Porkchop", + Item::CookedPorkchop => "Cooked Porkchop", + Item::Painting => "Painting", + Item::GoldenApple => "Golden Apple", + Item::EnchantedGoldenApple => "Enchanted Golden Apple", + Item::OakSign => "Oak Sign", + Item::SpruceSign => "Spruce Sign", + Item::BirchSign => "Birch Sign", + Item::JungleSign => "Jungle Sign", + Item::AcaciaSign => "Acacia Sign", + Item::DarkOakSign => "Dark Oak Sign", + Item::CrimsonSign => "Crimson Sign", + Item::WarpedSign => "Warped Sign", + Item::Bucket => "Bucket", + Item::WaterBucket => "Water Bucket", + Item::LavaBucket => "Lava Bucket", + Item::Minecart => "Minecart", + Item::Saddle => "Saddle", + Item::Redstone => "Redstone Dust", + Item::Snowball => "Snowball", + Item::OakBoat => "Oak Boat", + Item::Leather => "Leather", + Item::MilkBucket => "Milk Bucket", + Item::PufferfishBucket => "Bucket of Pufferfish", + Item::SalmonBucket => "Bucket of Salmon", + Item::CodBucket => "Bucket of Cod", + Item::TropicalFishBucket => "Bucket of Tropical Fish", + Item::Brick => "Brick", + Item::ClayBall => "Clay Ball", + Item::DriedKelpBlock => "Dried Kelp Block", + Item::Paper => "Paper", + Item::Book => "Book", + Item::SlimeBall => "Slimeball", + Item::ChestMinecart => "Minecart with Chest", + Item::FurnaceMinecart => "Minecart with Furnace", + Item::Egg => "Egg", + Item::Compass => "Compass", + Item::FishingRod => "Fishing Rod", + Item::Clock => "Clock", + Item::GlowstoneDust => "Glowstone Dust", + Item::Cod => "Raw Cod", + Item::Salmon => "Raw Salmon", + Item::TropicalFish => "Tropical Fish", + Item::Pufferfish => "Pufferfish", + Item::CookedCod => "Cooked Cod", + Item::CookedSalmon => "Cooked Salmon", + Item::InkSac => "Ink Sac", + Item::CocoaBeans => "Cocoa Beans", + Item::LapisLazuli => "Lapis Lazuli", + Item::WhiteDye => "White Dye", + Item::OrangeDye => "Orange Dye", + Item::MagentaDye => "Magenta Dye", + Item::LightBlueDye => "Light Blue Dye", + Item::YellowDye => "Yellow Dye", + Item::LimeDye => "Lime Dye", + Item::PinkDye => "Pink Dye", + Item::GrayDye => "Gray Dye", + Item::LightGrayDye => "Light Gray Dye", + Item::CyanDye => "Cyan Dye", + Item::PurpleDye => "Purple Dye", + Item::BlueDye => "Blue Dye", + Item::BrownDye => "Brown Dye", + Item::GreenDye => "Green Dye", + Item::RedDye => "Red Dye", + Item::BlackDye => "Black Dye", + Item::BoneMeal => "Bone Meal", + Item::Bone => "Bone", + Item::Sugar => "Sugar", + Item::Cake => "Cake", + Item::WhiteBed => "White Bed", + Item::OrangeBed => "Orange Bed", + Item::MagentaBed => "Magenta Bed", + Item::LightBlueBed => "Light Blue Bed", + Item::YellowBed => "Yellow Bed", + Item::LimeBed => "Lime Bed", + Item::PinkBed => "Pink Bed", + Item::GrayBed => "Gray Bed", + Item::LightGrayBed => "Light Gray Bed", + Item::CyanBed => "Cyan Bed", + Item::PurpleBed => "Purple Bed", + Item::BlueBed => "Blue Bed", + Item::BrownBed => "Brown Bed", + Item::GreenBed => "Green Bed", + Item::RedBed => "Red Bed", + Item::BlackBed => "Black Bed", + Item::Cookie => "Cookie", + Item::FilledMap => "Map", + Item::Shears => "Shears", + Item::MelonSlice => "Melon Slice", + Item::DriedKelp => "Dried Kelp", + Item::PumpkinSeeds => "Pumpkin Seeds", + Item::MelonSeeds => "Melon Seeds", + Item::Beef => "Raw Beef", + Item::CookedBeef => "Steak", + Item::Chicken => "Raw Chicken", + Item::CookedChicken => "Cooked Chicken", + Item::RottenFlesh => "Rotten Flesh", + Item::EnderPearl => "Ender Pearl", + Item::BlazeRod => "Blaze Rod", + Item::GhastTear => "Ghast Tear", + Item::GoldNugget => "Gold Nugget", + Item::NetherWart => "Nether Wart", + Item::Potion => "Potion", + Item::GlassBottle => "Glass Bottle", + Item::SpiderEye => "Spider Eye", + Item::FermentedSpiderEye => "Fermented Spider Eye", + Item::BlazePowder => "Blaze Powder", + Item::MagmaCream => "Magma Cream", + Item::BrewingStand => "Brewing Stand", + Item::Cauldron => "Cauldron", + Item::EnderEye => "Eye of Ender", + Item::GlisteringMelonSlice => "Glistering Melon Slice", + Item::BatSpawnEgg => "Bat Spawn Egg", + Item::BeeSpawnEgg => "Bee Spawn Egg", + Item::BlazeSpawnEgg => "Blaze Spawn Egg", + Item::CatSpawnEgg => "Cat Spawn Egg", + Item::CaveSpiderSpawnEgg => "Cave Spider Spawn Egg", + Item::ChickenSpawnEgg => "Chicken Spawn Egg", + Item::CodSpawnEgg => "Cod Spawn Egg", + Item::CowSpawnEgg => "Cow Spawn Egg", + Item::CreeperSpawnEgg => "Creeper Spawn Egg", + Item::DolphinSpawnEgg => "Dolphin Spawn Egg", + Item::DonkeySpawnEgg => "Donkey Spawn Egg", + Item::DrownedSpawnEgg => "Drowned Spawn Egg", + Item::ElderGuardianSpawnEgg => "Elder Guardian Spawn Egg", + Item::EndermanSpawnEgg => "Enderman Spawn Egg", + Item::EndermiteSpawnEgg => "Endermite Spawn Egg", + Item::EvokerSpawnEgg => "Evoker Spawn Egg", + Item::FoxSpawnEgg => "Fox Spawn Egg", + Item::GhastSpawnEgg => "Ghast Spawn Egg", + Item::GuardianSpawnEgg => "Guardian Spawn Egg", + Item::HoglinSpawnEgg => "Hoglin Spawn Egg", + Item::HorseSpawnEgg => "Horse Spawn Egg", + Item::HuskSpawnEgg => "Husk Spawn Egg", + Item::LlamaSpawnEgg => "Llama Spawn Egg", + Item::MagmaCubeSpawnEgg => "Magma Cube Spawn Egg", + Item::MooshroomSpawnEgg => "Mooshroom Spawn Egg", + Item::MuleSpawnEgg => "Mule Spawn Egg", + Item::OcelotSpawnEgg => "Ocelot Spawn Egg", + Item::PandaSpawnEgg => "Panda Spawn Egg", + Item::ParrotSpawnEgg => "Parrot Spawn Egg", + Item::PhantomSpawnEgg => "Phantom Spawn Egg", + Item::PigSpawnEgg => "Pig Spawn Egg", + Item::PiglinSpawnEgg => "Piglin Spawn Egg", + Item::PiglinBruteSpawnEgg => "Piglin Brute Spawn Egg", + Item::PillagerSpawnEgg => "Pillager Spawn Egg", + Item::PolarBearSpawnEgg => "Polar Bear Spawn Egg", + Item::PufferfishSpawnEgg => "Pufferfish Spawn Egg", + Item::RabbitSpawnEgg => "Rabbit Spawn Egg", + Item::RavagerSpawnEgg => "Ravager Spawn Egg", + Item::SalmonSpawnEgg => "Salmon Spawn Egg", + Item::SheepSpawnEgg => "Sheep Spawn Egg", + Item::ShulkerSpawnEgg => "Shulker Spawn Egg", + Item::SilverfishSpawnEgg => "Silverfish Spawn Egg", + Item::SkeletonSpawnEgg => "Skeleton Spawn Egg", + Item::SkeletonHorseSpawnEgg => "Skeleton Horse Spawn Egg", + Item::SlimeSpawnEgg => "Slime Spawn Egg", + Item::SpiderSpawnEgg => "Spider Spawn Egg", + Item::SquidSpawnEgg => "Squid Spawn Egg", + Item::StraySpawnEgg => "Stray Spawn Egg", + Item::StriderSpawnEgg => "Strider Spawn Egg", + Item::TraderLlamaSpawnEgg => "Trader Llama Spawn Egg", + Item::TropicalFishSpawnEgg => "Tropical Fish Spawn Egg", + Item::TurtleSpawnEgg => "Turtle Spawn Egg", + Item::VexSpawnEgg => "Vex Spawn Egg", + Item::VillagerSpawnEgg => "Villager Spawn Egg", + Item::VindicatorSpawnEgg => "Vindicator Spawn Egg", + Item::WanderingTraderSpawnEgg => "Wandering Trader Spawn Egg", + Item::WitchSpawnEgg => "Witch Spawn Egg", + Item::WitherSkeletonSpawnEgg => "Wither Skeleton Spawn Egg", + Item::WolfSpawnEgg => "Wolf Spawn Egg", + Item::ZoglinSpawnEgg => "Zoglin Spawn Egg", + Item::ZombieSpawnEgg => "Zombie Spawn Egg", + Item::ZombieHorseSpawnEgg => "Zombie Horse Spawn Egg", + Item::ZombieVillagerSpawnEgg => "Zombie Villager Spawn Egg", + Item::ZombifiedPiglinSpawnEgg => "Zombified Piglin Spawn Egg", + Item::ExperienceBottle => "Bottle o' Enchanting", + Item::FireCharge => "Fire Charge", + Item::WritableBook => "Book and Quill", + Item::WrittenBook => "Written Book", + Item::Emerald => "Emerald", + Item::ItemFrame => "Item Frame", + Item::FlowerPot => "Flower Pot", + Item::Carrot => "Carrot", + Item::Potato => "Potato", + Item::BakedPotato => "Baked Potato", + Item::PoisonousPotato => "Poisonous Potato", + Item::Map => "Empty Map", + Item::GoldenCarrot => "Golden Carrot", + Item::SkeletonSkull => "Skeleton Skull", + Item::WitherSkeletonSkull => "Wither Skeleton Skull", + Item::PlayerHead => "Player Head", + Item::ZombieHead => "Zombie Head", + Item::CreeperHead => "Creeper Head", + Item::DragonHead => "Dragon Head", + Item::CarrotOnAStick => "Carrot on a Stick", + Item::WarpedFungusOnAStick => "Warped Fungus on a Stick", + Item::NetherStar => "Nether Star", + Item::PumpkinPie => "Pumpkin Pie", + Item::FireworkRocket => "Firework Rocket", + Item::FireworkStar => "Firework Star", + Item::EnchantedBook => "Enchanted Book", + Item::NetherBrick => "Nether Brick", + Item::Quartz => "Nether Quartz", + Item::TntMinecart => "Minecart with TNT", + Item::HopperMinecart => "Minecart with Hopper", + Item::PrismarineShard => "Prismarine Shard", + Item::PrismarineCrystals => "Prismarine Crystals", + Item::Rabbit => "Raw Rabbit", + Item::CookedRabbit => "Cooked Rabbit", + Item::RabbitStew => "Rabbit Stew", + Item::RabbitFoot => "Rabbit's Foot", + Item::RabbitHide => "Rabbit Hide", + Item::ArmorStand => "Armor Stand", + Item::IronHorseArmor => "Iron Horse Armor", + Item::GoldenHorseArmor => "Golden Horse Armor", + Item::DiamondHorseArmor => "Diamond Horse Armor", + Item::LeatherHorseArmor => "Leather Horse Armor", + Item::Lead => "Lead", + Item::NameTag => "Name Tag", + Item::CommandBlockMinecart => "Minecart with Command Block", + Item::Mutton => "Raw Mutton", + Item::CookedMutton => "Cooked Mutton", + Item::WhiteBanner => "White Banner", + Item::OrangeBanner => "Orange Banner", + Item::MagentaBanner => "Magenta Banner", + Item::LightBlueBanner => "Light Blue Banner", + Item::YellowBanner => "Yellow Banner", + Item::LimeBanner => "Lime Banner", + Item::PinkBanner => "Pink Banner", + Item::GrayBanner => "Gray Banner", + Item::LightGrayBanner => "Light Gray Banner", + Item::CyanBanner => "Cyan Banner", + Item::PurpleBanner => "Purple Banner", + Item::BlueBanner => "Blue Banner", + Item::BrownBanner => "Brown Banner", + Item::GreenBanner => "Green Banner", + Item::RedBanner => "Red Banner", + Item::BlackBanner => "Black Banner", + Item::EndCrystal => "End Crystal", + Item::ChorusFruit => "Chorus Fruit", + Item::PoppedChorusFruit => "Popped Chorus Fruit", + Item::Beetroot => "Beetroot", + Item::BeetrootSeeds => "Beetroot Seeds", + Item::BeetrootSoup => "Beetroot Soup", + Item::DragonBreath => "Dragon's Breath", + Item::SplashPotion => "Splash Potion", + Item::SpectralArrow => "Spectral Arrow", + Item::TippedArrow => "Tipped Arrow", + Item::LingeringPotion => "Lingering Potion", + Item::Shield => "Shield", + Item::Elytra => "Elytra", + Item::SpruceBoat => "Spruce Boat", + Item::BirchBoat => "Birch Boat", + Item::JungleBoat => "Jungle Boat", + Item::AcaciaBoat => "Acacia Boat", + Item::DarkOakBoat => "Dark Oak Boat", + Item::TotemOfUndying => "Totem of Undying", + Item::ShulkerShell => "Shulker Shell", + Item::IronNugget => "Iron Nugget", + Item::KnowledgeBook => "Knowledge Book", + Item::DebugStick => "Debug Stick", + Item::MusicDisc13 => "13 Disc", + Item::MusicDiscCat => "Cat Disc", + Item::MusicDiscBlocks => "Blocks Disc", + Item::MusicDiscChirp => "Chirp Disc", + Item::MusicDiscFar => "Far Disc", + Item::MusicDiscMall => "Mall Disc", + Item::MusicDiscMellohi => "Mellohi Disc", + Item::MusicDiscStal => "Stal Disc", + Item::MusicDiscStrad => "Strad Disc", + Item::MusicDiscWard => "Ward Disc", + Item::MusicDisc11 => "11 Disc", + Item::MusicDiscWait => "Wait Disc", + Item::MusicDiscPigstep => "Music Disc", + Item::Trident => "Trident", + Item::PhantomMembrane => "Phantom Membrane", + Item::NautilusShell => "Nautilus Shell", + Item::HeartOfTheSea => "Heart of the Sea", + Item::Crossbow => "Crossbow", + Item::SuspiciousStew => "Suspicious Stew", + Item::Loom => "Loom", + Item::FlowerBannerPattern => "Banner Pattern", + Item::CreeperBannerPattern => "Banner Pattern", + Item::SkullBannerPattern => "Banner Pattern", + Item::MojangBannerPattern => "Banner Pattern", + Item::GlobeBannerPattern => "Banner Pattern", + Item::PiglinBannerPattern => "Banner Pattern", + Item::Composter => "Composter", + Item::Barrel => "Barrel", + Item::Smoker => "Smoker", + Item::BlastFurnace => "Blast Furnace", + Item::CartographyTable => "Cartography Table", + Item::FletchingTable => "Fletching Table", + Item::Grindstone => "Grindstone", + Item::Lectern => "Lectern", + Item::SmithingTable => "Smithing Table", + Item::Stonecutter => "Stonecutter", + Item::Bell => "Bell", + Item::Lantern => "Lantern", + Item::SoulLantern => "Soul Lantern", + Item::SweetBerries => "Sweet Berries", + Item::Campfire => "Campfire", + Item::SoulCampfire => "Soul Campfire", + Item::Shroomlight => "Shroomlight", + Item::Honeycomb => "Honeycomb", + Item::BeeNest => "Bee Nest", + Item::Beehive => "Beehive", + Item::HoneyBottle => "Honey Bottle", + Item::HoneyBlock => "Honey Block", + Item::HoneycombBlock => "Honeycomb Block", + Item::Lodestone => "Lodestone", + Item::NetheriteBlock => "Block of Netherite", + Item::AncientDebris => "Ancient Debris", + Item::Target => "Target", + Item::CryingObsidian => "Crying Obsidian", + Item::Blackstone => "Blackstone", + Item::BlackstoneSlab => "Blackstone Slab", + Item::BlackstoneStairs => "Blackstone Stairs", + Item::GildedBlackstone => "Gilded Blackstone", + Item::PolishedBlackstone => "Polished Blackstone", + Item::PolishedBlackstoneSlab => "Polished Blackstone Slab", + Item::PolishedBlackstoneStairs => "Polished Blackstone Stairs", + Item::ChiseledPolishedBlackstone => "Chiseled Polished Blackstone", + Item::PolishedBlackstoneBricks => "Polished Blackstone Bricks", + Item::PolishedBlackstoneBrickSlab => "Polished Blackstone Brick Slab", + Item::PolishedBlackstoneBrickStairs => "Polished Blackstone Brick Stairs", + Item::CrackedPolishedBlackstoneBricks => "Cracked Polished Blackstone Bricks", + Item::RespawnAnchor => "Respawn Anchor", + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Item { + /// Returns the `stack_size` property of this `Item`. + pub fn stack_size(&self) -> u32 { + match self { + Item::Air => 0, + Item::Stone => 64, + Item::Granite => 64, + Item::PolishedGranite => 64, + Item::Diorite => 64, + Item::PolishedDiorite => 64, + Item::Andesite => 64, + Item::PolishedAndesite => 64, + Item::GrassBlock => 64, + Item::Dirt => 64, + Item::CoarseDirt => 64, + Item::Podzol => 64, + Item::CrimsonNylium => 64, + Item::WarpedNylium => 64, + Item::Cobblestone => 64, + Item::OakPlanks => 64, + Item::SprucePlanks => 64, + Item::BirchPlanks => 64, + Item::JunglePlanks => 64, + Item::AcaciaPlanks => 64, + Item::DarkOakPlanks => 64, + Item::CrimsonPlanks => 64, + Item::WarpedPlanks => 64, + Item::OakSapling => 64, + Item::SpruceSapling => 64, + Item::BirchSapling => 64, + Item::JungleSapling => 64, + Item::AcaciaSapling => 64, + Item::DarkOakSapling => 64, + Item::Bedrock => 64, + Item::Sand => 64, + Item::RedSand => 64, + Item::Gravel => 64, + Item::GoldOre => 64, + Item::IronOre => 64, + Item::CoalOre => 64, + Item::NetherGoldOre => 64, + Item::OakLog => 64, + Item::SpruceLog => 64, + Item::BirchLog => 64, + Item::JungleLog => 64, + Item::AcaciaLog => 64, + Item::DarkOakLog => 64, + Item::CrimsonStem => 64, + Item::WarpedStem => 64, + Item::StrippedOakLog => 64, + Item::StrippedSpruceLog => 64, + Item::StrippedBirchLog => 64, + Item::StrippedJungleLog => 64, + Item::StrippedAcaciaLog => 64, + Item::StrippedDarkOakLog => 64, + Item::StrippedCrimsonStem => 64, + Item::StrippedWarpedStem => 64, + Item::StrippedOakWood => 64, + Item::StrippedSpruceWood => 64, + Item::StrippedBirchWood => 64, + Item::StrippedJungleWood => 64, + Item::StrippedAcaciaWood => 64, + Item::StrippedDarkOakWood => 64, + Item::StrippedCrimsonHyphae => 64, + Item::StrippedWarpedHyphae => 64, + Item::OakWood => 64, + Item::SpruceWood => 64, + Item::BirchWood => 64, + Item::JungleWood => 64, + Item::AcaciaWood => 64, + Item::DarkOakWood => 64, + Item::CrimsonHyphae => 64, + Item::WarpedHyphae => 64, + Item::OakLeaves => 64, + Item::SpruceLeaves => 64, + Item::BirchLeaves => 64, + Item::JungleLeaves => 64, + Item::AcaciaLeaves => 64, + Item::DarkOakLeaves => 64, + Item::Sponge => 64, + Item::WetSponge => 64, + Item::Glass => 64, + Item::LapisOre => 64, + Item::LapisBlock => 64, + Item::Dispenser => 64, + Item::Sandstone => 64, + Item::ChiseledSandstone => 64, + Item::CutSandstone => 64, + Item::NoteBlock => 64, + Item::PoweredRail => 64, + Item::DetectorRail => 64, + Item::StickyPiston => 64, + Item::Cobweb => 64, + Item::Grass => 64, + Item::Fern => 64, + Item::DeadBush => 64, + Item::Seagrass => 64, + Item::SeaPickle => 64, + Item::Piston => 64, + Item::WhiteWool => 64, + Item::OrangeWool => 64, + Item::MagentaWool => 64, + Item::LightBlueWool => 64, + Item::YellowWool => 64, + Item::LimeWool => 64, + Item::PinkWool => 64, + Item::GrayWool => 64, + Item::LightGrayWool => 64, + Item::CyanWool => 64, + Item::PurpleWool => 64, + Item::BlueWool => 64, + Item::BrownWool => 64, + Item::GreenWool => 64, + Item::RedWool => 64, + Item::BlackWool => 64, + Item::Dandelion => 64, + Item::Poppy => 64, + Item::BlueOrchid => 64, + Item::Allium => 64, + Item::AzureBluet => 64, + Item::RedTulip => 64, + Item::OrangeTulip => 64, + Item::WhiteTulip => 64, + Item::PinkTulip => 64, + Item::OxeyeDaisy => 64, + Item::Cornflower => 64, + Item::LilyOfTheValley => 64, + Item::WitherRose => 64, + Item::BrownMushroom => 64, + Item::RedMushroom => 64, + Item::CrimsonFungus => 64, + Item::WarpedFungus => 64, + Item::CrimsonRoots => 64, + Item::WarpedRoots => 64, + Item::NetherSprouts => 64, + Item::WeepingVines => 64, + Item::TwistingVines => 64, + Item::SugarCane => 64, + Item::Kelp => 64, + Item::Bamboo => 64, + Item::GoldBlock => 64, + Item::IronBlock => 64, + Item::OakSlab => 64, + Item::SpruceSlab => 64, + Item::BirchSlab => 64, + Item::JungleSlab => 64, + Item::AcaciaSlab => 64, + Item::DarkOakSlab => 64, + Item::CrimsonSlab => 64, + Item::WarpedSlab => 64, + Item::StoneSlab => 64, + Item::SmoothStoneSlab => 64, + Item::SandstoneSlab => 64, + Item::CutSandstoneSlab => 64, + Item::PetrifiedOakSlab => 64, + Item::CobblestoneSlab => 64, + Item::BrickSlab => 64, + Item::StoneBrickSlab => 64, + Item::NetherBrickSlab => 64, + Item::QuartzSlab => 64, + Item::RedSandstoneSlab => 64, + Item::CutRedSandstoneSlab => 64, + Item::PurpurSlab => 64, + Item::PrismarineSlab => 64, + Item::PrismarineBrickSlab => 64, + Item::DarkPrismarineSlab => 64, + Item::SmoothQuartz => 64, + Item::SmoothRedSandstone => 64, + Item::SmoothSandstone => 64, + Item::SmoothStone => 64, + Item::Bricks => 64, + Item::Tnt => 64, + Item::Bookshelf => 64, + Item::MossyCobblestone => 64, + Item::Obsidian => 64, + Item::Torch => 64, + Item::EndRod => 64, + Item::ChorusPlant => 64, + Item::ChorusFlower => 64, + Item::PurpurBlock => 64, + Item::PurpurPillar => 64, + Item::PurpurStairs => 64, + Item::Spawner => 64, + Item::OakStairs => 64, + Item::Chest => 64, + Item::DiamondOre => 64, + Item::DiamondBlock => 64, + Item::CraftingTable => 64, + Item::Farmland => 64, + Item::Furnace => 64, + Item::Ladder => 64, + Item::Rail => 64, + Item::CobblestoneStairs => 64, + Item::Lever => 64, + Item::StonePressurePlate => 64, + Item::OakPressurePlate => 64, + Item::SprucePressurePlate => 64, + Item::BirchPressurePlate => 64, + Item::JunglePressurePlate => 64, + Item::AcaciaPressurePlate => 64, + Item::DarkOakPressurePlate => 64, + Item::CrimsonPressurePlate => 64, + Item::WarpedPressurePlate => 64, + Item::PolishedBlackstonePressurePlate => 64, + Item::RedstoneOre => 64, + Item::RedstoneTorch => 64, + Item::Snow => 64, + Item::Ice => 64, + Item::SnowBlock => 64, + Item::Cactus => 64, + Item::Clay => 64, + Item::Jukebox => 64, + Item::OakFence => 64, + Item::SpruceFence => 64, + Item::BirchFence => 64, + Item::JungleFence => 64, + Item::AcaciaFence => 64, + Item::DarkOakFence => 64, + Item::CrimsonFence => 64, + Item::WarpedFence => 64, + Item::Pumpkin => 64, + Item::CarvedPumpkin => 64, + Item::Netherrack => 64, + Item::SoulSand => 64, + Item::SoulSoil => 64, + Item::Basalt => 64, + Item::PolishedBasalt => 64, + Item::SoulTorch => 64, + Item::Glowstone => 64, + Item::JackOLantern => 64, + Item::OakTrapdoor => 64, + Item::SpruceTrapdoor => 64, + Item::BirchTrapdoor => 64, + Item::JungleTrapdoor => 64, + Item::AcaciaTrapdoor => 64, + Item::DarkOakTrapdoor => 64, + Item::CrimsonTrapdoor => 64, + Item::WarpedTrapdoor => 64, + Item::InfestedStone => 64, + Item::InfestedCobblestone => 64, + Item::InfestedStoneBricks => 64, + Item::InfestedMossyStoneBricks => 64, + Item::InfestedCrackedStoneBricks => 64, + Item::InfestedChiseledStoneBricks => 64, + Item::StoneBricks => 64, + Item::MossyStoneBricks => 64, + Item::CrackedStoneBricks => 64, + Item::ChiseledStoneBricks => 64, + Item::BrownMushroomBlock => 64, + Item::RedMushroomBlock => 64, + Item::MushroomStem => 64, + Item::IronBars => 64, + Item::Chain => 64, + Item::GlassPane => 64, + Item::Melon => 64, + Item::Vine => 64, + Item::OakFenceGate => 64, + Item::SpruceFenceGate => 64, + Item::BirchFenceGate => 64, + Item::JungleFenceGate => 64, + Item::AcaciaFenceGate => 64, + Item::DarkOakFenceGate => 64, + Item::CrimsonFenceGate => 64, + Item::WarpedFenceGate => 64, + Item::BrickStairs => 64, + Item::StoneBrickStairs => 64, + Item::Mycelium => 64, + Item::LilyPad => 64, + Item::NetherBricks => 64, + Item::CrackedNetherBricks => 64, + Item::ChiseledNetherBricks => 64, + Item::NetherBrickFence => 64, + Item::NetherBrickStairs => 64, + Item::EnchantingTable => 64, + Item::EndPortalFrame => 64, + Item::EndStone => 64, + Item::EndStoneBricks => 64, + Item::DragonEgg => 64, + Item::RedstoneLamp => 64, + Item::SandstoneStairs => 64, + Item::EmeraldOre => 64, + Item::EnderChest => 64, + Item::TripwireHook => 64, + Item::EmeraldBlock => 64, + Item::SpruceStairs => 64, + Item::BirchStairs => 64, + Item::JungleStairs => 64, + Item::CrimsonStairs => 64, + Item::WarpedStairs => 64, + Item::CommandBlock => 64, + Item::Beacon => 64, + Item::CobblestoneWall => 64, + Item::MossyCobblestoneWall => 64, + Item::BrickWall => 64, + Item::PrismarineWall => 64, + Item::RedSandstoneWall => 64, + Item::MossyStoneBrickWall => 64, + Item::GraniteWall => 64, + Item::StoneBrickWall => 64, + Item::NetherBrickWall => 64, + Item::AndesiteWall => 64, + Item::RedNetherBrickWall => 64, + Item::SandstoneWall => 64, + Item::EndStoneBrickWall => 64, + Item::DioriteWall => 64, + Item::BlackstoneWall => 64, + Item::PolishedBlackstoneWall => 64, + Item::PolishedBlackstoneBrickWall => 64, + Item::StoneButton => 64, + Item::OakButton => 64, + Item::SpruceButton => 64, + Item::BirchButton => 64, + Item::JungleButton => 64, + Item::AcaciaButton => 64, + Item::DarkOakButton => 64, + Item::CrimsonButton => 64, + Item::WarpedButton => 64, + Item::PolishedBlackstoneButton => 64, + Item::Anvil => 64, + Item::ChippedAnvil => 64, + Item::DamagedAnvil => 64, + Item::TrappedChest => 64, + Item::LightWeightedPressurePlate => 64, + Item::HeavyWeightedPressurePlate => 64, + Item::DaylightDetector => 64, + Item::RedstoneBlock => 64, + Item::NetherQuartzOre => 64, + Item::Hopper => 64, + Item::ChiseledQuartzBlock => 64, + Item::QuartzBlock => 64, + Item::QuartzBricks => 64, + Item::QuartzPillar => 64, + Item::QuartzStairs => 64, + Item::ActivatorRail => 64, + Item::Dropper => 64, + Item::WhiteTerracotta => 64, + Item::OrangeTerracotta => 64, + Item::MagentaTerracotta => 64, + Item::LightBlueTerracotta => 64, + Item::YellowTerracotta => 64, + Item::LimeTerracotta => 64, + Item::PinkTerracotta => 64, + Item::GrayTerracotta => 64, + Item::LightGrayTerracotta => 64, + Item::CyanTerracotta => 64, + Item::PurpleTerracotta => 64, + Item::BlueTerracotta => 64, + Item::BrownTerracotta => 64, + Item::GreenTerracotta => 64, + Item::RedTerracotta => 64, + Item::BlackTerracotta => 64, + Item::Barrier => 64, + Item::IronTrapdoor => 64, + Item::HayBlock => 64, + Item::WhiteCarpet => 64, + Item::OrangeCarpet => 64, + Item::MagentaCarpet => 64, + Item::LightBlueCarpet => 64, + Item::YellowCarpet => 64, + Item::LimeCarpet => 64, + Item::PinkCarpet => 64, + Item::GrayCarpet => 64, + Item::LightGrayCarpet => 64, + Item::CyanCarpet => 64, + Item::PurpleCarpet => 64, + Item::BlueCarpet => 64, + Item::BrownCarpet => 64, + Item::GreenCarpet => 64, + Item::RedCarpet => 64, + Item::BlackCarpet => 64, + Item::Terracotta => 64, + Item::CoalBlock => 64, + Item::PackedIce => 64, + Item::AcaciaStairs => 64, + Item::DarkOakStairs => 64, + Item::SlimeBlock => 64, + Item::GrassPath => 64, + Item::Sunflower => 64, + Item::Lilac => 64, + Item::RoseBush => 64, + Item::Peony => 64, + Item::TallGrass => 64, + Item::LargeFern => 64, + Item::WhiteStainedGlass => 64, + Item::OrangeStainedGlass => 64, + Item::MagentaStainedGlass => 64, + Item::LightBlueStainedGlass => 64, + Item::YellowStainedGlass => 64, + Item::LimeStainedGlass => 64, + Item::PinkStainedGlass => 64, + Item::GrayStainedGlass => 64, + Item::LightGrayStainedGlass => 64, + Item::CyanStainedGlass => 64, + Item::PurpleStainedGlass => 64, + Item::BlueStainedGlass => 64, + Item::BrownStainedGlass => 64, + Item::GreenStainedGlass => 64, + Item::RedStainedGlass => 64, + Item::BlackStainedGlass => 64, + Item::WhiteStainedGlassPane => 64, + Item::OrangeStainedGlassPane => 64, + Item::MagentaStainedGlassPane => 64, + Item::LightBlueStainedGlassPane => 64, + Item::YellowStainedGlassPane => 64, + Item::LimeStainedGlassPane => 64, + Item::PinkStainedGlassPane => 64, + Item::GrayStainedGlassPane => 64, + Item::LightGrayStainedGlassPane => 64, + Item::CyanStainedGlassPane => 64, + Item::PurpleStainedGlassPane => 64, + Item::BlueStainedGlassPane => 64, + Item::BrownStainedGlassPane => 64, + Item::GreenStainedGlassPane => 64, + Item::RedStainedGlassPane => 64, + Item::BlackStainedGlassPane => 64, + Item::Prismarine => 64, + Item::PrismarineBricks => 64, + Item::DarkPrismarine => 64, + Item::PrismarineStairs => 64, + Item::PrismarineBrickStairs => 64, + Item::DarkPrismarineStairs => 64, + Item::SeaLantern => 64, + Item::RedSandstone => 64, + Item::ChiseledRedSandstone => 64, + Item::CutRedSandstone => 64, + Item::RedSandstoneStairs => 64, + Item::RepeatingCommandBlock => 64, + Item::ChainCommandBlock => 64, + Item::MagmaBlock => 64, + Item::NetherWartBlock => 64, + Item::WarpedWartBlock => 64, + Item::RedNetherBricks => 64, + Item::BoneBlock => 64, + Item::StructureVoid => 64, + Item::Observer => 64, + Item::ShulkerBox => 1, + Item::WhiteShulkerBox => 1, + Item::OrangeShulkerBox => 1, + Item::MagentaShulkerBox => 1, + Item::LightBlueShulkerBox => 1, + Item::YellowShulkerBox => 1, + Item::LimeShulkerBox => 1, + Item::PinkShulkerBox => 1, + Item::GrayShulkerBox => 1, + Item::LightGrayShulkerBox => 1, + Item::CyanShulkerBox => 1, + Item::PurpleShulkerBox => 1, + Item::BlueShulkerBox => 1, + Item::BrownShulkerBox => 1, + Item::GreenShulkerBox => 1, + Item::RedShulkerBox => 1, + Item::BlackShulkerBox => 1, + Item::WhiteGlazedTerracotta => 64, + Item::OrangeGlazedTerracotta => 64, + Item::MagentaGlazedTerracotta => 64, + Item::LightBlueGlazedTerracotta => 64, + Item::YellowGlazedTerracotta => 64, + Item::LimeGlazedTerracotta => 64, + Item::PinkGlazedTerracotta => 64, + Item::GrayGlazedTerracotta => 64, + Item::LightGrayGlazedTerracotta => 64, + Item::CyanGlazedTerracotta => 64, + Item::PurpleGlazedTerracotta => 64, + Item::BlueGlazedTerracotta => 64, + Item::BrownGlazedTerracotta => 64, + Item::GreenGlazedTerracotta => 64, + Item::RedGlazedTerracotta => 64, + Item::BlackGlazedTerracotta => 64, + Item::WhiteConcrete => 64, + Item::OrangeConcrete => 64, + Item::MagentaConcrete => 64, + Item::LightBlueConcrete => 64, + Item::YellowConcrete => 64, + Item::LimeConcrete => 64, + Item::PinkConcrete => 64, + Item::GrayConcrete => 64, + Item::LightGrayConcrete => 64, + Item::CyanConcrete => 64, + Item::PurpleConcrete => 64, + Item::BlueConcrete => 64, + Item::BrownConcrete => 64, + Item::GreenConcrete => 64, + Item::RedConcrete => 64, + Item::BlackConcrete => 64, + Item::WhiteConcretePowder => 64, + Item::OrangeConcretePowder => 64, + Item::MagentaConcretePowder => 64, + Item::LightBlueConcretePowder => 64, + Item::YellowConcretePowder => 64, + Item::LimeConcretePowder => 64, + Item::PinkConcretePowder => 64, + Item::GrayConcretePowder => 64, + Item::LightGrayConcretePowder => 64, + Item::CyanConcretePowder => 64, + Item::PurpleConcretePowder => 64, + Item::BlueConcretePowder => 64, + Item::BrownConcretePowder => 64, + Item::GreenConcretePowder => 64, + Item::RedConcretePowder => 64, + Item::BlackConcretePowder => 64, + Item::TurtleEgg => 64, + Item::DeadTubeCoralBlock => 64, + Item::DeadBrainCoralBlock => 64, + Item::DeadBubbleCoralBlock => 64, + Item::DeadFireCoralBlock => 64, + Item::DeadHornCoralBlock => 64, + Item::TubeCoralBlock => 64, + Item::BrainCoralBlock => 64, + Item::BubbleCoralBlock => 64, + Item::FireCoralBlock => 64, + Item::HornCoralBlock => 64, + Item::TubeCoral => 64, + Item::BrainCoral => 64, + Item::BubbleCoral => 64, + Item::FireCoral => 64, + Item::HornCoral => 64, + Item::DeadBrainCoral => 64, + Item::DeadBubbleCoral => 64, + Item::DeadFireCoral => 64, + Item::DeadHornCoral => 64, + Item::DeadTubeCoral => 64, + Item::TubeCoralFan => 64, + Item::BrainCoralFan => 64, + Item::BubbleCoralFan => 64, + Item::FireCoralFan => 64, + Item::HornCoralFan => 64, + Item::DeadTubeCoralFan => 64, + Item::DeadBrainCoralFan => 64, + Item::DeadBubbleCoralFan => 64, + Item::DeadFireCoralFan => 64, + Item::DeadHornCoralFan => 64, + Item::BlueIce => 64, + Item::Conduit => 64, + Item::PolishedGraniteStairs => 64, + Item::SmoothRedSandstoneStairs => 64, + Item::MossyStoneBrickStairs => 64, + Item::PolishedDioriteStairs => 64, + Item::MossyCobblestoneStairs => 64, + Item::EndStoneBrickStairs => 64, + Item::StoneStairs => 64, + Item::SmoothSandstoneStairs => 64, + Item::SmoothQuartzStairs => 64, + Item::GraniteStairs => 64, + Item::AndesiteStairs => 64, + Item::RedNetherBrickStairs => 64, + Item::PolishedAndesiteStairs => 64, + Item::DioriteStairs => 64, + Item::PolishedGraniteSlab => 64, + Item::SmoothRedSandstoneSlab => 64, + Item::MossyStoneBrickSlab => 64, + Item::PolishedDioriteSlab => 64, + Item::MossyCobblestoneSlab => 64, + Item::EndStoneBrickSlab => 64, + Item::SmoothSandstoneSlab => 64, + Item::SmoothQuartzSlab => 64, + Item::GraniteSlab => 64, + Item::AndesiteSlab => 64, + Item::RedNetherBrickSlab => 64, + Item::PolishedAndesiteSlab => 64, + Item::DioriteSlab => 64, + Item::Scaffolding => 64, + Item::IronDoor => 64, + Item::OakDoor => 64, + Item::SpruceDoor => 64, + Item::BirchDoor => 64, + Item::JungleDoor => 64, + Item::AcaciaDoor => 64, + Item::DarkOakDoor => 64, + Item::CrimsonDoor => 64, + Item::WarpedDoor => 64, + Item::Repeater => 64, + Item::Comparator => 64, + Item::StructureBlock => 64, + Item::Jigsaw => 64, + Item::TurtleHelmet => 1, + Item::Scute => 64, + Item::FlintAndSteel => 1, + Item::Apple => 64, + Item::Bow => 1, + Item::Arrow => 64, + Item::Coal => 64, + Item::Charcoal => 64, + Item::Diamond => 64, + Item::IronIngot => 64, + Item::GoldIngot => 64, + Item::NetheriteIngot => 64, + Item::NetheriteScrap => 64, + Item::WoodenSword => 1, + Item::WoodenShovel => 1, + Item::WoodenPickaxe => 1, + Item::WoodenAxe => 1, + Item::WoodenHoe => 1, + Item::StoneSword => 1, + Item::StoneShovel => 1, + Item::StonePickaxe => 1, + Item::StoneAxe => 1, + Item::StoneHoe => 1, + Item::GoldenSword => 1, + Item::GoldenShovel => 1, + Item::GoldenPickaxe => 1, + Item::GoldenAxe => 1, + Item::GoldenHoe => 1, + Item::IronSword => 1, + Item::IronShovel => 1, + Item::IronPickaxe => 1, + Item::IronAxe => 1, + Item::IronHoe => 1, + Item::DiamondSword => 1, + Item::DiamondShovel => 1, + Item::DiamondPickaxe => 1, + Item::DiamondAxe => 1, + Item::DiamondHoe => 1, + Item::NetheriteSword => 1, + Item::NetheriteShovel => 1, + Item::NetheritePickaxe => 1, + Item::NetheriteAxe => 1, + Item::NetheriteHoe => 1, + Item::Stick => 64, + Item::Bowl => 64, + Item::MushroomStew => 1, + Item::String => 64, + Item::Feather => 64, + Item::Gunpowder => 64, + Item::WheatSeeds => 64, + Item::Wheat => 64, + Item::Bread => 64, + Item::LeatherHelmet => 1, + Item::LeatherChestplate => 1, + Item::LeatherLeggings => 1, + Item::LeatherBoots => 1, + Item::ChainmailHelmet => 1, + Item::ChainmailChestplate => 1, + Item::ChainmailLeggings => 1, + Item::ChainmailBoots => 1, + Item::IronHelmet => 1, + Item::IronChestplate => 1, + Item::IronLeggings => 1, + Item::IronBoots => 1, + Item::DiamondHelmet => 1, + Item::DiamondChestplate => 1, + Item::DiamondLeggings => 1, + Item::DiamondBoots => 1, + Item::GoldenHelmet => 1, + Item::GoldenChestplate => 1, + Item::GoldenLeggings => 1, + Item::GoldenBoots => 1, + Item::NetheriteHelmet => 1, + Item::NetheriteChestplate => 1, + Item::NetheriteLeggings => 1, + Item::NetheriteBoots => 1, + Item::Flint => 64, + Item::Porkchop => 64, + Item::CookedPorkchop => 64, + Item::Painting => 64, + Item::GoldenApple => 64, + Item::EnchantedGoldenApple => 64, + Item::OakSign => 16, + Item::SpruceSign => 16, + Item::BirchSign => 16, + Item::JungleSign => 16, + Item::AcaciaSign => 16, + Item::DarkOakSign => 16, + Item::CrimsonSign => 16, + Item::WarpedSign => 16, + Item::Bucket => 16, + Item::WaterBucket => 1, + Item::LavaBucket => 1, + Item::Minecart => 1, + Item::Saddle => 1, + Item::Redstone => 64, + Item::Snowball => 16, + Item::OakBoat => 1, + Item::Leather => 64, + Item::MilkBucket => 1, + Item::PufferfishBucket => 1, + Item::SalmonBucket => 1, + Item::CodBucket => 1, + Item::TropicalFishBucket => 1, + Item::Brick => 64, + Item::ClayBall => 64, + Item::DriedKelpBlock => 64, + Item::Paper => 64, + Item::Book => 64, + Item::SlimeBall => 64, + Item::ChestMinecart => 1, + Item::FurnaceMinecart => 1, + Item::Egg => 16, + Item::Compass => 64, + Item::FishingRod => 1, + Item::Clock => 64, + Item::GlowstoneDust => 64, + Item::Cod => 64, + Item::Salmon => 64, + Item::TropicalFish => 64, + Item::Pufferfish => 64, + Item::CookedCod => 64, + Item::CookedSalmon => 64, + Item::InkSac => 64, + Item::CocoaBeans => 64, + Item::LapisLazuli => 64, + Item::WhiteDye => 64, + Item::OrangeDye => 64, + Item::MagentaDye => 64, + Item::LightBlueDye => 64, + Item::YellowDye => 64, + Item::LimeDye => 64, + Item::PinkDye => 64, + Item::GrayDye => 64, + Item::LightGrayDye => 64, + Item::CyanDye => 64, + Item::PurpleDye => 64, + Item::BlueDye => 64, + Item::BrownDye => 64, + Item::GreenDye => 64, + Item::RedDye => 64, + Item::BlackDye => 64, + Item::BoneMeal => 64, + Item::Bone => 64, + Item::Sugar => 64, + Item::Cake => 1, + Item::WhiteBed => 1, + Item::OrangeBed => 1, + Item::MagentaBed => 1, + Item::LightBlueBed => 1, + Item::YellowBed => 1, + Item::LimeBed => 1, + Item::PinkBed => 1, + Item::GrayBed => 1, + Item::LightGrayBed => 1, + Item::CyanBed => 1, + Item::PurpleBed => 1, + Item::BlueBed => 1, + Item::BrownBed => 1, + Item::GreenBed => 1, + Item::RedBed => 1, + Item::BlackBed => 1, + Item::Cookie => 64, + Item::FilledMap => 64, + Item::Shears => 1, + Item::MelonSlice => 64, + Item::DriedKelp => 64, + Item::PumpkinSeeds => 64, + Item::MelonSeeds => 64, + Item::Beef => 64, + Item::CookedBeef => 64, + Item::Chicken => 64, + Item::CookedChicken => 64, + Item::RottenFlesh => 64, + Item::EnderPearl => 16, + Item::BlazeRod => 64, + Item::GhastTear => 64, + Item::GoldNugget => 64, + Item::NetherWart => 64, + Item::Potion => 1, + Item::GlassBottle => 64, + Item::SpiderEye => 64, + Item::FermentedSpiderEye => 64, + Item::BlazePowder => 64, + Item::MagmaCream => 64, + Item::BrewingStand => 64, + Item::Cauldron => 64, + Item::EnderEye => 64, + Item::GlisteringMelonSlice => 64, + Item::BatSpawnEgg => 64, + Item::BeeSpawnEgg => 64, + Item::BlazeSpawnEgg => 64, + Item::CatSpawnEgg => 64, + Item::CaveSpiderSpawnEgg => 64, + Item::ChickenSpawnEgg => 64, + Item::CodSpawnEgg => 64, + Item::CowSpawnEgg => 64, + Item::CreeperSpawnEgg => 64, + Item::DolphinSpawnEgg => 64, + Item::DonkeySpawnEgg => 64, + Item::DrownedSpawnEgg => 64, + Item::ElderGuardianSpawnEgg => 64, + Item::EndermanSpawnEgg => 64, + Item::EndermiteSpawnEgg => 64, + Item::EvokerSpawnEgg => 64, + Item::FoxSpawnEgg => 64, + Item::GhastSpawnEgg => 64, + Item::GuardianSpawnEgg => 64, + Item::HoglinSpawnEgg => 64, + Item::HorseSpawnEgg => 64, + Item::HuskSpawnEgg => 64, + Item::LlamaSpawnEgg => 64, + Item::MagmaCubeSpawnEgg => 64, + Item::MooshroomSpawnEgg => 64, + Item::MuleSpawnEgg => 64, + Item::OcelotSpawnEgg => 64, + Item::PandaSpawnEgg => 64, + Item::ParrotSpawnEgg => 64, + Item::PhantomSpawnEgg => 64, + Item::PigSpawnEgg => 64, + Item::PiglinSpawnEgg => 64, + Item::PiglinBruteSpawnEgg => 64, + Item::PillagerSpawnEgg => 64, + Item::PolarBearSpawnEgg => 64, + Item::PufferfishSpawnEgg => 64, + Item::RabbitSpawnEgg => 64, + Item::RavagerSpawnEgg => 64, + Item::SalmonSpawnEgg => 64, + Item::SheepSpawnEgg => 64, + Item::ShulkerSpawnEgg => 64, + Item::SilverfishSpawnEgg => 64, + Item::SkeletonSpawnEgg => 64, + Item::SkeletonHorseSpawnEgg => 64, + Item::SlimeSpawnEgg => 64, + Item::SpiderSpawnEgg => 64, + Item::SquidSpawnEgg => 64, + Item::StraySpawnEgg => 64, + Item::StriderSpawnEgg => 64, + Item::TraderLlamaSpawnEgg => 64, + Item::TropicalFishSpawnEgg => 64, + Item::TurtleSpawnEgg => 64, + Item::VexSpawnEgg => 64, + Item::VillagerSpawnEgg => 64, + Item::VindicatorSpawnEgg => 64, + Item::WanderingTraderSpawnEgg => 64, + Item::WitchSpawnEgg => 64, + Item::WitherSkeletonSpawnEgg => 64, + Item::WolfSpawnEgg => 64, + Item::ZoglinSpawnEgg => 64, + Item::ZombieSpawnEgg => 64, + Item::ZombieHorseSpawnEgg => 64, + Item::ZombieVillagerSpawnEgg => 64, + Item::ZombifiedPiglinSpawnEgg => 64, + Item::ExperienceBottle => 64, + Item::FireCharge => 64, + Item::WritableBook => 1, + Item::WrittenBook => 16, + Item::Emerald => 64, + Item::ItemFrame => 64, + Item::FlowerPot => 64, + Item::Carrot => 64, + Item::Potato => 64, + Item::BakedPotato => 64, + Item::PoisonousPotato => 64, + Item::Map => 64, + Item::GoldenCarrot => 64, + Item::SkeletonSkull => 64, + Item::WitherSkeletonSkull => 64, + Item::PlayerHead => 64, + Item::ZombieHead => 64, + Item::CreeperHead => 64, + Item::DragonHead => 64, + Item::CarrotOnAStick => 1, + Item::WarpedFungusOnAStick => 64, + Item::NetherStar => 64, + Item::PumpkinPie => 64, + Item::FireworkRocket => 64, + Item::FireworkStar => 64, + Item::EnchantedBook => 1, + Item::NetherBrick => 64, + Item::Quartz => 64, + Item::TntMinecart => 1, + Item::HopperMinecart => 1, + Item::PrismarineShard => 64, + Item::PrismarineCrystals => 64, + Item::Rabbit => 64, + Item::CookedRabbit => 64, + Item::RabbitStew => 1, + Item::RabbitFoot => 64, + Item::RabbitHide => 64, + Item::ArmorStand => 16, + Item::IronHorseArmor => 1, + Item::GoldenHorseArmor => 1, + Item::DiamondHorseArmor => 1, + Item::LeatherHorseArmor => 1, + Item::Lead => 64, + Item::NameTag => 64, + Item::CommandBlockMinecart => 1, + Item::Mutton => 64, + Item::CookedMutton => 64, + Item::WhiteBanner => 16, + Item::OrangeBanner => 16, + Item::MagentaBanner => 16, + Item::LightBlueBanner => 16, + Item::YellowBanner => 16, + Item::LimeBanner => 16, + Item::PinkBanner => 16, + Item::GrayBanner => 16, + Item::LightGrayBanner => 16, + Item::CyanBanner => 16, + Item::PurpleBanner => 16, + Item::BlueBanner => 16, + Item::BrownBanner => 16, + Item::GreenBanner => 16, + Item::RedBanner => 16, + Item::BlackBanner => 16, + Item::EndCrystal => 64, + Item::ChorusFruit => 64, + Item::PoppedChorusFruit => 64, + Item::Beetroot => 64, + Item::BeetrootSeeds => 64, + Item::BeetrootSoup => 1, + Item::DragonBreath => 64, + Item::SplashPotion => 1, + Item::SpectralArrow => 64, + Item::TippedArrow => 64, + Item::LingeringPotion => 1, + Item::Shield => 1, + Item::Elytra => 1, + Item::SpruceBoat => 1, + Item::BirchBoat => 1, + Item::JungleBoat => 1, + Item::AcaciaBoat => 1, + Item::DarkOakBoat => 1, + Item::TotemOfUndying => 1, + Item::ShulkerShell => 64, + Item::IronNugget => 64, + Item::KnowledgeBook => 1, + Item::DebugStick => 1, + Item::MusicDisc13 => 1, + Item::MusicDiscCat => 1, + Item::MusicDiscBlocks => 1, + Item::MusicDiscChirp => 1, + Item::MusicDiscFar => 1, + Item::MusicDiscMall => 1, + Item::MusicDiscMellohi => 1, + Item::MusicDiscStal => 1, + Item::MusicDiscStrad => 1, + Item::MusicDiscWard => 1, + Item::MusicDisc11 => 1, + Item::MusicDiscWait => 1, + Item::MusicDiscPigstep => 1, + Item::Trident => 1, + Item::PhantomMembrane => 64, + Item::NautilusShell => 64, + Item::HeartOfTheSea => 64, + Item::Crossbow => 1, + Item::SuspiciousStew => 1, + Item::Loom => 64, + Item::FlowerBannerPattern => 1, + Item::CreeperBannerPattern => 1, + Item::SkullBannerPattern => 1, + Item::MojangBannerPattern => 1, + Item::GlobeBannerPattern => 1, + Item::PiglinBannerPattern => 1, + Item::Composter => 64, + Item::Barrel => 64, + Item::Smoker => 64, + Item::BlastFurnace => 64, + Item::CartographyTable => 64, + Item::FletchingTable => 64, + Item::Grindstone => 64, + Item::Lectern => 64, + Item::SmithingTable => 64, + Item::Stonecutter => 64, + Item::Bell => 64, + Item::Lantern => 64, + Item::SoulLantern => 64, + Item::SweetBerries => 64, + Item::Campfire => 64, + Item::SoulCampfire => 64, + Item::Shroomlight => 64, + Item::Honeycomb => 64, + Item::BeeNest => 64, + Item::Beehive => 64, + Item::HoneyBottle => 16, + Item::HoneyBlock => 64, + Item::HoneycombBlock => 64, + Item::Lodestone => 64, + Item::NetheriteBlock => 64, + Item::AncientDebris => 64, + Item::Target => 64, + Item::CryingObsidian => 64, + Item::Blackstone => 64, + Item::BlackstoneSlab => 64, + Item::BlackstoneStairs => 64, + Item::GildedBlackstone => 64, + Item::PolishedBlackstone => 64, + Item::PolishedBlackstoneSlab => 64, + Item::PolishedBlackstoneStairs => 64, + Item::ChiseledPolishedBlackstone => 64, + Item::PolishedBlackstoneBricks => 64, + Item::PolishedBlackstoneBrickSlab => 64, + Item::PolishedBlackstoneBrickStairs => 64, + Item::CrackedPolishedBlackstoneBricks => 64, + Item::RespawnAnchor => 64, + } + } +} +#[allow(warnings)] +#[allow(clippy::all)] +impl Item { + /// Returns the `durability` property of this `Item`. + pub fn durability(&self) -> Option<u32> { + match self { + Item::Air => None, + Item::Stone => None, + Item::Granite => None, + Item::PolishedGranite => None, + Item::Diorite => None, + Item::PolishedDiorite => None, + Item::Andesite => None, + Item::PolishedAndesite => None, + Item::GrassBlock => None, + Item::Dirt => None, + Item::CoarseDirt => None, + Item::Podzol => None, + Item::CrimsonNylium => None, + Item::WarpedNylium => None, + Item::Cobblestone => None, + Item::OakPlanks => None, + Item::SprucePlanks => None, + Item::BirchPlanks => None, + Item::JunglePlanks => None, + Item::AcaciaPlanks => None, + Item::DarkOakPlanks => None, + Item::CrimsonPlanks => None, + Item::WarpedPlanks => None, + Item::OakSapling => None, + Item::SpruceSapling => None, + Item::BirchSapling => None, + Item::JungleSapling => None, + Item::AcaciaSapling => None, + Item::DarkOakSapling => None, + Item::Bedrock => None, + Item::Sand => None, + Item::RedSand => None, + Item::Gravel => None, + Item::GoldOre => None, + Item::IronOre => None, + Item::CoalOre => None, + Item::NetherGoldOre => None, + Item::OakLog => None, + Item::SpruceLog => None, + Item::BirchLog => None, + Item::JungleLog => None, + Item::AcaciaLog => None, + Item::DarkOakLog => None, + Item::CrimsonStem => None, + Item::WarpedStem => None, + Item::StrippedOakLog => None, + Item::StrippedSpruceLog => None, + Item::StrippedBirchLog => None, + Item::StrippedJungleLog => None, + Item::StrippedAcaciaLog => None, + Item::StrippedDarkOakLog => None, + Item::StrippedCrimsonStem => None, + Item::StrippedWarpedStem => None, + Item::StrippedOakWood => None, + Item::StrippedSpruceWood => None, + Item::StrippedBirchWood => None, + Item::StrippedJungleWood => None, + Item::StrippedAcaciaWood => None, + Item::StrippedDarkOakWood => None, + Item::StrippedCrimsonHyphae => None, + Item::StrippedWarpedHyphae => None, + Item::OakWood => None, + Item::SpruceWood => None, + Item::BirchWood => None, + Item::JungleWood => None, + Item::AcaciaWood => None, + Item::DarkOakWood => None, + Item::CrimsonHyphae => None, + Item::WarpedHyphae => None, + Item::OakLeaves => None, + Item::SpruceLeaves => None, + Item::BirchLeaves => None, + Item::JungleLeaves => None, + Item::AcaciaLeaves => None, + Item::DarkOakLeaves => None, + Item::Sponge => None, + Item::WetSponge => None, + Item::Glass => None, + Item::LapisOre => None, + Item::LapisBlock => None, + Item::Dispenser => None, + Item::Sandstone => None, + Item::ChiseledSandstone => None, + Item::CutSandstone => None, + Item::NoteBlock => None, + Item::PoweredRail => None, + Item::DetectorRail => None, + Item::StickyPiston => None, + Item::Cobweb => None, + Item::Grass => None, + Item::Fern => None, + Item::DeadBush => None, + Item::Seagrass => None, + Item::SeaPickle => None, + Item::Piston => None, + Item::WhiteWool => None, + Item::OrangeWool => None, + Item::MagentaWool => None, + Item::LightBlueWool => None, + Item::YellowWool => None, + Item::LimeWool => None, + Item::PinkWool => None, + Item::GrayWool => None, + Item::LightGrayWool => None, + Item::CyanWool => None, + Item::PurpleWool => None, + Item::BlueWool => None, + Item::BrownWool => None, + Item::GreenWool => None, + Item::RedWool => None, + Item::BlackWool => None, + Item::Dandelion => None, + Item::Poppy => None, + Item::BlueOrchid => None, + Item::Allium => None, + Item::AzureBluet => None, + Item::RedTulip => None, + Item::OrangeTulip => None, + Item::WhiteTulip => None, + Item::PinkTulip => None, + Item::OxeyeDaisy => None, + Item::Cornflower => None, + Item::LilyOfTheValley => None, + Item::WitherRose => None, + Item::BrownMushroom => None, + Item::RedMushroom => None, + Item::CrimsonFungus => None, + Item::WarpedFungus => None, + Item::CrimsonRoots => None, + Item::WarpedRoots => None, + Item::NetherSprouts => None, + Item::WeepingVines => None, + Item::TwistingVines => None, + Item::SugarCane => None, + Item::Kelp => None, + Item::Bamboo => None, + Item::GoldBlock => None, + Item::IronBlock => None, + Item::OakSlab => None, + Item::SpruceSlab => None, + Item::BirchSlab => None, + Item::JungleSlab => None, + Item::AcaciaSlab => None, + Item::DarkOakSlab => None, + Item::CrimsonSlab => None, + Item::WarpedSlab => None, + Item::StoneSlab => None, + Item::SmoothStoneSlab => None, + Item::SandstoneSlab => None, + Item::CutSandstoneSlab => None, + Item::PetrifiedOakSlab => None, + Item::CobblestoneSlab => None, + Item::BrickSlab => None, + Item::StoneBrickSlab => None, + Item::NetherBrickSlab => None, + Item::QuartzSlab => None, + Item::RedSandstoneSlab => None, + Item::CutRedSandstoneSlab => None, + Item::PurpurSlab => None, + Item::PrismarineSlab => None, + Item::PrismarineBrickSlab => None, + Item::DarkPrismarineSlab => None, + Item::SmoothQuartz => None, + Item::SmoothRedSandstone => None, + Item::SmoothSandstone => None, + Item::SmoothStone => None, + Item::Bricks => None, + Item::Tnt => None, + Item::Bookshelf => None, + Item::MossyCobblestone => None, + Item::Obsidian => None, + Item::Torch => None, + Item::EndRod => None, + Item::ChorusPlant => None, + Item::ChorusFlower => None, + Item::PurpurBlock => None, + Item::PurpurPillar => None, + Item::PurpurStairs => None, + Item::Spawner => None, + Item::OakStairs => None, + Item::Chest => None, + Item::DiamondOre => None, + Item::DiamondBlock => None, + Item::CraftingTable => None, + Item::Farmland => None, + Item::Furnace => None, + Item::Ladder => None, + Item::Rail => None, + Item::CobblestoneStairs => None, + Item::Lever => None, + Item::StonePressurePlate => None, + Item::OakPressurePlate => None, + Item::SprucePressurePlate => None, + Item::BirchPressurePlate => None, + Item::JunglePressurePlate => None, + Item::AcaciaPressurePlate => None, + Item::DarkOakPressurePlate => None, + Item::CrimsonPressurePlate => None, + Item::WarpedPressurePlate => None, + Item::PolishedBlackstonePressurePlate => None, + Item::RedstoneOre => None, + Item::RedstoneTorch => None, + Item::Snow => None, + Item::Ice => None, + Item::SnowBlock => None, + Item::Cactus => None, + Item::Clay => None, + Item::Jukebox => None, + Item::OakFence => None, + Item::SpruceFence => None, + Item::BirchFence => None, + Item::JungleFence => None, + Item::AcaciaFence => None, + Item::DarkOakFence => None, + Item::CrimsonFence => None, + Item::WarpedFence => None, + Item::Pumpkin => None, + Item::CarvedPumpkin => None, + Item::Netherrack => None, + Item::SoulSand => None, + Item::SoulSoil => None, + Item::Basalt => None, + Item::PolishedBasalt => None, + Item::SoulTorch => None, + Item::Glowstone => None, + Item::JackOLantern => None, + Item::OakTrapdoor => None, + Item::SpruceTrapdoor => None, + Item::BirchTrapdoor => None, + Item::JungleTrapdoor => None, + Item::AcaciaTrapdoor => None, + Item::DarkOakTrapdoor => None, + Item::CrimsonTrapdoor => None, + Item::WarpedTrapdoor => None, + Item::InfestedStone => None, + Item::InfestedCobblestone => None, + Item::InfestedStoneBricks => None, + Item::InfestedMossyStoneBricks => None, + Item::InfestedCrackedStoneBricks => None, + Item::InfestedChiseledStoneBricks => None, + Item::StoneBricks => None, + Item::MossyStoneBricks => None, + Item::CrackedStoneBricks => None, + Item::ChiseledStoneBricks => None, + Item::BrownMushroomBlock => None, + Item::RedMushroomBlock => None, + Item::MushroomStem => None, + Item::IronBars => None, + Item::Chain => None, + Item::GlassPane => None, + Item::Melon => None, + Item::Vine => None, + Item::OakFenceGate => None, + Item::SpruceFenceGate => None, + Item::BirchFenceGate => None, + Item::JungleFenceGate => None, + Item::AcaciaFenceGate => None, + Item::DarkOakFenceGate => None, + Item::CrimsonFenceGate => None, + Item::WarpedFenceGate => None, + Item::BrickStairs => None, + Item::StoneBrickStairs => None, + Item::Mycelium => None, + Item::LilyPad => None, + Item::NetherBricks => None, + Item::CrackedNetherBricks => None, + Item::ChiseledNetherBricks => None, + Item::NetherBrickFence => None, + Item::NetherBrickStairs => None, + Item::EnchantingTable => None, + Item::EndPortalFrame => None, + Item::EndStone => None, + Item::EndStoneBricks => None, + Item::DragonEgg => None, + Item::RedstoneLamp => None, + Item::SandstoneStairs => None, + Item::EmeraldOre => None, + Item::EnderChest => None, + Item::TripwireHook => None, + Item::EmeraldBlock => None, + Item::SpruceStairs => None, + Item::BirchStairs => None, + Item::JungleStairs => None, + Item::CrimsonStairs => None, + Item::WarpedStairs => None, + Item::CommandBlock => None, + Item::Beacon => None, + Item::CobblestoneWall => None, + Item::MossyCobblestoneWall => None, + Item::BrickWall => None, + Item::PrismarineWall => None, + Item::RedSandstoneWall => None, + Item::MossyStoneBrickWall => None, + Item::GraniteWall => None, + Item::StoneBrickWall => None, + Item::NetherBrickWall => None, + Item::AndesiteWall => None, + Item::RedNetherBrickWall => None, + Item::SandstoneWall => None, + Item::EndStoneBrickWall => None, + Item::DioriteWall => None, + Item::BlackstoneWall => None, + Item::PolishedBlackstoneWall => None, + Item::PolishedBlackstoneBrickWall => None, + Item::StoneButton => None, + Item::OakButton => None, + Item::SpruceButton => None, + Item::BirchButton => None, + Item::JungleButton => None, + Item::AcaciaButton => None, + Item::DarkOakButton => None, + Item::CrimsonButton => None, + Item::WarpedButton => None, + Item::PolishedBlackstoneButton => None, + Item::Anvil => None, + Item::ChippedAnvil => None, + Item::DamagedAnvil => None, + Item::TrappedChest => None, + Item::LightWeightedPressurePlate => None, + Item::HeavyWeightedPressurePlate => None, + Item::DaylightDetector => None, + Item::RedstoneBlock => None, + Item::NetherQuartzOre => None, + Item::Hopper => None, + Item::ChiseledQuartzBlock => None, + Item::QuartzBlock => None, + Item::QuartzBricks => None, + Item::QuartzPillar => None, + Item::QuartzStairs => None, + Item::ActivatorRail => None, + Item::Dropper => None, + Item::WhiteTerracotta => None, + Item::OrangeTerracotta => None, + Item::MagentaTerracotta => None, + Item::LightBlueTerracotta => None, + Item::YellowTerracotta => None, + Item::LimeTerracotta => None, + Item::PinkTerracotta => None, + Item::GrayTerracotta => None, + Item::LightGrayTerracotta => None, + Item::CyanTerracotta => None, + Item::PurpleTerracotta => None, + Item::BlueTerracotta => None, + Item::BrownTerracotta => None, + Item::GreenTerracotta => None, + Item::RedTerracotta => None, + Item::BlackTerracotta => None, + Item::Barrier => None, + Item::IronTrapdoor => None, + Item::HayBlock => None, + Item::WhiteCarpet => None, + Item::OrangeCarpet => None, + Item::MagentaCarpet => None, + Item::LightBlueCarpet => None, + Item::YellowCarpet => None, + Item::LimeCarpet => None, + Item::PinkCarpet => None, + Item::GrayCarpet => None, + Item::LightGrayCarpet => None, + Item::CyanCarpet => None, + Item::PurpleCarpet => None, + Item::BlueCarpet => None, + Item::BrownCarpet => None, + Item::GreenCarpet => None, + Item::RedCarpet => None, + Item::BlackCarpet => None, + Item::Terracotta => None, + Item::CoalBlock => None, + Item::PackedIce => None, + Item::AcaciaStairs => None, + Item::DarkOakStairs => None, + Item::SlimeBlock => None, + Item::GrassPath => None, + Item::Sunflower => None, + Item::Lilac => None, + Item::RoseBush => None, + Item::Peony => None, + Item::TallGrass => None, + Item::LargeFern => None, + Item::WhiteStainedGlass => None, + Item::OrangeStainedGlass => None, + Item::MagentaStainedGlass => None, + Item::LightBlueStainedGlass => None, + Item::YellowStainedGlass => None, + Item::LimeStainedGlass => None, + Item::PinkStainedGlass => None, + Item::GrayStainedGlass => None, + Item::LightGrayStainedGlass => None, + Item::CyanStainedGlass => None, + Item::PurpleStainedGlass => None, + Item::BlueStainedGlass => None, + Item::BrownStainedGlass => None, + Item::GreenStainedGlass => None, + Item::RedStainedGlass => None, + Item::BlackStainedGlass => None, + Item::WhiteStainedGlassPane => None, + Item::OrangeStainedGlassPane => None, + Item::MagentaStainedGlassPane => None, + Item::LightBlueStainedGlassPane => None, + Item::YellowStainedGlassPane => None, + Item::LimeStainedGlassPane => None, + Item::PinkStainedGlassPane => None, + Item::GrayStainedGlassPane => None, + Item::LightGrayStainedGlassPane => None, + Item::CyanStainedGlassPane => None, + Item::PurpleStainedGlassPane => None, + Item::BlueStainedGlassPane => None, + Item::BrownStainedGlassPane => None, + Item::GreenStainedGlassPane => None, + Item::RedStainedGlassPane => None, + Item::BlackStainedGlassPane => None, + Item::Prismarine => None, + Item::PrismarineBricks => None, + Item::DarkPrismarine => None, + Item::PrismarineStairs => None, + Item::PrismarineBrickStairs => None, + Item::DarkPrismarineStairs => None, + Item::SeaLantern => None, + Item::RedSandstone => None, + Item::ChiseledRedSandstone => None, + Item::CutRedSandstone => None, + Item::RedSandstoneStairs => None, + Item::RepeatingCommandBlock => None, + Item::ChainCommandBlock => None, + Item::MagmaBlock => None, + Item::NetherWartBlock => None, + Item::WarpedWartBlock => None, + Item::RedNetherBricks => None, + Item::BoneBlock => None, + Item::StructureVoid => None, + Item::Observer => None, + Item::ShulkerBox => None, + Item::WhiteShulkerBox => None, + Item::OrangeShulkerBox => None, + Item::MagentaShulkerBox => None, + Item::LightBlueShulkerBox => None, + Item::YellowShulkerBox => None, + Item::LimeShulkerBox => None, + Item::PinkShulkerBox => None, + Item::GrayShulkerBox => None, + Item::LightGrayShulkerBox => None, + Item::CyanShulkerBox => None, + Item::PurpleShulkerBox => None, + Item::BlueShulkerBox => None, + Item::BrownShulkerBox => None, + Item::GreenShulkerBox => None, + Item::RedShulkerBox => None, + Item::BlackShulkerBox => None, + Item::WhiteGlazedTerracotta => None, + Item::OrangeGlazedTerracotta => None, + Item::MagentaGlazedTerracotta => None, + Item::LightBlueGlazedTerracotta => None, + Item::YellowGlazedTerracotta => None, + Item::LimeGlazedTerracotta => None, + Item::PinkGlazedTerracotta => None, + Item::GrayGlazedTerracotta => None, + Item::LightGrayGlazedTerracotta => None, + Item::CyanGlazedTerracotta => None, + Item::PurpleGlazedTerracotta => None, + Item::BlueGlazedTerracotta => None, + Item::BrownGlazedTerracotta => None, + Item::GreenGlazedTerracotta => None, + Item::RedGlazedTerracotta => None, + Item::BlackGlazedTerracotta => None, + Item::WhiteConcrete => None, + Item::OrangeConcrete => None, + Item::MagentaConcrete => None, + Item::LightBlueConcrete => None, + Item::YellowConcrete => None, + Item::LimeConcrete => None, + Item::PinkConcrete => None, + Item::GrayConcrete => None, + Item::LightGrayConcrete => None, + Item::CyanConcrete => None, + Item::PurpleConcrete => None, + Item::BlueConcrete => None, + Item::BrownConcrete => None, + Item::GreenConcrete => None, + Item::RedConcrete => None, + Item::BlackConcrete => None, + Item::WhiteConcretePowder => None, + Item::OrangeConcretePowder => None, + Item::MagentaConcretePowder => None, + Item::LightBlueConcretePowder => None, + Item::YellowConcretePowder => None, + Item::LimeConcretePowder => None, + Item::PinkConcretePowder => None, + Item::GrayConcretePowder => None, + Item::LightGrayConcretePowder => None, + Item::CyanConcretePowder => None, + Item::PurpleConcretePowder => None, + Item::BlueConcretePowder => None, + Item::BrownConcretePowder => None, + Item::GreenConcretePowder => None, + Item::RedConcretePowder => None, + Item::BlackConcretePowder => None, + Item::TurtleEgg => None, + Item::DeadTubeCoralBlock => None, + Item::DeadBrainCoralBlock => None, + Item::DeadBubbleCoralBlock => None, + Item::DeadFireCoralBlock => None, + Item::DeadHornCoralBlock => None, + Item::TubeCoralBlock => None, + Item::BrainCoralBlock => None, + Item::BubbleCoralBlock => None, + Item::FireCoralBlock => None, + Item::HornCoralBlock => None, + Item::TubeCoral => None, + Item::BrainCoral => None, + Item::BubbleCoral => None, + Item::FireCoral => None, + Item::HornCoral => None, + Item::DeadBrainCoral => None, + Item::DeadBubbleCoral => None, + Item::DeadFireCoral => None, + Item::DeadHornCoral => None, + Item::DeadTubeCoral => None, + Item::TubeCoralFan => None, + Item::BrainCoralFan => None, + Item::BubbleCoralFan => None, + Item::FireCoralFan => None, + Item::HornCoralFan => None, + Item::DeadTubeCoralFan => None, + Item::DeadBrainCoralFan => None, + Item::DeadBubbleCoralFan => None, + Item::DeadFireCoralFan => None, + Item::DeadHornCoralFan => None, + Item::BlueIce => None, + Item::Conduit => None, + Item::PolishedGraniteStairs => None, + Item::SmoothRedSandstoneStairs => None, + Item::MossyStoneBrickStairs => None, + Item::PolishedDioriteStairs => None, + Item::MossyCobblestoneStairs => None, + Item::EndStoneBrickStairs => None, + Item::StoneStairs => None, + Item::SmoothSandstoneStairs => None, + Item::SmoothQuartzStairs => None, + Item::GraniteStairs => None, + Item::AndesiteStairs => None, + Item::RedNetherBrickStairs => None, + Item::PolishedAndesiteStairs => None, + Item::DioriteStairs => None, + Item::PolishedGraniteSlab => None, + Item::SmoothRedSandstoneSlab => None, + Item::MossyStoneBrickSlab => None, + Item::PolishedDioriteSlab => None, + Item::MossyCobblestoneSlab => None, + Item::EndStoneBrickSlab => None, + Item::SmoothSandstoneSlab => None, + Item::SmoothQuartzSlab => None, + Item::GraniteSlab => None, + Item::AndesiteSlab => None, + Item::RedNetherBrickSlab => None, + Item::PolishedAndesiteSlab => None, + Item::DioriteSlab => None, + Item::Scaffolding => None, + Item::IronDoor => None, + Item::OakDoor => None, + Item::SpruceDoor => None, + Item::BirchDoor => None, + Item::JungleDoor => None, + Item::AcaciaDoor => None, + Item::DarkOakDoor => None, + Item::CrimsonDoor => None, + Item::WarpedDoor => None, + Item::Repeater => None, + Item::Comparator => None, + Item::StructureBlock => None, + Item::Jigsaw => None, + Item::TurtleHelmet => None, + Item::Scute => None, + Item::FlintAndSteel => None, + Item::Apple => None, + Item::Bow => None, + Item::Arrow => None, + Item::Coal => None, + Item::Charcoal => None, + Item::Diamond => None, + Item::IronIngot => None, + Item::GoldIngot => None, + Item::NetheriteIngot => None, + Item::NetheriteScrap => None, + Item::WoodenSword => None, + Item::WoodenShovel => None, + Item::WoodenPickaxe => None, + Item::WoodenAxe => None, + Item::WoodenHoe => None, + Item::StoneSword => None, + Item::StoneShovel => None, + Item::StonePickaxe => None, + Item::StoneAxe => None, + Item::StoneHoe => None, + Item::GoldenSword => None, + Item::GoldenShovel => None, + Item::GoldenPickaxe => None, + Item::GoldenAxe => None, + Item::GoldenHoe => None, + Item::IronSword => None, + Item::IronShovel => None, + Item::IronPickaxe => None, + Item::IronAxe => None, + Item::IronHoe => None, + Item::DiamondSword => None, + Item::DiamondShovel => None, + Item::DiamondPickaxe => None, + Item::DiamondAxe => None, + Item::DiamondHoe => None, + Item::NetheriteSword => None, + Item::NetheriteShovel => None, + Item::NetheritePickaxe => None, + Item::NetheriteAxe => None, + Item::NetheriteHoe => None, + Item::Stick => None, + Item::Bowl => None, + Item::MushroomStew => None, + Item::String => None, + Item::Feather => None, + Item::Gunpowder => None, + Item::WheatSeeds => None, + Item::Wheat => None, + Item::Bread => None, + Item::LeatherHelmet => None, + Item::LeatherChestplate => None, + Item::LeatherLeggings => None, + Item::LeatherBoots => None, + Item::ChainmailHelmet => None, + Item::ChainmailChestplate => None, + Item::ChainmailLeggings => None, + Item::ChainmailBoots => None, + Item::IronHelmet => None, + Item::IronChestplate => None, + Item::IronLeggings => None, + Item::IronBoots => None, + Item::DiamondHelmet => None, + Item::DiamondChestplate => None, + Item::DiamondLeggings => None, + Item::DiamondBoots => None, + Item::GoldenHelmet => None, + Item::GoldenChestplate => None, + Item::GoldenLeggings => None, + Item::GoldenBoots => None, + Item::NetheriteHelmet => None, + Item::NetheriteChestplate => None, + Item::NetheriteLeggings => None, + Item::NetheriteBoots => None, + Item::Flint => None, + Item::Porkchop => None, + Item::CookedPorkchop => None, + Item::Painting => None, + Item::GoldenApple => None, + Item::EnchantedGoldenApple => None, + Item::OakSign => None, + Item::SpruceSign => None, + Item::BirchSign => None, + Item::JungleSign => None, + Item::AcaciaSign => None, + Item::DarkOakSign => None, + Item::CrimsonSign => None, + Item::WarpedSign => None, + Item::Bucket => None, + Item::WaterBucket => None, + Item::LavaBucket => None, + Item::Minecart => None, + Item::Saddle => None, + Item::Redstone => None, + Item::Snowball => None, + Item::OakBoat => None, + Item::Leather => None, + Item::MilkBucket => None, + Item::PufferfishBucket => None, + Item::SalmonBucket => None, + Item::CodBucket => None, + Item::TropicalFishBucket => None, + Item::Brick => None, + Item::ClayBall => None, + Item::DriedKelpBlock => None, + Item::Paper => None, + Item::Book => None, + Item::SlimeBall => None, + Item::ChestMinecart => None, + Item::FurnaceMinecart => None, + Item::Egg => None, + Item::Compass => None, + Item::FishingRod => None, + Item::Clock => None, + Item::GlowstoneDust => None, + Item::Cod => None, + Item::Salmon => None, + Item::TropicalFish => None, + Item::Pufferfish => None, + Item::CookedCod => None, + Item::CookedSalmon => None, + Item::InkSac => None, + Item::CocoaBeans => None, + Item::LapisLazuli => None, + Item::WhiteDye => None, + Item::OrangeDye => None, + Item::MagentaDye => None, + Item::LightBlueDye => None, + Item::YellowDye => None, + Item::LimeDye => None, + Item::PinkDye => None, + Item::GrayDye => None, + Item::LightGrayDye => None, + Item::CyanDye => None, + Item::PurpleDye => None, + Item::BlueDye => None, + Item::BrownDye => None, + Item::GreenDye => None, + Item::RedDye => None, + Item::BlackDye => None, + Item::BoneMeal => None, + Item::Bone => None, + Item::Sugar => None, + Item::Cake => None, + Item::WhiteBed => None, + Item::OrangeBed => None, + Item::MagentaBed => None, + Item::LightBlueBed => None, + Item::YellowBed => None, + Item::LimeBed => None, + Item::PinkBed => None, + Item::GrayBed => None, + Item::LightGrayBed => None, + Item::CyanBed => None, + Item::PurpleBed => None, + Item::BlueBed => None, + Item::BrownBed => None, + Item::GreenBed => None, + Item::RedBed => None, + Item::BlackBed => None, + Item::Cookie => None, + Item::FilledMap => None, + Item::Shears => None, + Item::MelonSlice => None, + Item::DriedKelp => None, + Item::PumpkinSeeds => None, + Item::MelonSeeds => None, + Item::Beef => None, + Item::CookedBeef => None, + Item::Chicken => None, + Item::CookedChicken => None, + Item::RottenFlesh => None, + Item::EnderPearl => None, + Item::BlazeRod => None, + Item::GhastTear => None, + Item::GoldNugget => None, + Item::NetherWart => None, + Item::Potion => None, + Item::GlassBottle => None, + Item::SpiderEye => None, + Item::FermentedSpiderEye => None, + Item::BlazePowder => None, + Item::MagmaCream => None, + Item::BrewingStand => None, + Item::Cauldron => None, + Item::EnderEye => None, + Item::GlisteringMelonSlice => None, + Item::BatSpawnEgg => None, + Item::BeeSpawnEgg => None, + Item::BlazeSpawnEgg => None, + Item::CatSpawnEgg => None, + Item::CaveSpiderSpawnEgg => None, + Item::ChickenSpawnEgg => None, + Item::CodSpawnEgg => None, + Item::CowSpawnEgg => None, + Item::CreeperSpawnEgg => None, + Item::DolphinSpawnEgg => None, + Item::DonkeySpawnEgg => None, + Item::DrownedSpawnEgg => None, + Item::ElderGuardianSpawnEgg => None, + Item::EndermanSpawnEgg => None, + Item::EndermiteSpawnEgg => None, + Item::EvokerSpawnEgg => None, + Item::FoxSpawnEgg => None, + Item::GhastSpawnEgg => None, + Item::GuardianSpawnEgg => None, + Item::HoglinSpawnEgg => None, + Item::HorseSpawnEgg => None, + Item::HuskSpawnEgg => None, + Item::LlamaSpawnEgg => None, + Item::MagmaCubeSpawnEgg => None, + Item::MooshroomSpawnEgg => None, + Item::MuleSpawnEgg => None, + Item::OcelotSpawnEgg => None, + Item::PandaSpawnEgg => None, + Item::ParrotSpawnEgg => None, + Item::PhantomSpawnEgg => None, + Item::PigSpawnEgg => None, + Item::PiglinSpawnEgg => None, + Item::PiglinBruteSpawnEgg => None, + Item::PillagerSpawnEgg => None, + Item::PolarBearSpawnEgg => None, + Item::PufferfishSpawnEgg => None, + Item::RabbitSpawnEgg => None, + Item::RavagerSpawnEgg => None, + Item::SalmonSpawnEgg => None, + Item::SheepSpawnEgg => None, + Item::ShulkerSpawnEgg => None, + Item::SilverfishSpawnEgg => None, + Item::SkeletonSpawnEgg => None, + Item::SkeletonHorseSpawnEgg => None, + Item::SlimeSpawnEgg => None, + Item::SpiderSpawnEgg => None, + Item::SquidSpawnEgg => None, + Item::StraySpawnEgg => None, + Item::StriderSpawnEgg => None, + Item::TraderLlamaSpawnEgg => None, + Item::TropicalFishSpawnEgg => None, + Item::TurtleSpawnEgg => None, + Item::VexSpawnEgg => None, + Item::VillagerSpawnEgg => None, + Item::VindicatorSpawnEgg => None, + Item::WanderingTraderSpawnEgg => None, + Item::WitchSpawnEgg => None, + Item::WitherSkeletonSpawnEgg => None, + Item::WolfSpawnEgg => None, + Item::ZoglinSpawnEgg => None, + Item::ZombieSpawnEgg => None, + Item::ZombieHorseSpawnEgg => None, + Item::ZombieVillagerSpawnEgg => None, + Item::ZombifiedPiglinSpawnEgg => None, + Item::ExperienceBottle => None, + Item::FireCharge => None, + Item::WritableBook => None, + Item::WrittenBook => None, + Item::Emerald => None, + Item::ItemFrame => None, + Item::FlowerPot => None, + Item::Carrot => None, + Item::Potato => None, + Item::BakedPotato => None, + Item::PoisonousPotato => None, + Item::Map => None, + Item::GoldenCarrot => None, + Item::SkeletonSkull => None, + Item::WitherSkeletonSkull => None, + Item::PlayerHead => None, + Item::ZombieHead => None, + Item::CreeperHead => None, + Item::DragonHead => None, + Item::CarrotOnAStick => None, + Item::WarpedFungusOnAStick => None, + Item::NetherStar => None, + Item::PumpkinPie => None, + Item::FireworkRocket => None, + Item::FireworkStar => None, + Item::EnchantedBook => None, + Item::NetherBrick => None, + Item::Quartz => None, + Item::TntMinecart => None, + Item::HopperMinecart => None, + Item::PrismarineShard => None, + Item::PrismarineCrystals => None, + Item::Rabbit => None, + Item::CookedRabbit => None, + Item::RabbitStew => None, + Item::RabbitFoot => None, + Item::RabbitHide => None, + Item::ArmorStand => None, + Item::IronHorseArmor => None, + Item::GoldenHorseArmor => None, + Item::DiamondHorseArmor => None, + Item::LeatherHorseArmor => None, + Item::Lead => None, + Item::NameTag => None, + Item::CommandBlockMinecart => None, + Item::Mutton => None, + Item::CookedMutton => None, + Item::WhiteBanner => None, + Item::OrangeBanner => None, + Item::MagentaBanner => None, + Item::LightBlueBanner => None, + Item::YellowBanner => None, + Item::LimeBanner => None, + Item::PinkBanner => None, + Item::GrayBanner => None, + Item::LightGrayBanner => None, + Item::CyanBanner => None, + Item::PurpleBanner => None, + Item::BlueBanner => None, + Item::BrownBanner => None, + Item::GreenBanner => None, + Item::RedBanner => None, + Item::BlackBanner => None, + Item::EndCrystal => None, + Item::ChorusFruit => None, + Item::PoppedChorusFruit => None, + Item::Beetroot => None, + Item::BeetrootSeeds => None, + Item::BeetrootSoup => None, + Item::DragonBreath => None, + Item::SplashPotion => None, + Item::SpectralArrow => None, + Item::TippedArrow => None, + Item::LingeringPotion => None, + Item::Shield => None, + Item::Elytra => None, + Item::SpruceBoat => None, + Item::BirchBoat => None, + Item::JungleBoat => None, + Item::AcaciaBoat => None, + Item::DarkOakBoat => None, + Item::TotemOfUndying => None, + Item::ShulkerShell => None, + Item::IronNugget => None, + Item::KnowledgeBook => None, + Item::DebugStick => None, + Item::MusicDisc13 => None, + Item::MusicDiscCat => None, + Item::MusicDiscBlocks => None, + Item::MusicDiscChirp => None, + Item::MusicDiscFar => None, + Item::MusicDiscMall => None, + Item::MusicDiscMellohi => None, + Item::MusicDiscStal => None, + Item::MusicDiscStrad => None, + Item::MusicDiscWard => None, + Item::MusicDisc11 => None, + Item::MusicDiscWait => None, + Item::MusicDiscPigstep => None, + Item::Trident => None, + Item::PhantomMembrane => None, + Item::NautilusShell => None, + Item::HeartOfTheSea => None, + Item::Crossbow => None, + Item::SuspiciousStew => None, + Item::Loom => None, + Item::FlowerBannerPattern => None, + Item::CreeperBannerPattern => None, + Item::SkullBannerPattern => None, + Item::MojangBannerPattern => None, + Item::GlobeBannerPattern => None, + Item::PiglinBannerPattern => None, + Item::Composter => None, + Item::Barrel => None, + Item::Smoker => None, + Item::BlastFurnace => None, + Item::CartographyTable => None, + Item::FletchingTable => None, + Item::Grindstone => None, + Item::Lectern => None, + Item::SmithingTable => None, + Item::Stonecutter => None, + Item::Bell => None, + Item::Lantern => None, + Item::SoulLantern => None, + Item::SweetBerries => None, + Item::Campfire => None, + Item::SoulCampfire => None, + Item::Shroomlight => None, + Item::Honeycomb => None, + Item::BeeNest => None, + Item::Beehive => None, + Item::HoneyBottle => None, + Item::HoneyBlock => None, + Item::HoneycombBlock => None, + Item::Lodestone => None, + Item::NetheriteBlock => None, + Item::AncientDebris => None, + Item::Target => None, + Item::CryingObsidian => None, + Item::Blackstone => None, + Item::BlackstoneSlab => None, + Item::BlackstoneStairs => None, + Item::GildedBlackstone => None, + Item::PolishedBlackstone => None, + Item::PolishedBlackstoneSlab => None, + Item::PolishedBlackstoneStairs => None, + Item::ChiseledPolishedBlackstone => None, + Item::PolishedBlackstoneBricks => None, + Item::PolishedBlackstoneBrickSlab => None, + Item::PolishedBlackstoneBrickStairs => None, + Item::CrackedPolishedBlackstoneBricks => None, + Item::RespawnAnchor => None, + } + } +} +use std::convert::TryFrom; + +impl TryFrom<String> for Item { + type Error = &'static str; + + fn try_from(value: String) -> Result<Self, Self::Error> { + if let Some(item) = Item::from_name(value.as_str()) { + Ok(item) + } else { + Err("Unknown item name.") + } + } +} + +impl From<Item> for &'static str { + fn from(i: Item) -> Self { + i.name() + } +} + +use std::str::FromStr; + +impl FromStr for Item { + type Err = &'static str; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + if let Some(item) = Item::from_name(s) { + Ok(item) + } else { + Err("Unknown item name.") + } + } +} diff --git a/libcraft/items/src/item_stack.rs b/libcraft/items/src/item_stack.rs new file mode 100644 index 000000000..410e6650d --- /dev/null +++ b/libcraft/items/src/item_stack.rs @@ -0,0 +1,530 @@ +use crate::{Enchantment, EnchantmentKind, Item}; +use core::fmt::Display; +use serde::{Deserialize, Serialize}; +use std::convert::TryInto; +use std::error::Error; +use std::fmt; +use std::num::NonZeroU32; + +/// Represents an item stack. +/// +/// An item stack includes an item type, an amount and a bunch of properties (enchantments, etc.) +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct ItemStack { + /// The item type of this `ItemStack`. + #[serde(rename = "id")] + item: Item, + + /// The number of items in the `ItemStack`. + #[serde(rename = "Count")] + count: NonZeroU32, + + /// The `ItemStack` metadata, containing data such as damage, + /// repair cost, enchantments... + #[serde(rename = "tag")] + meta: Option<ItemStackMeta>, +} + +/// Represents the metadata of an `ItemStack`. Contains: +/// * Item title +/// * Item lore (Optional) +/// * Item damage (Optional) +/// * Item repair cost (Optional) +/// * Item enchantments +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +#[serde(rename_all = "PascalCase")] +pub struct ItemStackMeta { + /// The displayed title (name) of the associated `ItemStack`. + title: String, + + /// The displayed lore of the associated `ItemStack`. + lore: String, + + /// The damage taken by the `ItemStack`. + damage: Option<i32>, + + /// The cost of repairing the `ItemStack`. + repair_cost: Option<u32>, + + /// The enchantments applied to this `ItemStack`. + enchantments: Vec<Enchantment>, +} + +impl ItemStack { + /// Creates a new `ItemStack` with the default name (title) + /// no lore, no damage, no repair cost and no enchantments. + /// # Errors + /// Return `ItemStackError::EmptyStack` when `count` is zero. + pub fn new(item: Item, count: u32) -> Result<Self, ItemStackError> { + let count = NonZeroU32::new(count).ok_or(ItemStackError::EmptyStack)?; + Ok(Self { + item, + count, + meta: Some(ItemStackMeta { + title: String::from(item.name()), + lore: "".to_owned(), + damage: None, + repair_cost: None, + enchantments: vec![], + }), + }) + } + + /// Returns whether the given item stack has + /// the same type as (but not necessarily the same + /// amount as) `self`. + #[must_use] + pub fn has_same_type(&self, other: &Self) -> bool { + self.item == other.item + } + + /// Returns whether the given item stack has the same damage + /// as `self`. + #[must_use] + pub fn has_same_damage(&self, other: &Self) -> bool { + if let (Some(self_meta), Some(other_meta)) = (self.meta.as_ref(), other.meta.as_ref()) { + self_meta.damage == other_meta.damage + } else { + self.meta.is_none() && other.meta.is_none() + } + } + + /// Returns whether the given `ItemStack` has + /// the same count as (but not necessarily the same + /// type as) `self`. + #[must_use] + pub fn has_same_count(&self, other: &Self) -> bool { + self.count == other.count + } + + /// Returns whether the given `ItemStack` has the same + /// type and count as (but not necessarily the same meta + /// as) `self`. + #[must_use] + pub fn has_same_type_and_count(&self, other: &Self) -> bool { + self.item == other.item && self.count == other.count + } + + /// Returns whether the given `ItemStack` has + /// the same type and damage as `self`. + #[must_use] + pub fn has_same_type_and_damage(&self, other: &Self) -> bool { + self.item == other.item && self.has_same_damage(other) + } + + /// Returns the item type for this `ItemStack`. + #[must_use] + pub const fn item(&self) -> Item { + self.item + } + + /// Returns the number of items in this `ItemStack`. + #[must_use] + pub const fn count(&self) -> u32 { + self.count.get() + } + + /// Adds more items to this `ItemStack`. Returns the new count. + /// # Errors + /// Returns `ExceedsStackSize` when the combined amount of items is greater than the stack size. + /// If the new item count cannot be represented as `i32`, returns `ClientOverflow`. + pub fn add(&mut self, count: u32) -> Result<u32, ItemStackError> { + self.set_count(self.count.get() + count) + } + + /// Adds more items to this `ItemStack`. Does not check if the + /// addition will make the count to be greater than the + /// stack size. Does not check count overflows. Returns the new count. + /// # Panics + /// Panics if the new item count is greater than the stack size. + pub fn unchecked_add(&mut self, count: u32) -> u32 { + self.count = NonZeroU32::new(self.count.get() + count).unwrap(); + self.count.get() + } + + /// Removes some items from this `ItemStack` and return the new item count. + /// # Errors + /// Returns `NotEnoughItems` if the new stack would be empty. + #[allow(clippy::missing_panics_doc)] + pub fn remove(&mut self, count: u32) -> Result<u32, ItemStackError> { + if self.count.get() <= count { + return Err(ItemStackError::NotEnoughItems); + } + // Cannot panic because `self.count` > `count` at this point + self.count = NonZeroU32::new(self.count.get() - count).unwrap(); + Ok(self.count.get()) + } + + /// Change the item type for this `ItemStack` and return the new item. + /// # Errors + /// Returns `ExceedsStackSize` when the new item's stack size is lower than the current amount of items. + pub fn set_item(&mut self, item: Item) -> Result<Item, ItemStackError> { + if self.count.get() > item.stack_size() { + return Err(ItemStackError::ExceedsStackSize); + } + self.item = item; + Ok(self.item) + } + + /// Gets the `ItemStack` and returns it. + #[allow(clippy::missing_panics_doc)] + #[must_use] + pub fn get_item(&self) -> Self { + Self { + count: 1.try_into().unwrap(), + ..self.clone() + } + } + + /// Sets the item type for this `ItemStack`. Does not check if + /// the new item type stack size will be lower than the current + /// item count. Returns the new item type. + pub fn unchecked_set_item(&mut self, item: Item) -> Item { + self.item = item; + self.item + } + + /// Sets the count for this `ItemStack` and returns the updated count. + /// # Errors + /// Returns `EmptyStack` when `count` is zero and `ExceedsStackSize` when `count` is greater than this item's stack size. + /// If the new item count cannot be represented as `i32`, returns `ClientOverflow`. + pub fn set_count(&mut self, count: u32) -> Result<u32, ItemStackError> { + let count = NonZeroU32::new(count).ok_or(ItemStackError::EmptyStack)?; + if count.get() > self.item.stack_size() { + Err(ItemStackError::ExceedsStackSize) + } else if count.get() > i32::MAX as u32 { + Err(ItemStackError::ClientOverflow) + } else { + self.count = count; + Ok(self.count.get()) + } + } + + /// Sets the count for this `ItemStack`. Does not check if + /// the desired count exceeds the current item type stack size, nor whether it overflows. + /// Returns the updated count. + /// # Panics + /// Panics if `count` is zero. + pub fn unchecked_set_count(&mut self, count: u32) -> u32 { + self.count = NonZeroU32::new(count).unwrap(); + self.count.get() + } + + /// Splits this `ItemStack` in half, returning the + /// removed half. If the amount is odd, `self` + /// will be left with the least items. Returns the taken + /// half. + #[must_use] + #[allow(clippy::missing_panics_doc)] + pub fn take_half(self) -> (Option<Self>, Self) { + let half = (self.count.get() + 1) / 2; + // Cannot panic because `half` is always > 0; `self.count` >= 1 -> At minimum (1 + 1) / 2 = 1 + self.take(NonZeroU32::new(half).unwrap()) + } + + /// Splits this `ItemStack` by removing the + /// specified amount. Returns the taken part. + #[must_use] + #[allow(clippy::missing_panics_doc)] + pub fn take(mut self, amount: NonZeroU32) -> (Option<Self>, Self) { + if self.count <= amount { + return (None, self); + } + let count_left: u32 = self.count.get() - amount.get(); + let taken = Self { + count: amount, + ..self.clone() + }; + // Cannot panic because `self.count` > `amount` -> `self.count` - `amount` > 0 + self.count = NonZeroU32::new(count_left).unwrap(); + (Some(self), taken) + } + + /// Merges another `ItemStack` with this one. + /// # Errors + /// Returns `IncompatibleStacks` when the two stacks have different item types. + #[allow(clippy::missing_panics_doc)] + pub fn merge_with(&mut self, other: &Self) -> Result<(), ItemStackError> { + if !self.has_same_type_and_damage(other) { + return Err(ItemStackError::IncompatibleStacks); + } + let new_count = (self.count.get() + other.count.get()).min(self.item.stack_size()); + // Cannot panic because `self.count` > 0 and `other.count` > 0 -> `self.count` + `other.count` > 0 + self.count = NonZeroU32::new(new_count).unwrap(); + //other.count = NonZeroU32::new(other.count() - amount_added).unwrap(); + Ok(()) + } + + /// Transfers up to `n` items to `other`. + /// # Errors + /// Returns `NotEnoughItems` when there aren't enough items to complete the transfer. + /// If the new item count in `other` cannot be represented by `i32`, returns `ClientOverflow`. + #[allow(clippy::missing_panics_doc)] + pub fn transfer_to(&mut self, n: u32, other: &mut Self) -> Result<(), ItemStackError> { + if self.count.get() <= n || n == 0 { + return Err(ItemStackError::NotEnoughItems); + } + let max_transfer = other.item.stack_size().saturating_sub(other.count.get()); + let transfer = max_transfer.min(self.count.get()).min(n); + if other.count.get() + transfer > i32::MAX as u32 { + return Err(ItemStackError::ClientOverflow); + } + + self.count = NonZeroU32::new(self.count.get() - transfer).unwrap(); + other.count = NonZeroU32::new(other.count.get() + transfer).unwrap(); + Ok(()) + } + + /// Move up to `n` items from `self` to `other`. + /// # Errors + /// Returns `IncompatibleStacks` when the two item stacks have different items. + #[allow(clippy::missing_panics_doc)] + pub fn drain_into_bounded( + mut self, + n: u32, + other: &mut Self, + ) -> Result<Option<Self>, ItemStackError> { + if !self.has_same_type(other) { + return Err(ItemStackError::IncompatibleStacks); + } + + // Stack size is the same for both self and other because they are the same type. + let stack_size = self.item.stack_size(); + let space_in_other = stack_size - other.count(); + let items_in_self = self.count(); + let moving_items = space_in_other.min(n).min(items_in_self); + + // Guaranteed to be <`self.stack_size` because of `space_in_other` being one of the minimums + other.set_count(moving_items + other.count()).unwrap(); + + if items_in_self - moving_items == 0 { + Ok(None) + } else { + self.set_count(items_in_self - moving_items).unwrap(); + Ok(Some(self)) + } + } + + /// Damages the item by the specified amount. + /// If this function returns `true`, then the item is broken. + #[allow(clippy::missing_panics_doc)] + pub fn damage(&mut self, amount: i32) -> bool { + if self.meta.is_none() { + return false; + } + match &mut self.meta.clone().unwrap().damage { + Some(damage) => { + *damage += amount; + if let Some(durability) = self.item.durability() { + // Convert to a larger type for a safe conversion + i64::from(*damage) >= i64::from(durability) + } else { + false + } + } + None => false, + } + } + + /// Returns the amount of damage the items have taken. + #[must_use] + pub fn damage_taken(&self) -> Option<i32> { + self.meta.as_ref().map_or(Some(0), |meta| meta.damage) + } + + /// Returns true is the contents of other could be merged with the contents + /// of self. This does not look at the item count, just the kind. + /// Items can be merged when they have the same kind, damage, and enchantment. + /// If a item has a stacksize of one then it can never be stacked. + #[must_use] + pub fn stackable_types(&self, other: &Self) -> bool { + self.has_same_type(other) && + // Todo: make this function check that the items have same name + // if you rename a item, then it does not stack with items that + // dont share the rename. Someone need to explore this further. + self.stack_size() > 1 && + other.stack_size() > 1 + } + + /// How many items could be stacked together + #[must_use] + pub fn stack_size(&self) -> u32 { + self.item.stack_size() + } +} + +/// An error type that may be returned when performing +/// operations over an `ItemStack`. +#[derive(Debug, Clone)] +pub enum ItemStackError { + ClientOverflow, + EmptyStack, + ExceedsStackSize, + IncompatibleStacks, + NotEnoughItems, +} + +impl Display for ItemStackError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Error for ItemStackError {} + +impl ItemStackMeta { + #[must_use] + pub fn new(item: Item) -> Self { + Self { + title: item.display_name().to_owned(), + lore: "".to_owned(), + damage: None, + repair_cost: None, + enchantments: vec![], + } + } + + /// Get the level of the given enchantment. + pub fn get_enchantment_level(&self, ench: EnchantmentKind) -> Option<u32> { + self.enchantments + .iter() + .find(|e| e.kind() == ench) + .map(Enchantment::level) + } + /// Change the level of the given enchantment in-place or add it at the end of the list. + pub fn set_enchantment_level(&mut self, ench: EnchantmentKind, level: u32) { + if let Some(enchant) = self.enchantments.iter_mut().find(|e| e.kind() == ench) { + enchant.set_level(level); + } else { + self.enchantments.push(Enchantment::new(ench, level)); + } + } +} + +pub struct ItemStackBuilder { + item: Item, + count: NonZeroU32, + meta: Option<ItemStackMeta>, +} + +impl Default for ItemStackBuilder { + fn default() -> Self { + Self { + item: Item::Stone, + count: 1.try_into().unwrap(), + meta: None, + } + } +} + +impl ItemStackBuilder { + #[must_use] + #[allow(clippy::missing_panics_doc)] + pub fn new() -> Self { + Self { + item: Item::Stone, + count: 1.try_into().unwrap(), + meta: None, + } + } + + #[must_use] + #[allow(clippy::missing_panics_doc)] + pub fn with_item(item: Item) -> Self { + Self { + item, + count: 1.try_into().unwrap(), + meta: None, + } + } + + #[must_use] + pub fn item(self, item: Item) -> Self { + Self { item, ..self } + } + + /// Set the item `count`. + /// # Panics + /// Panics if `count` is zero. + #[must_use] + pub fn count(self, count: u32) -> Self { + Self { + count: count.try_into().expect("`count` cannot be zero"), + ..self + } + } + + /// Set the item `title`. + #[must_use] + pub fn title(mut self, title: impl AsRef<str>) -> Self { + self.get_or_init_meta().title = title.as_ref().to_owned(); + self + } + + /// Set the item `lore`. + #[must_use] + pub fn lore(mut self, lore: impl AsRef<str>) -> Self { + self.get_or_init_meta().lore = lore.as_ref().to_owned(); + self + } + + /// Set the item's repair cost metadata to `repair_cost`. + #[must_use] + pub fn repair_cost(mut self, cost: u32) -> Self { + self.get_or_init_meta().repair_cost = Some(cost); + self + } + + /// Set the item's damage metadata to `damage`. + #[must_use] + pub fn damage(mut self, damage: i32) -> Self { + self.get_or_init_meta().damage = Some(damage); + self + } + + /// Set the item's enchantment metadata to `enchantments` + #[must_use] + pub fn enchantments(mut self, enchantments: Vec<Enchantment>) -> Self { + self.get_or_init_meta().enchantments = enchantments; + self + } + + /// If `damage` is some, then its value is applied, else this is a no-op. + #[must_use] + pub fn apply_damage(self, damage: Option<i32>) -> Self { + match damage { + Some(damage) => self.damage(damage), + None => self, + } + } + + /// Copy metadate from another item. + #[must_use] + pub fn copy_meta(mut self, other: &Self) -> Self { + self.meta = other.meta.clone(); + self + } + + /// Placeholder for the `Option::get_or_insert_default` funcion, setting the default item name. + fn get_or_init_meta(&mut self) -> &mut ItemStackMeta { + if let Some(ref mut s) = self.meta { + s + } else { + self.meta = Some(ItemStackMeta { + title: self.item.display_name().to_owned(), + ..ItemStackMeta::default() + }); + self.meta.as_mut().unwrap() + } + } +} + +impl From<ItemStackBuilder> for ItemStack { + fn from(it: ItemStackBuilder) -> Self { + Self { + item: it.item, + count: it.count, + meta: it.meta, + } + } +} diff --git a/libcraft/items/src/lib.rs b/libcraft/items/src/lib.rs new file mode 100644 index 000000000..1fe70d299 --- /dev/null +++ b/libcraft/items/src/lib.rs @@ -0,0 +1,16 @@ +#![forbid(unsafe_code)] +#![deny(warnings)] +#![warn(clippy::pedantic)] +#![allow(clippy::module_name_repetitions)] + +//! Libcraft crate for item manipulation. + +mod enchantment; +mod inventory_slot; +mod item; +mod item_stack; + +pub use enchantment::{Enchantment, EnchantmentKind}; +pub use inventory_slot::InventorySlot; +pub use item::*; +pub use item_stack::{ItemStack, ItemStackBuilder, ItemStackError, ItemStackMeta}; diff --git a/libcraft/macros/Cargo.toml b/libcraft/macros/Cargo.toml new file mode 100644 index 000000000..697ada416 --- /dev/null +++ b/libcraft/macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "libcraft-macros" +version = "0.1.0" +authors = ["Kalle Kankaanpää"] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +syn = "1.0" +quote = "1.0" +proc-macro2 = "1.0" diff --git a/libcraft/macros/src/lib.rs b/libcraft/macros/src/lib.rs new file mode 100644 index 000000000..58ac67a3f --- /dev/null +++ b/libcraft/macros/src/lib.rs @@ -0,0 +1,118 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use quote::{format_ident, quote}; +use syn::{self, parse_macro_input, Data, DeriveInput, Error, Field, Fields, Ident, Result}; + +#[proc_macro_derive(BlockData)] +pub fn block_data_derive(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + + let name = &ast.ident; + match get_fields(&ast) { + Ok(fields) => { + let block_data = impl_block_data(name, &fields); + let get_and_set = impl_getters_and_setters(name, &fields); + quote!( + #block_data + #get_and_set + ) + } + Err(err) => err.to_compile_error(), + } + .into() +} + +fn get_fields(ast: &DeriveInput) -> Result<Vec<Field>> { + let name = &ast.ident; + let mut fields: Vec<Field>; + + if let Data::Struct(data) = &ast.data { + if let Fields::Named(named_fields) = &data.fields { + fields = named_fields + .named + .iter() + .map(|field| field.to_owned()) + .collect(); + + let valid = fields + .iter() + .position(|field| field.to_owned().ident.unwrap() == "valid_properties"); + + if let Some(index) = valid { + fields.remove(index); + } else { + return Err(Error::new( + name.span(), + "Can't derive BlockData for struct without valid_properties field", + )); + } + } else { + return Err(Error::new( + name.span(), + "Can't derive BlockData for a struct with no named fields", + )); + } + } else { + return Err(Error::new( + name.span(), + "Can't derive BlockData for a non struct", + )); + } + + Ok(fields) +} + +fn impl_block_data(name: &Ident, fields: &[Field]) -> TokenStream2 { + let idents: Vec<Ident> = fields.iter().map(|f| f.to_owned().ident.unwrap()).collect(); + quote!( + impl BlockData for #name { + fn from_raw(raw: &RawBlockStateProperties, valid: &'static ValidProperties) -> Option<Self> + where + Self: Sized, + { + Some(Self { #(#idents: raw.#idents?),*,valid_properties: valid, }) + } + + fn apply(&self, raw: &mut RawBlockStateProperties) { + #(raw.#idents.replace(self.#idents));*; + } + } + ) +} + +fn impl_getters_and_setters(name: &Ident, fields: &[Field]) -> TokenStream2 { + let mut getters_setters = Vec::new(); + for field in fields { + let field = field.to_owned(); + let ident = field.ident.unwrap(); + let ty = field.ty; + let set_ident = format_ident!("set_{}", ident); + let valid_ident = format_ident!("valid_{}", ident); + getters_setters.push(quote! { + pub fn #ident (&self) -> #ty { + self.#ident + } + + pub fn #set_ident (&mut self, value: #ty) -> bool { + if self.valid_properties.#ident.contains(&value) { + self.#ident = value; + true + } else { + false + } + } + + pub fn #valid_ident (&self) -> &[#ty] { + &self.valid_properties.#ident + } + }) + } + + quote! { + impl #name { + #(#getters_setters)* + } + } +} diff --git a/libcraft/particles/Cargo.toml b/libcraft/particles/Cargo.toml new file mode 100644 index 000000000..070038b74 --- /dev/null +++ b/libcraft/particles/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "libcraft-particles" +version = "0.1.0" +authors = ["Gijs de Jong <berichtaangijs@gmail.com>"] +edition = "2018" + +[dependencies] + +libcraft-blocks = { path = "../blocks"} +libcraft-items = { path = "../items" } +ordinalizer = "0.1.0" +bytemuck = { version = "1", features = ["derive"] } +num-derive = "0.3" +num-traits = "0.2" +serde = { version = "1", features = ["derive"] } \ No newline at end of file diff --git a/libcraft/particles/src/lib.rs b/libcraft/particles/src/lib.rs new file mode 100644 index 000000000..67b0a79a6 --- /dev/null +++ b/libcraft/particles/src/lib.rs @@ -0,0 +1,3 @@ +pub mod particle; + +pub use particle::{Particle, ParticleKind}; diff --git a/libcraft/particles/src/particle.rs b/libcraft/particles/src/particle.rs new file mode 100644 index 000000000..4e514fd4f --- /dev/null +++ b/libcraft/particles/src/particle.rs @@ -0,0 +1,349 @@ +use libcraft_blocks::BlockState; +use libcraft_items::Item; +use ordinalizer::Ordinal; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[repr(C)] +pub struct Particle { + pub kind: ParticleKind, + pub offset_x: f32, + pub offset_y: f32, + pub offset_z: f32, + pub count: i32, +} + +/// This is an enum over the kinds of particles +/// listed on [the Particle data type](https://wiki.vg/index.php?title=Protocol&oldid=16400#Particle). +/// Some particles are missing on that list (SoulFlame, Soul, BubblePop and the crying obsidian ones) +/// So they've been added +#[derive(Copy, Clone, Debug, PartialEq, Ordinal, Serialize, Deserialize)] +#[repr(C)] +pub enum ParticleKind { + AmbientEntityEffect, + AngryVillager, + Barrier, + /// Block break particles + Block(BlockState), + Bubble, + Cloud, + Crit, + DamageIndicator, + DragonBreath, + DrippingLava, + FallingLava, + LandingLava, + DrippingWater, + FallingWater, + Dust { + red: f32, + green: f32, + blue: f32, + /// Will be clamped between 0.01 and 4.0. + scale: f32, + }, + Effect, + ElderGuardian, + EnchantedHit, + Enchant, + EndRod, + EntityEffect, + ExplosionEmitter, + Explosion, + FallingDust(BlockState), + Firework, + Fishing, + Flame, + SoulFireFlame, + Soul, + Flash, + HappyVillager, + Composter, + Heart, + InstantEffect, + Item(Option<Item>), // TODO: Should be moved to Slot/ItemStack once it's done + ItemSlime, + ItemSnowball, + LargeSmoke, + Lava, + Mycelium, + Note, + Poof, + Portal, + Rain, + Smoke, + Sneeze, + Spit, + SquidInk, + SweepAttack, + TotemOfUndying, + Underwater, + Splash, + Witch, + BubblePop, + CurrentDown, + BubbleColumnUp, + Nautilus, + Dolphin, + CampfireCosySmoke, + CampfireSignalSmoke, + DrippingHoney, + FallingHoney, + LandingHoney, + FallingNectar, + Ash, + CrimsonSpore, + WarpedSpore, + DrippingObsidianTear, + FallingObsidianTear, + LandingObsidianTear, + ReversePortal, + WhiteAsh, +} + +impl ParticleKind { + /// Returns the `id` property of this `ParticleKind`. + pub fn id(&self) -> u32 { + match self { + ParticleKind::AmbientEntityEffect => 0, + ParticleKind::AngryVillager => 1, + ParticleKind::Barrier => 2, + ParticleKind::Block(_) => 3, + ParticleKind::Bubble => 4, + ParticleKind::Cloud => 5, + ParticleKind::Crit => 6, + ParticleKind::DamageIndicator => 7, + ParticleKind::DragonBreath => 8, + ParticleKind::DrippingLava => 9, + ParticleKind::FallingLava => 10, + ParticleKind::LandingLava => 11, + ParticleKind::DrippingWater => 12, + ParticleKind::FallingWater => 13, + ParticleKind::Dust { .. } => 14, + ParticleKind::Effect => 15, + ParticleKind::ElderGuardian => 16, + ParticleKind::EnchantedHit => 17, + ParticleKind::Enchant => 18, + ParticleKind::EndRod => 19, + ParticleKind::EntityEffect => 20, + ParticleKind::ExplosionEmitter => 21, + ParticleKind::Explosion => 22, + ParticleKind::FallingDust(_) => 23, + ParticleKind::Firework => 24, + ParticleKind::Fishing => 25, + ParticleKind::Flame => 26, + ParticleKind::SoulFireFlame => 27, + ParticleKind::Soul => 28, + ParticleKind::Flash => 29, + ParticleKind::HappyVillager => 30, + ParticleKind::Composter => 31, + ParticleKind::Heart => 32, + ParticleKind::InstantEffect => 33, + ParticleKind::Item(_) => 34, + ParticleKind::ItemSlime => 35, + ParticleKind::ItemSnowball => 36, + ParticleKind::LargeSmoke => 37, + ParticleKind::Lava => 38, + ParticleKind::Mycelium => 39, + ParticleKind::Note => 40, + ParticleKind::Poof => 41, + ParticleKind::Portal => 42, + ParticleKind::Rain => 43, + ParticleKind::Smoke => 44, + ParticleKind::Sneeze => 45, + ParticleKind::Spit => 46, + ParticleKind::SquidInk => 47, + ParticleKind::SweepAttack => 48, + ParticleKind::TotemOfUndying => 49, + ParticleKind::Underwater => 50, + ParticleKind::Splash => 51, + ParticleKind::Witch => 52, + ParticleKind::BubblePop => 53, + ParticleKind::CurrentDown => 54, + ParticleKind::BubbleColumnUp => 55, + ParticleKind::Nautilus => 56, + ParticleKind::Dolphin => 57, + ParticleKind::CampfireCosySmoke => 58, + ParticleKind::CampfireSignalSmoke => 59, + ParticleKind::DrippingHoney => 60, + ParticleKind::FallingHoney => 61, + ParticleKind::LandingHoney => 62, + ParticleKind::FallingNectar => 63, + ParticleKind::Ash => 64, + ParticleKind::CrimsonSpore => 65, + ParticleKind::WarpedSpore => 66, + ParticleKind::DrippingObsidianTear => 67, + ParticleKind::FallingObsidianTear => 68, + ParticleKind::LandingObsidianTear => 69, + ParticleKind::ReversePortal => 70, + ParticleKind::WhiteAsh => 71, + } + } + + /// Gets a `Particle` by its `id`. + /// + /// For kinds like `ParticleKind::Block` that require additional data, + /// this will return the "empty" variant. + pub fn from_id(id: u32) -> Option<Self> { + match id { + 0 => Some(ParticleKind::AmbientEntityEffect), + 1 => Some(ParticleKind::AngryVillager), + 2 => Some(ParticleKind::Barrier), + 3 => Some(ParticleKind::Block(BlockState::from_id(0).unwrap())), + 4 => Some(ParticleKind::Bubble), + 5 => Some(ParticleKind::Cloud), + 6 => Some(ParticleKind::Crit), + 7 => Some(ParticleKind::DamageIndicator), + 8 => Some(ParticleKind::DragonBreath), + 9 => Some(ParticleKind::DrippingLava), + 10 => Some(ParticleKind::FallingLava), + 11 => Some(ParticleKind::LandingLava), + 12 => Some(ParticleKind::DrippingWater), + 13 => Some(ParticleKind::FallingWater), + 14 => Some(ParticleKind::Dust { + red: 0.0, + blue: 0.0, + green: 0.0, + scale: 0.0, + }), + 15 => Some(ParticleKind::Effect), + 16 => Some(ParticleKind::ElderGuardian), + 17 => Some(ParticleKind::EnchantedHit), + 18 => Some(ParticleKind::Enchant), + 19 => Some(ParticleKind::EndRod), + 20 => Some(ParticleKind::EntityEffect), + 21 => Some(ParticleKind::ExplosionEmitter), + 22 => Some(ParticleKind::Explosion), + 23 => Some(ParticleKind::FallingDust(BlockState::from_id(0).unwrap())), + 24 => Some(ParticleKind::Firework), + 25 => Some(ParticleKind::Fishing), + 26 => Some(ParticleKind::Flame), + 27 => Some(ParticleKind::SoulFireFlame), + 28 => Some(ParticleKind::Soul), + 29 => Some(ParticleKind::Flash), + 30 => Some(ParticleKind::HappyVillager), + 31 => Some(ParticleKind::Composter), + 32 => Some(ParticleKind::Heart), + 33 => Some(ParticleKind::InstantEffect), + 34 => Some(ParticleKind::Item(None)), + 35 => Some(ParticleKind::ItemSlime), + 36 => Some(ParticleKind::ItemSnowball), + 37 => Some(ParticleKind::LargeSmoke), + 38 => Some(ParticleKind::Lava), + 39 => Some(ParticleKind::Mycelium), + 40 => Some(ParticleKind::Note), + 41 => Some(ParticleKind::Poof), + 42 => Some(ParticleKind::Portal), + 43 => Some(ParticleKind::Rain), + 44 => Some(ParticleKind::Smoke), + 45 => Some(ParticleKind::Sneeze), + 46 => Some(ParticleKind::Spit), + 47 => Some(ParticleKind::SquidInk), + 48 => Some(ParticleKind::SweepAttack), + 49 => Some(ParticleKind::TotemOfUndying), + 50 => Some(ParticleKind::Underwater), + 51 => Some(ParticleKind::Splash), + 52 => Some(ParticleKind::Witch), + 53 => Some(ParticleKind::BubblePop), + 54 => Some(ParticleKind::CurrentDown), + 55 => Some(ParticleKind::BubbleColumnUp), + 56 => Some(ParticleKind::Nautilus), + 57 => Some(ParticleKind::Dolphin), + 58 => Some(ParticleKind::CampfireCosySmoke), + 59 => Some(ParticleKind::CampfireSignalSmoke), + 60 => Some(ParticleKind::DrippingHoney), + 61 => Some(ParticleKind::FallingHoney), + 62 => Some(ParticleKind::LandingHoney), + 63 => Some(ParticleKind::FallingNectar), + 64 => Some(ParticleKind::Ash), + 65 => Some(ParticleKind::CrimsonSpore), + 66 => Some(ParticleKind::WarpedSpore), + 67 => Some(ParticleKind::DrippingObsidianTear), + 68 => Some(ParticleKind::FallingObsidianTear), + 69 => Some(ParticleKind::LandingObsidianTear), + 70 => Some(ParticleKind::ReversePortal), + 71 => Some(ParticleKind::WhiteAsh), + _ => None, + } + } +} + +impl ParticleKind { + /// Returns the `name` property of this `ParticleKind`. + pub fn name(&self) -> &'static str { + match self { + ParticleKind::AmbientEntityEffect => "ambient_entity_effect", + ParticleKind::AngryVillager => "angry_villager", + ParticleKind::Barrier => "barrier", + ParticleKind::Block(_) => "block", + ParticleKind::Bubble => "bubble", + ParticleKind::Cloud => "cloud", + ParticleKind::Crit => "crit", + ParticleKind::DamageIndicator => "damage_indicator", + ParticleKind::DragonBreath => "dragon_breath", + ParticleKind::DrippingLava => "dripping_lava", + ParticleKind::FallingLava => "falling_lava", + ParticleKind::LandingLava => "landing_lava", + ParticleKind::DrippingWater => "dripping_water", + ParticleKind::FallingWater => "falling_water", + ParticleKind::Dust { .. } => "dust", + ParticleKind::Effect => "effect", + ParticleKind::ElderGuardian => "elder_guardian", + ParticleKind::EnchantedHit => "enchanted_hit", + ParticleKind::Enchant => "enchant", + ParticleKind::EndRod => "end_rod", + ParticleKind::EntityEffect => "entity_effect", + ParticleKind::ExplosionEmitter => "explosion_emitter", + ParticleKind::Explosion => "explosion", + ParticleKind::FallingDust(_) => "falling_dust", + ParticleKind::Firework => "firework", + ParticleKind::Fishing => "fishing", + ParticleKind::Flame => "flame", + ParticleKind::SoulFireFlame => "soul_fire_flame", + ParticleKind::Soul => "soul", + ParticleKind::Flash => "flash", + ParticleKind::HappyVillager => "happy_villager", + ParticleKind::Composter => "composter", + ParticleKind::Heart => "heart", + ParticleKind::InstantEffect => "instant_effect", + ParticleKind::Item(_) => "item", + ParticleKind::ItemSlime => "item_slime", + ParticleKind::ItemSnowball => "item_snowball", + ParticleKind::LargeSmoke => "large_smoke", + ParticleKind::Lava => "lava", + ParticleKind::Mycelium => "mycelium", + ParticleKind::Note => "note", + ParticleKind::Poof => "poof", + ParticleKind::Portal => "portal", + ParticleKind::Rain => "rain", + ParticleKind::Smoke => "smoke", + ParticleKind::Sneeze => "sneeze", + ParticleKind::Spit => "spit", + ParticleKind::SquidInk => "squid_ink", + ParticleKind::SweepAttack => "sweep_attack", + ParticleKind::TotemOfUndying => "totem_of_undying", + ParticleKind::Underwater => "underwater", + ParticleKind::Splash => "splash", + ParticleKind::Witch => "witch", + ParticleKind::BubblePop => "bubble_pop", + ParticleKind::CurrentDown => "current_down", + ParticleKind::BubbleColumnUp => "bubble_column_up", + ParticleKind::Nautilus => "nautilus", + ParticleKind::Dolphin => "dolphin", + ParticleKind::CampfireCosySmoke => "campfire_cosy_smoke", + ParticleKind::CampfireSignalSmoke => "campfire_signal_smoke", + ParticleKind::DrippingHoney => "dripping_honey", + ParticleKind::FallingHoney => "falling_honey", + ParticleKind::LandingHoney => "landing_honey", + ParticleKind::FallingNectar => "falling_nectar", + ParticleKind::Ash => "ash", + ParticleKind::CrimsonSpore => "crimson_spore", + ParticleKind::WarpedSpore => "warped_spore", + ParticleKind::DrippingObsidianTear => "dripping_obsidian_tear", + ParticleKind::FallingObsidianTear => "falling_obsidian_tear", + ParticleKind::LandingObsidianTear => "landing_obsidian_tear", + ParticleKind::ReversePortal => "reverse_portal", + ParticleKind::WhiteAsh => "white_ash", + } + } +} diff --git a/libcraft/text/Cargo.toml b/libcraft/text/Cargo.toml new file mode 100644 index 000000000..b99bd785c --- /dev/null +++ b/libcraft/text/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "libcraft-text" +version = "0.1.0" +authors = ["Gijs de Jong <berichtaangijs@gmail.com>", "caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +hematite-nbt = { git = "https://github.com/PistonDevelopers/hematite_nbt" } +nom = "5" +nom_locate = "2" +serde = { version = "1", features = [ "derive" ] } +serde_json = "1" +serde_with = "1" +uuid = { version = "0.8", features = [ "serde" ] } +thiserror = "1" diff --git a/libcraft/text/src/lib.rs b/libcraft/text/src/lib.rs new file mode 100644 index 000000000..672851c8c --- /dev/null +++ b/libcraft/text/src/lib.rs @@ -0,0 +1,5 @@ +pub mod text; +pub mod title; + +pub use text::*; +pub use title::Title; diff --git a/libcraft/text/src/text.rs b/libcraft/text/src/text.rs new file mode 100644 index 000000000..90af776de --- /dev/null +++ b/libcraft/text/src/text.rs @@ -0,0 +1,1217 @@ +//! Implementation of the Minecraft chat component format. + +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use std::borrow::Cow; +use std::fmt::{self, Display, Formatter}; +use std::str::FromStr; +use uuid::Uuid; + +pub mod markdown; + +#[derive(Debug, thiserror::Error)] +pub enum TextConversionError { + #[error("'{0}' is not a recognized color")] + InvalidColor(String), + #[error("'{0}' is not a recognized style type")] + InvalidStyle(String), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Color { + DarkRed, + Red, + Gold, + Yellow, + DarkGreen, + Green, + Aqua, + DarkAqua, + DarkBlue, + Blue, + LightPurple, + DarkPurple, + White, + Gray, + DarkGray, + Black, + Custom(String), +} + +impl FromStr for Color { + type Err = TextConversionError; + + fn from_str(s: &str) -> Result<Self, TextConversionError> { + match s { + "dark_red" => Ok(Color::DarkRed), + "red" => Ok(Color::Red), + "gold" => Ok(Color::Gold), + "yellow" => Ok(Color::Yellow), + "dark_green" => Ok(Color::DarkGreen), + "green" => Ok(Color::Green), + "aqua" => Ok(Color::Aqua), + "dark_aqua" => Ok(Color::DarkAqua), + "dark_blue" => Ok(Color::DarkBlue), + "blue" => Ok(Color::Blue), + "light_purple" => Ok(Color::LightPurple), + "dark_purple" => Ok(Color::DarkPurple), + "white" => Ok(Color::White), + "gray" => Ok(Color::Gray), + "dark_gray" => Ok(Color::DarkGray), + "black" => Ok(Color::Black), + _ => Err(TextConversionError::InvalidColor(s.to_string())), + } + } +} + +impl From<Color> for Text { + fn from(color: Color) -> Self { + Text::empty().color(color) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Style { + Bold, + Italic, + Underlined, + Strikethrough, + Obfuscated, +} + +impl FromStr for Style { + type Err = TextConversionError; + + fn from_str(s: &str) -> Result<Self, TextConversionError> { + match s { + "bold" => Ok(Style::Bold), + "italic" => Ok(Style::Italic), + "underline" => Ok(Style::Underlined), + "strikethrough" => Ok(Style::Strikethrough), + "magic" => Ok(Style::Obfuscated), + _ => Err(TextConversionError::InvalidStyle(s.to_string())), + } + } +} + +impl From<Style> for Text { + fn from(style: Style) -> Self { + Text::empty().style(style) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +/// Represent all possible keybinds in vanilla. +pub enum Keybind { + Attack, + UseItem, + Forward, + Left, + Back, + Right, + Jump, + Sneak, + Sprint, + Drop, + Inventory, + Chat, + ListPlayers, + PickBlock, + Command, + Screenshot, + Perspective, + MouseSmoothing, + Fullscreen, + SpectatorOutlines, + SwapHands, + SaveToolbar, + LoadToolbar, + Advancements, + Hotbar1, + Hotbar2, + Hotbar3, + Hotbar4, + Hotbar5, + Hotbar6, + Hotbar7, + Hotbar8, + Hotbar9, + Custom(Cow<'static, str>), +} + +impl From<Keybind> for Text { + fn from(keybind: Keybind) -> Self { + Text::keybind(keybind) + } +} + +impl Serialize for Keybind { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_str(String::from(self).as_ref()) + } +} + +impl<'de> Deserialize<'de> for Keybind { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Ok(Keybind::from(s)) + } +} + +impl<T> From<T> for Keybind +where + T: Into<Cow<'static, str>>, +{ + fn from(keybind: T) -> Self { + let keybind = keybind.into(); + match keybind.as_ref() { + "key_key.attack" => Keybind::Attack, + "key_key.use" => Keybind::UseItem, + "key_key.forward" => Keybind::Forward, + "key_key.left" => Keybind::Left, + "key_key.back" => Keybind::Back, + "key_key.right" => Keybind::Right, + "key_key.jump" => Keybind::Jump, + "key_key.sneak" => Keybind::Sneak, + "key_key.sprint" => Keybind::Sprint, + "key_key.drop" => Keybind::Drop, + "key_key.inventory" => Keybind::Inventory, + "key_key.chat" => Keybind::Chat, + "key_key.playerlist" => Keybind::ListPlayers, + "key_key.pickItem" => Keybind::PickBlock, + "key_key.command" => Keybind::Command, + "key_key.screenshot" => Keybind::Screenshot, + "key_key.togglePerspective" => Keybind::Perspective, + "key_key.smoothCamera" => Keybind::MouseSmoothing, + "key_key.fullscreen" => Keybind::Fullscreen, + "key_key.spectatorOutlines" => Keybind::SpectatorOutlines, + "key_key.swapHands" => Keybind::SwapHands, + "key_key.saveToolbarActivator" => Keybind::SaveToolbar, + "key_key.loadToolbarActivator" => Keybind::LoadToolbar, + "key_key.advancements" => Keybind::Advancements, + "key_key.hotbar.1" => Keybind::Hotbar1, + "key_key.hotbar.2" => Keybind::Hotbar2, + "key_key.hotbar.3" => Keybind::Hotbar3, + "key_key.hotbar.4" => Keybind::Hotbar4, + "key_key.hotbar.5" => Keybind::Hotbar5, + "key_key.hotbar.6" => Keybind::Hotbar6, + "key_key.hotbar.7" => Keybind::Hotbar7, + "key_key.hotbar.8" => Keybind::Hotbar8, + "key_key.hotbar.9" => Keybind::Hotbar9, + _ => Keybind::Custom(keybind), + } + } +} + +impl From<&Keybind> for String { + fn from(keybind: &Keybind) -> Self { + match keybind { + Keybind::Attack => "key_key.attack", + Keybind::UseItem => "key_key.use", + Keybind::Forward => "key_key.forward", + Keybind::Left => "key_key.left", + Keybind::Back => "key_key.back", + Keybind::Right => "key_key.right", + Keybind::Jump => "key_key.jump", + Keybind::Sneak => "key_key.sneak", + Keybind::Sprint => "key_key.sprint", + Keybind::Drop => "key_key.drop", + Keybind::Inventory => "key_key.inventory", + Keybind::Chat => "key_key.chat", + Keybind::ListPlayers => "key_key.playerlist", + Keybind::PickBlock => "key_key.pickItem", + Keybind::Command => "key_key.command", + Keybind::Screenshot => "key_key.screenshot", + Keybind::Perspective => "key_key.togglePerspective", + Keybind::MouseSmoothing => "key_key.smoothCamera", + Keybind::Fullscreen => "key_key.fullscreen", + Keybind::SpectatorOutlines => "key_key.spectatorOutlines", + Keybind::SwapHands => "key_key.swapHands", + Keybind::SaveToolbar => "key_key.saveToolbarActivator", + Keybind::LoadToolbar => "key_key.loadToolbarActivator", + Keybind::Advancements => "key_key.advancements", + Keybind::Hotbar1 => "key_key.hotbar.1", + Keybind::Hotbar2 => "key_key.hotbar.2", + Keybind::Hotbar3 => "key_key.hotbar.3", + Keybind::Hotbar4 => "key_key.hotbar.4", + Keybind::Hotbar5 => "key_key.hotbar.5", + Keybind::Hotbar6 => "key_key.hotbar.6", + Keybind::Hotbar7 => "key_key.hotbar.7", + Keybind::Hotbar8 => "key_key.hotbar.8", + Keybind::Hotbar9 => "key_key.hotbar.9", + Keybind::Custom(bind) => bind.as_ref(), + } + .into() + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +/// Represent all possible translation keys in vanilla. +pub enum Translate { + ChatTypeText, + MultiplayerPlayerJoined, + Custom(Cow<'static, str>), +} + +impl Serialize for Translate { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_str(String::from(self).as_ref()) + } +} + +impl<'de> Deserialize<'de> for Translate { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Ok(Translate::from(s)) + } +} + +impl<T> std::ops::Mul<T> for Translate +where + T: IntoIterator, + T::Item: Into<Text>, +{ + type Output = Text; + fn mul(self, rhs: T) -> Text { + Text::translate_with(self, rhs) + } +} + +impl<T> From<T> for Translate +where + T: Into<Cow<'static, str>>, +{ + fn from(value: T) -> Translate { + let value = value.into(); + match value.as_ref() { + "chat.type.text" => Translate::ChatTypeText, + "multiplayer.player.joined" => Translate::MultiplayerPlayerJoined, + _ => Translate::Custom(value), + } + } +} + +impl<'a> From<&Translate> for String { + fn from(translate: &Translate) -> Self { + match translate { + Translate::ChatTypeText => "chat.type.text", + Translate::MultiplayerPlayerJoined => "multiplayer.player.joined", + Translate::Custom(key) => key.as_ref(), + } + .into() + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "action", content = "value", rename_all = "snake_case")] +// TODO: Accept any json primitive as string +pub enum Click { + OpenUrl(Cow<'static, str>), + OpenFile(Cow<'static, str>), + RunCommand(Cow<'static, str>), + ChangePage(i32), + SuggestCommand(Cow<'static, str>), + CopyToClipboard(Cow<'static, str>), +} + +#[serde_with::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Entity { + id: Uuid, + ty: Option<Cow<'static, str>>, + name: Cow<'static, str>, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(tag = "action", content = "value")] +// TODO: Accept any json primitive as string +pub enum Hover { + #[serde(rename = "show_text")] + ShowText(Box<Text>), + #[serde(rename = "show_item")] + // TODO: Item struct + ShowItem(String), + #[serde(rename = "show_entity")] + ShowEntity(Entity), +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +/// Text component can either be Text, Translate, Score, Selector, Keybind, or Nbt. +pub enum TextValue { + Text { + text: Cow<'static, str>, + }, + Translate { + translate: Translate, + with: Vec<Text>, + }, + Score { + name: Cow<'static, str>, + objective: Cow<'static, str>, + value: Option<Cow<'static, str>>, + }, + Selector { + selector: Cow<'static, str>, + }, + Keybind { + keybind: Keybind, + }, + Nbt { + nbt: nbt::Blob, + }, +} + +impl<T> From<T> for TextValue +where + T: Into<Cow<'static, str>>, +{ + fn from(value: T) -> Self { + Self::text(value.into()) + } +} + +impl TextValue { + pub fn text<T: Into<Cow<'static, str>>>(text: T) -> Self { + TextValue::Text { text: text.into() } + } + + pub fn translate<A>(translate: A) -> Self + where + A: Into<Translate>, + { + TextValue::Translate { + translate: translate.into(), + with: Default::default(), + } + } + + pub fn translate_with<A, B>(translate: A, with: B) -> Self + where + A: Into<Translate>, + B: IntoIterator, + B::Item: Into<Text>, + { + let with = with.into_iter().map(|e| e.into()).collect(); + TextValue::Translate { + translate: translate.into(), + with, + } + } + + pub fn score< + A: Into<Cow<'static, str>>, + B: Into<Cow<'static, str>>, + C: Into<Cow<'static, str>>, + >( + name: A, + objective: B, + value: Option<C>, + ) -> Self { + TextValue::Score { + name: name.into(), + objective: objective.into(), + value: value.map(|v| v.into()), + } + } + + pub fn keybind<A: Into<Keybind>>(keybind: A) -> Self { + TextValue::Keybind { + keybind: keybind.into(), + } + } + + pub fn nbt<A: Into<nbt::Blob>>(nbt: A) -> Self { + TextValue::Nbt { nbt: nbt.into() } + } +} + +#[serde_with::skip_serializing_none] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +/// Text json object that holds all styles. +pub struct TextComponent { + #[serde(flatten)] + value: TextValue, + color: Option<Color>, + bold: Option<bool>, + italic: Option<bool>, + underlined: Option<bool>, + strikethrough: Option<bool>, + obfuscated: Option<bool>, + insertion: Option<Cow<'static, str>>, + #[serde(rename = "clickEvent")] + click: Option<Click>, + #[serde(rename = "hoverEvent")] + hover: Option<Hover>, + extra: Option<Vec<Text>>, +} + +impl Default for TextComponent { + fn default() -> Self { + Self::empty() + } +} + +pub trait IntoTextComponent { + fn into_component(self) -> TextComponent; +} + +impl TextComponent { + pub fn empty() -> TextComponent { + TextComponent::from("") + } +} + +pub enum Reset { + Color, + Style, + Insertion, + OnClick, + OnHover, +} + +/// Text component interface. +pub trait TextComponentBuilder { + /// Sets the given style to either None, true, or false. + fn set_style(self, style: Style, value: Option<bool>) -> Self; + + /// Applies the given style. + fn style(self, style: Style) -> Self; + fn bold(self) -> Self; + fn italic(self) -> Self; + fn obfuscated(self) -> Self; + fn strikethrough(self) -> Self; + fn underlined(self) -> Self; + + /// Removes the given style. + fn not_style(self, style: Style) -> Self; + fn not_bold(self) -> Self; + fn not_italic(self) -> Self; + fn not_obfuscated(self) -> Self; + fn not_strikethrough(self) -> Self; + fn not_underlined(self) -> Self; + + /// Resets the given style; the parent's color will be inherited. + fn reset_style(self, style: Style) -> Self; + fn reset_bold(self) -> Self; + fn reset_italic(self) -> Self; + fn reset_obfuscated(self) -> Self; + fn reset_strikethrough(self) -> Self; + fn reset_underlined(self) -> Self; + fn reset_style_all(self) -> Self; + + /// Aplies the given color. + fn color(self, color: Color) -> Self; + fn dark_red(self) -> Self; + fn red(self) -> Self; + fn gold(self) -> Self; + fn yellow(self) -> Self; + fn dark_green(self) -> Self; + fn green(self) -> Self; + fn aqua(self) -> Self; + fn dark_aqua(self) -> Self; + fn dark_blue(self) -> Self; + fn blue(self) -> Self; + fn light_purple(self) -> Self; + fn dark_purple(self) -> Self; + fn white(self) -> Self; + fn gray(self) -> Self; + fn dark_gray(self) -> Self; + fn black(self) -> Self; + + /// Resets the given color; the parent's color will be inherited. + fn reset_color(self) -> Self; + + /// Inserts the given text into the chat, when shift is held and clicked. + /// Only useable for messages in chat. + fn insertion<A: Into<Cow<'static, str>>>(self, insertion: A) -> Self; + + /// Resets the insertions. + fn reset_insertion(self) -> Self; + + fn on_click(self, click: Click) -> Self; + fn on_click_change_page(self, page: i32) -> Self; + fn on_click_copy_to_clipboard<A: Into<Cow<'static, str>>>(self, to_copy: A) -> Self; + /// Can only be used on the client. + fn on_click_open_file<A: Into<Cow<'static, str>>>(self, path: A) -> Self; + fn on_click_open_url<A: Into<Cow<'static, str>>>(self, url: A) -> Self; + fn on_click_run_command<A: Into<Cow<'static, str>>>(self, command: A) -> Self; + /// Only useable for messages in chat. + fn on_click_suggest_command<A: Into<Cow<'static, str>>>(self, command: A) -> Self; + + fn reset_on_click(self) -> Self; + + fn on_hover(self, hover: Hover) -> Self; + fn on_hover_show_entity<A: Into<Entity>>(self, entity: A) -> Self; + fn on_hover_show_item(self, item: String) -> Self; + fn on_hover_show_text<A: Into<Text>>(self, text: A) -> Self; + + fn reset_on_hover(self) -> Self; + + /// Inherited Text; they will inherent the parent's style, color, insertion, on_click, and on_hover. + fn extra<A>(self, extra: A) -> Self + where + A: IntoIterator, + A::Item: Into<Text>; + fn push_extra<A: Into<Text>>(self, extra: A) -> Self; + + fn reset_extra(self) -> Self; + + /// Will inherent the parent's style, color, insertion, on_click, and on_hover. + fn reset_all(self) -> Self; + + /// Aplies the given reset + fn reset(self, reset: Reset) -> Self; +} + +impl IntoTextComponent for TextComponent { + fn into_component(self) -> TextComponent { + self + } +} + +impl<T> TextComponentBuilder for T +where + T: IntoTextComponent + From<TextComponent>, +{ + fn set_style(self, style: Style, value: Option<bool>) -> Self { + let mut component = self.into_component(); + match style { + Style::Bold => component.bold = value, + Style::Italic => component.italic = value, + Style::Obfuscated => component.obfuscated = value, + Style::Strikethrough => component.strikethrough = value, + Style::Underlined => component.underlined = value, + }; + component.into() + } + + fn style(self, style: Style) -> Self { + self.set_style(style, Some(true)) + } + + fn bold(self) -> Self { + self.style(Style::Bold) + } + + fn italic(self) -> Self { + self.style(Style::Italic) + } + + fn obfuscated(self) -> Self { + self.style(Style::Obfuscated) + } + + fn strikethrough(self) -> Self { + self.style(Style::Strikethrough) + } + + fn underlined(self) -> Self { + self.style(Style::Underlined) + } + + fn not_style(self, style: Style) -> Self { + self.set_style(style, None) + } + + fn not_bold(self) -> Self { + self.style(Style::Bold) + } + + fn not_italic(self) -> Self { + self.style(Style::Italic) + } + + fn not_obfuscated(self) -> Self { + self.style(Style::Obfuscated) + } + + fn not_strikethrough(self) -> Self { + self.style(Style::Strikethrough) + } + + fn not_underlined(self) -> Self { + self.style(Style::Underlined) + } + + fn reset_style(self, style: Style) -> Self { + self.set_style(style, None) + } + + fn reset_bold(self) -> Self { + self.style(Style::Bold) + } + + fn reset_italic(self) -> Self { + self.style(Style::Italic) + } + + fn reset_obfuscated(self) -> Self { + self.style(Style::Obfuscated) + } + + fn reset_strikethrough(self) -> Self { + self.style(Style::Strikethrough) + } + + fn reset_underlined(self) -> Self { + self.style(Style::Underlined) + } + + fn reset_style_all(self) -> Self { + let mut component = self.into_component(); + component.bold = None; + component.italic = None; + component.obfuscated = None; + component.strikethrough = None; + component.underlined = None; + component.into() + } + + fn color(self, color: Color) -> Self { + let mut component = self.into_component(); + component.color = Some(color); + component.into() + } + + fn dark_red(self) -> Self { + self.color(Color::DarkRed) + } + + fn red(self) -> Self { + self.color(Color::Red) + } + + fn gold(self) -> Self { + self.color(Color::Gold) + } + + fn yellow(self) -> Self { + self.color(Color::Yellow) + } + + fn dark_green(self) -> Self { + self.color(Color::DarkGreen) + } + + fn green(self) -> Self { + self.color(Color::Green) + } + + fn aqua(self) -> Self { + self.color(Color::Aqua) + } + + fn dark_aqua(self) -> Self { + self.color(Color::DarkAqua) + } + + fn dark_blue(self) -> Self { + self.color(Color::DarkBlue) + } + + fn blue(self) -> Self { + self.color(Color::Blue) + } + + fn light_purple(self) -> Self { + self.color(Color::LightPurple) + } + + fn dark_purple(self) -> Self { + self.color(Color::DarkPurple) + } + + fn white(self) -> Self { + self.color(Color::White) + } + + fn gray(self) -> Self { + self.color(Color::Gray) + } + + fn dark_gray(self) -> Self { + self.color(Color::DarkGray) + } + + fn black(self) -> Self { + self.color(Color::Black) + } + + fn reset_color(self) -> Self { + let mut component = self.into_component(); + component.color = None; + component.into() + } + + fn insertion<A: Into<Cow<'static, str>>>(self, insertion: A) -> Self { + let mut component = self.into_component(); + component.insertion = Some(insertion.into()); + component.into() + } + + fn reset_insertion(self) -> Self { + let mut component = self.into_component(); + component.insertion = None; + component.into() + } + + fn on_click(self, click: Click) -> Self { + let mut component = self.into_component(); + component.click = Some(click); + component.into() + } + + fn on_click_change_page(self, page: i32) -> Self { + self.on_click(Click::ChangePage(page)) + } + + fn on_click_copy_to_clipboard<A: Into<Cow<'static, str>>>(self, to_copy: A) -> Self { + self.on_click(Click::CopyToClipboard(to_copy.into())) + } + + fn on_click_open_file<A: Into<Cow<'static, str>>>(self, path: A) -> Self { + self.on_click(Click::OpenFile(path.into())) + } + + fn on_click_open_url<A: Into<Cow<'static, str>>>(self, url: A) -> Self { + self.on_click(Click::OpenUrl(url.into())) + } + + fn on_click_run_command<A: Into<Cow<'static, str>>>(self, command: A) -> Self { + self.on_click(Click::RunCommand(command.into())) + } + fn on_click_suggest_command<A: Into<Cow<'static, str>>>(self, command: A) -> Self { + self.on_click(Click::SuggestCommand(command.into())) + } + + fn reset_on_click(self) -> Self { + let mut component = self.into_component(); + component.click = None; + component.into() + } + + fn on_hover(self, hover: Hover) -> Self { + let mut component = self.into_component(); + component.hover = Some(hover); + component.into() + } + + fn on_hover_show_entity<A: Into<Entity>>(self, entity: A) -> Self { + self.on_hover(Hover::ShowEntity(entity.into())) + } + + fn on_hover_show_item(self, item: String) -> Self { + self.on_hover(Hover::ShowItem(item)) + } + + fn on_hover_show_text<A: Into<Text>>(self, text: A) -> Self { + self.on_hover(Hover::ShowText(Box::new(text.into()))) + } + + fn reset_on_hover(self) -> Self { + let mut component = self.into_component(); + component.hover = None; + component.into() + } + + fn extra<A>(self, extra: A) -> Self + where + A: IntoIterator, + A::Item: Into<Text>, + { + let mut component = self.into_component(); + component.extra = Some(extra.into_iter().map(|e| e.into()).collect()); + component.into() + } + + fn push_extra<A: Into<Text>>(self, extra: A) -> Self { + let mut component = self.into_component(); + match component.extra { + Some(ref mut extras) => extras.push(extra.into()), + None => component.extra = Some(vec![extra.into()]), + }; + component.into() + } + + fn reset_extra(self) -> Self { + let mut component = self.into_component(); + component.extra = None; + component.into() + } + + fn reset_all(self) -> Self { + let mut component = self.into_component(); + component.color = None; + component.bold = None; + component.italic = None; + component.underlined = None; + component.strikethrough = None; + component.obfuscated = None; + component.insertion = None; + component.click = None; + component.hover = None; + component.extra = None; + component.into() + } + + fn reset(self, reset: Reset) -> Self { + match reset { + Reset::Color => self.reset_color(), + Reset::Insertion => self.reset_insertion(), + Reset::OnClick => self.reset_on_click(), + Reset::OnHover => self.reset_on_hover(), + Reset::Style => self.reset_style_all(), + } + } +} + +impl<T> From<T> for TextComponent +where + T: Into<TextValue>, +{ + fn from(value: T) -> Self { + TextComponent { + value: value.into(), + color: None, + bold: None, + italic: None, + underlined: None, + strikethrough: None, + obfuscated: None, + insertion: None, + click: None, + hover: None, + extra: None, + } + } +} + +impl From<Text> for TextComponent { + fn from(value: Text) -> Self { + match value { + Text::String(s) => TextComponent::from(s), + Text::Component(c) => *c, + Text::Array(arr) => TextComponent::from("").extra(arr), + } + } +} + +/// Text can either be a json String, Object, or an Array. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum Text { + String(Cow<'static, str>), + Array(Vec<Text>), + Component(Box<TextComponent>), +} + +impl IntoTextComponent for Text { + fn into_component(self) -> TextComponent { + match self { + Text::Component(c) => *c, + Text::String(text) => TextComponent::from(text), + Text::Array(arr) => TextComponent::empty().extra(arr), + } + } +} + +impl Text { + pub fn empty() -> Self { + Self::from("") + } + + pub fn of<A: Into<Cow<'static, str>>>(text: A) -> Self { + Text::from(text) + } + + pub fn translate_with<A, B>(translate: A, with: B) -> Self + where + A: Into<Translate>, + B: IntoIterator, + B::Item: Into<Text>, + { + Text::from(TextValue::translate_with(translate, with)) + } + + pub fn score< + A: Into<Cow<'static, str>>, + B: Into<Cow<'static, str>>, + C: Into<Cow<'static, str>>, + >( + name: A, + objective: B, + value: Option<C>, + ) -> Text { + Text::from(TextValue::score(name, objective, value)) + } + + pub fn keybind<A: Into<Keybind>>(keybind: A) -> Text { + Text::from(TextValue::keybind(keybind)) + } + + pub fn nbt<A: Into<nbt::Blob>>(nbt: A) -> Text { + Text::from(TextValue::nbt(nbt)) + } +} + +impl From<Text> for String { + fn from(text: Text) -> Self { + TextRoot(text).into() + } +} + +impl Display for Text { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.write_str(&serde_json::to_string(self).unwrap()) + } +} + +impl From<TextComponent> for Text { + fn from(component: TextComponent) -> Self { + Text::Component(Box::new(component)) + } +} + +impl From<TextValue> for Text { + fn from(value: TextValue) -> Self { + Text::from(TextComponent::from(value)) + } +} + +impl<T> From<T> for Text +where + T: Into<Cow<'static, str>>, +{ + fn from(value: T) -> Self { + Text::String(value.into()) + } +} + +impl std::ops::Add<TextComponent> for Text { + type Output = Text; + fn add(self, rhs: TextComponent) -> Text { + self + Text::from(rhs) + } +} + +impl std::ops::Add<Text> for Text { + type Output = Text; + fn add(mut self, rhs: Text) -> Text { + match self { + s @ Text::String(_) => Text::Array(vec![s, rhs]), + c @ Text::Component(_) => Text::Array(vec![Text::empty(), c, rhs]), + Text::Array(ref mut inner) => { + inner.push(rhs); + self + } + } + } +} + +/// A `Deserialize` impl for `Text` which uses the text markdown format. +pub fn deserialize_text<'de, D>(deserializer: D) -> Result<Text, D::Error> +where + D: Deserializer<'de>, +{ + let string = String::deserialize(deserializer)?; + + let component = markdown::translator::translate_text(&string) + .map_err(|e| de::Error::custom(e.to_string()))?; + Ok(Text::Component(Box::new(component))) +} + +/// Ensures Text is either an Array or Object. +/// This is required at some places when sending to the client. +pub struct TextRoot(Text); + +impl From<TextRoot> for String { + fn from(text: TextRoot) -> String { + text.0.to_string() + } +} + +impl<T> From<T> for TextRoot +where + T: Into<Text>, +{ + fn from(text: T) -> Self { + match text.into() { + s @ Text::String(_) => TextRoot(s.into_component().into()), + c @ Text::Component(_) => TextRoot(c), + Text::Array(arr) if arr.is_empty() => TextRoot(Text::empty()), + arr @ Text::Array(_) => TextRoot(arr), + } + } +} + +impl IntoTextComponent for TextRoot { + fn into_component(self) -> TextComponent { + self.0.into_component() + } +} + +macro_rules! impl_operators { + ($ty:ident) => { + impl std::ops::Mul<Color> for $ty { + type Output = Self; + fn mul(self, rhs: Color) -> Self { + self.color(rhs) + } + } + + impl std::ops::Mul<Style> for $ty { + type Output = Self; + fn mul(self, rhs: Style) -> Self { + self.style(rhs) + } + } + + impl std::ops::Div<Style> for $ty { + type Output = Self; + fn div(self, rhs: Style) -> Self { + self.not_style(rhs) + } + } + + impl std::ops::Div<Reset> for $ty { + type Output = Self; + fn div(self, rhs: Reset) -> Self { + self.reset(rhs) + } + } + }; + ($($ty:ident),+) => { + $( + impl_operators!($ty); + )+ + } +} + +impl_operators!(TextRoot, Text, TextComponent); + +#[cfg(test)] +mod tests { + use super::*; + use std::error::Error; + + #[test] + pub fn text_text_single() -> Result<(), Box<dyn Error>> { + let text_orignal: Text = Text::from("hello"); + + let text_json = serde_json::to_string(&text_orignal)?; + + assert_eq!(&text_json, r#""hello""#); + + let text: Text = serde_json::from_str(&text_json)?; + assert_eq!(text_orignal, text); + + Ok(()) + } + + #[test] + fn text_text_array() -> Result<(), Box<dyn Error>> { + let text_orignal = Text::from("hello") + Text::from(" ") + Text::from("world!"); + + let text_json = serde_json::to_string(&text_orignal)?; + + assert_eq!(&text_json, r#"["hello"," ","world!"]"#); + + let text: Text = serde_json::from_str(&text_json)?; + assert_eq!(text_orignal, text); + + Ok(()) + } + + #[test] + fn text_text_color() -> Result<(), Box<dyn Error>> { + let text_original: Text = Text::from("hello world") * Color::DarkRed; + + let text_json = serde_json::to_string(&text_original)?; + + assert_eq!(&text_json, r#"{"text":"hello world","color":"dark_red"}"#); + + let text: Text = serde_json::from_str(&text_json)?; + assert_eq!(text_original, text); + + Ok(()) + } + + #[test] + fn text_hello_space_world() -> Result<(), Box<dyn Error>> { + let hello: Text = Text::from("hello") * Color::Red * Style::Italic * Style::Bold; + let space: Text = Text::from(" "); + let world: Text = Text::from("world") * Color::Blue * Style::Bold; + let hello_space_world: Text = hello + space + world; + + let text_json = serde_json::to_string(&hello_space_world)?; + + assert_eq!( + text_json, + r#"["",{"text":"hello","color":"red","bold":true,"italic":true}," ",{"text":"world","color":"blue","bold":true}]"# + ); + + Ok(()) + } + + #[test] + fn text_translate() -> Result<(), Box<dyn Error>> { + let join = + Translate::from("multiplayer.player.joined") * vec!["The_Defman"] * Color::Yellow; + + let text_json = serde_json::to_string(&join)?; + + assert_eq!( + text_json, + r#"{"translate":"multiplayer.player.joined","with":["The_Defman"],"color":"yellow"}"# + ); + + let join = Translate::MultiplayerPlayerJoined * vec!["The_Defman"] * Color::Yellow; + + let text_json = serde_json::to_string(&join)?; + + assert_eq!( + text_json, + r#"{"translate":"multiplayer.player.joined","with":["The_Defman"],"color":"yellow"}"# + ); + + Ok(()) + } + + #[test] + fn text_root() { + let hello = Text::from("hello"); + + let root = TextRoot::from(hello); + + let root_json = String::from(root); + + assert_eq!(root_json, r#"{"text":"hello"}"#); + } + + #[test] + fn text_hover_and_click() -> Result<(), Box<dyn Error>> { + let text = Text::from("hello") + .on_hover_show_text("hover") + .on_click_run_command("/say hello"); + assert_eq!( + serde_json::to_string(&text)?, + r#"{"text":"hello","clickEvent":{"action":"run_command","value":"/say hello"},"hoverEvent":{"action":"show_text","value":"hover"}}"# + ); + + Ok(()) + } +} diff --git a/libcraft/text/src/text/markdown.rs b/libcraft/text/src/text/markdown.rs new file mode 100644 index 000000000..6c0acc909 --- /dev/null +++ b/libcraft/text/src/text/markdown.rs @@ -0,0 +1,6 @@ +mod lexer; +mod parser; +pub mod translator; + +pub(crate) use self::lexer::{lex_input, LexToken, LexTokenType, Span, Tokens}; +pub(crate) use self::parser::{events, parse_tokens, Token, TokenType}; diff --git a/libcraft/text/src/text/markdown/lexer.rs b/libcraft/text/src/text/markdown/lexer.rs new file mode 100644 index 000000000..27e003e3b --- /dev/null +++ b/libcraft/text/src/text/markdown/lexer.rs @@ -0,0 +1,255 @@ +use nom::branch::*; +use nom::bytes::complete::*; +use nom::character::complete::*; +use nom::combinator::*; +use nom::error::VerboseError; +use nom::multi::*; +use nom::sequence::*; +use nom::{IResult, InputIter, InputLength, InputTake, Slice}; +use nom_locate::*; +use std::iter::Enumerate; +use std::ops::{Range, RangeFrom, RangeFull, RangeTo}; +use std::slice::Iter; + +pub type Span<'a> = LocatedSpan<&'a str>; + +#[derive(Debug, PartialEq, Clone)] +pub struct LexToken<'a> { + pub tok: LexTokenType<'a>, + pub span: Span<'a>, +} + +impl<'a> LexToken<'a> { + pub fn new(span: Span<'a>, tok: LexTokenType<'a>) -> LexToken<'a> { + LexToken { tok, span } + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum LexTokenType<'a> { + ControlWordStarter, + LBrace, + RBrace, + Space(&'a str), + Word(&'a str), +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct Tokens<'a> { + pub tok: &'a [LexToken<'a>], + start: usize, + end: usize, +} + +impl<'a> Tokens<'a> { + #[allow(clippy::ptr_arg)] + pub fn new(vec: &'a Vec<LexToken<'a>>) -> Tokens<'a> { + Tokens { + tok: &vec[..], + start: 0, + end: vec.len(), + } + } +} + +impl<'a> InputLength for Tokens<'a> { + fn input_len(&self) -> usize { + self.tok.len() + } +} + +impl<'a> InputTake for Tokens<'a> { + fn take(&self, count: usize) -> Self { + Tokens { + tok: &self.tok[..count], + start: 0, + end: count, + } + } + + fn take_split(&self, count: usize) -> (Self, Self) { + let (prefix, suffix) = self.tok.split_at(count); + let first = Tokens { + tok: prefix, + start: 0, + end: prefix.len(), + }; + let second = Tokens { + tok: suffix, + start: 0, + end: suffix.len(), + }; + + (second, first) + } +} + +impl<'a> InputLength for LexToken<'a> { + fn input_len(&self) -> usize { + 1 + } +} + +impl<'a> Slice<Range<usize>> for Tokens<'a> { + fn slice(&self, range: Range<usize>) -> Self { + Tokens { + tok: &self.tok[range.clone()], + start: self.start + range.start, + end: self.end + range.end, + } + } +} + +impl<'a> Slice<RangeTo<usize>> for Tokens<'a> { + fn slice(&self, range: RangeTo<usize>) -> Self { + self.slice(0..range.end) + } +} + +impl<'a> Slice<RangeFrom<usize>> for Tokens<'a> { + fn slice(&self, range: RangeFrom<usize>) -> Self { + self.slice(range.start..self.end - self.start) + } +} + +impl<'a> Slice<RangeFull> for Tokens<'a> { + fn slice(&self, _: RangeFull) -> Self { + Tokens { + tok: self.tok, + start: self.start, + end: self.end, + } + } +} + +impl<'a> InputIter for Tokens<'a> { + type Item = &'a LexToken<'a>; + type Iter = Enumerate<Iter<'a, LexToken<'a>>>; + type IterElem = Iter<'a, LexToken<'a>>; + + fn iter_indices(&self) -> Self::Iter { + self.tok.iter().enumerate() + } + + fn iter_elements(&self) -> Self::IterElem { + self.tok.iter() + } + + fn position<P>(&self, predicate: P) -> Option<usize> + where + P: Fn(Self::Item) -> bool, + { + self.tok.iter().position(predicate) + } + + fn slice_index(&self, count: usize) -> Option<usize> { + if self.tok.len() >= count { + Some(count) + } else { + None + } + } +} + +pub fn lex_control_word(input: Span) -> IResult<Span, LexToken, VerboseError<Span>> { + map(tag("@"), |pos| { + LexToken::new(pos, LexTokenType::ControlWordStarter) + })(input) +} + +pub fn lex_spaces(input: Span) -> IResult<Span, LexToken, VerboseError<Span>> { + map(space1, |s: Span| { + LexToken::new(s, LexTokenType::Space(*s.fragment())) + })(input) +} + +pub fn valid_word(input: Span) -> IResult<Span, Span, VerboseError<Span>> { + use nom::{AsChar, InputTakeAtPosition}; + input.split_at_position1_complete( + |item| !item.is_alphanum() && item.as_char() != '_', + nom::error::ErrorKind::AlphaNumeric, + ) +} + +pub fn lex_word(input: Span) -> IResult<Span, LexToken, VerboseError<Span>> { + map(valid_word, |s: Span| { + LexToken::new(s, LexTokenType::Word(*s.fragment())) + })(input) +} + +pub fn lex_color_code(input: Span) -> IResult<Span, LexToken, VerboseError<Span>> { + map(preceded(peek(tag("#")), take(7usize)), |code: Span| { + LexToken::new(code, LexTokenType::Word(*code.fragment())) + })(input) +} + +pub fn lex_brace(input: Span) -> IResult<Span, LexToken, VerboseError<Span>> { + alt(( + map(tag("{"), |pos| LexToken::new(pos, LexTokenType::LBrace)), + map(tag("}"), |pos| LexToken::new(pos, LexTokenType::RBrace)), + ))(input) +} + +pub fn lex_input(input: Span) -> IResult<Span, Vec<LexToken>, VerboseError<Span>> { + many1(alt(( + lex_control_word, + lex_brace, + lex_word, + lex_color_code, + lex_spaces, + )))(input) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_input() { + let input = Span::new( + "@red red text @bold {Some bold text too} more text @color #00FF00 green text", + ); + + let expected = vec![ + LexTokenType::ControlWordStarter, + LexTokenType::Word("red"), + LexTokenType::Space(" "), + LexTokenType::Word("red"), + LexTokenType::Space(" "), + LexTokenType::Word("text"), + LexTokenType::Space(" "), + LexTokenType::ControlWordStarter, + LexTokenType::Word("bold"), + LexTokenType::Space(" "), + LexTokenType::LBrace, + LexTokenType::Word("Some"), + LexTokenType::Space(" "), + LexTokenType::Word("bold"), + LexTokenType::Space(" "), + LexTokenType::Word("text"), + LexTokenType::Space(" "), + LexTokenType::Word("too"), + LexTokenType::RBrace, + LexTokenType::Space(" "), + LexTokenType::Word("more"), + LexTokenType::Space(" "), + LexTokenType::Word("text"), + LexTokenType::Space(" "), + LexTokenType::ControlWordStarter, + LexTokenType::Word("color"), + LexTokenType::Space(" "), + LexTokenType::Word("#00FF00"), + LexTokenType::Space(" "), + LexTokenType::Word("green"), + LexTokenType::Space(" "), + LexTokenType::Word("text"), + ]; + + let (_, res) = lex_input(input).unwrap(); + assert_eq!( + res.into_iter() + .map(|tok| tok.tok) + .collect::<Vec<LexTokenType>>(), + expected + ); + } +} diff --git a/libcraft/text/src/text/markdown/parser.rs b/libcraft/text/src/text/markdown/parser.rs new file mode 100644 index 000000000..60ba2d9c5 --- /dev/null +++ b/libcraft/text/src/text/markdown/parser.rs @@ -0,0 +1,551 @@ +use super::*; +use nom::branch::alt; +use nom::bytes::complete::*; +use nom::combinator::*; +use nom::error::ErrorKind; +use nom::multi::*; +use nom::sequence::*; +use nom::{Err, IResult}; + +pub mod events; + +#[derive(Debug, PartialEq, Clone)] +pub struct DynamicSpan { + pub fragment: String, + pub col: usize, + pub line: usize, +} + +impl DynamicSpan { + pub fn new(fragment: String, col: usize, line: usize) -> DynamicSpan { + DynamicSpan { + fragment, + col, + line, + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct Token { + pub span: DynamicSpan, + pub tok: TokenType, +} + +impl Token { + pub fn new(span: DynamicSpan, tok: TokenType) -> Token { + Token { span, tok } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum TokenType { + Call(CallToken), + Text(String), +} + +#[derive(Debug, PartialEq, Clone)] +pub struct CallToken { + pub ident: String, + pub args: Option<Vec<String>>, + pub body: Vec<Token>, +} + +fn token(t: LexTokenType<'static>) -> impl Fn(Tokens) -> IResult<Tokens, LexToken> { + move |input: Tokens| { + let (rest, tok) = take(1usize)(input)?; + if tok.tok[0].tok == t { + Ok((rest, tok.tok[0].clone())) + } else { + Err(nom::Err::Error((rest, nom::error::ErrorKind::Tag))) + } + } +} + +fn space(input: Tokens) -> IResult<Tokens, LexToken> { + let (rest, tok) = take(1usize)(input)?; + if let LexTokenType::Space(_) = tok.tok[0].tok { + Ok((rest, tok.tok[0].clone())) + } else { + Err(nom::Err::Error((rest, nom::error::ErrorKind::Tag))) + } +} + +fn word_or_space(input: Tokens) -> IResult<Tokens, LexToken> { + let (rest, tok) = take(1usize)(input)?; + match &tok.tok[0].tok { + LexTokenType::Word(_) | LexTokenType::Space(_) => Ok((rest, tok.tok[0].clone())), + _ => Err(nom::Err::Error((rest, nom::error::ErrorKind::Tag))), + } +} + +pub fn tokens_to_text(tokens: Vec<LexToken>) -> Token { + let mut s = String::new(); + + for tok in &tokens { + match &tok.tok { + LexTokenType::Word(word) => s.push_str(word), + LexTokenType::Space(space) => s.push_str(space), + _ => unreachable!(), + } + } + + let trimmed = s.trim(); + if s.starts_with(' ') && !trimmed.is_empty() { + let first_span = &tokens[1].span; + let t = TokenType::Text(trimmed.to_string()); + let span = DynamicSpan::new( + trimmed.to_string(), + first_span.get_column(), + first_span.location_line() as usize, + ); + Token { span, tok: t } + } else { + let first_span = &tokens[0].span; + let t = TokenType::Text(trimmed.to_string()); + let span = DynamicSpan::new( + trimmed.to_string(), + first_span.get_column(), + first_span.location_line() as usize, + ); + Token { span, tok: t } + } +} + +pub fn has_lbrace(input: Tokens) -> Option<usize> { + for (i, tok) in input.tok.iter().enumerate() { + if let LexTokenType::LBrace = tok.tok { + return Some(i); + } + } + + None +} + +fn consume_scope(lbrace_idx: Option<usize>) -> impl Fn(Tokens) -> IResult<Tokens, Vec<Token>> { + move |input: Tokens| { + if let Some(idx) = lbrace_idx { + let (i, _) = take(idx + 1)(input)?; + parse_tokens(true)(i) + } else { + parse_tokens(false)(input) + } + } +} + +pub fn parse_arg(i: Tokens) -> IResult<Tokens, String> { + let (i, tok) = opt(token(LexTokenType::ControlWordStarter))(i)?; + let (i, next) = take(1usize)(i)?; + + match &next.tok[0].tok { + LexTokenType::Word(s) => { + if tok.is_some() { + Ok((i, (*s).to_string())) + } else { + // Argument is a colour code + if s.starts_with('#') { + Ok((i, (*s).to_string())) + } else { + Err(nom::Err::Error((i, nom::error::ErrorKind::Tag))) + } + } + } + _ => Err(nom::Err::Error((i, nom::error::ErrorKind::Tag))), + } +} + +pub fn parse_control_word(i: Tokens) -> IResult<Tokens, Token> { + let (i, tok) = token(LexTokenType::ControlWordStarter)(i)?; + let (i, next) = take(1usize)(i)?; + + let span = &tok.span; + + match &next.tok[0].tok { + LexTokenType::Word(s) => { + let (i, arg) = opt(preceded(many0(space), parse_arg))(i)?; + let (_, peeked) = peek(take(2usize))(i)?; + + let span = DynamicSpan::new( + format!("{}{}", span.fragment(), next.tok[0].span.fragment()), + span.get_column(), + span.location_line() as usize, + ); + + map(consume_scope(has_lbrace(peeked)), move |body| { + Token::new( + span.clone(), + TokenType::Call(CallToken { + ident: (*s).to_string(), + args: arg.clone().map(|arg| vec![arg]), + body, + }), + ) + })(i) + } + _ => Err(Err::Error((i, ErrorKind::Tag))), + } +} + +pub fn parse_text(brace_delimited: bool) -> impl Fn(Tokens) -> IResult<Tokens, Token> { + move |input: Tokens| { + if brace_delimited { + map( + many_till( + word_or_space, + alt(( + peek(token(LexTokenType::RBrace)), + peek(token(LexTokenType::ControlWordStarter)), + )), + ), + |(toks, _)| tokens_to_text(toks), + )(input) + } else { + map(many1(word_or_space), tokens_to_text)(input) + } + } +} + +fn trim_empty_text(v: Vec<Token>) -> Vec<Token> { + v.into_iter() + .filter(|tok| match &tok.tok { + TokenType::Text(s) => !s.is_empty(), + _ => true, + }) + .collect() +} + +pub fn parse_tokens(brace_delimited: bool) -> impl Fn(Tokens) -> IResult<Tokens, Vec<Token>> { + move |input: Tokens| { + if brace_delimited { + map( + many_till( + alt((parse_control_word, parse_text(brace_delimited))), + token(LexTokenType::RBrace), + ), + |(toks, _)| trim_empty_text(toks), + )(input) + } else { + map( + many1(alt((parse_control_word, parse_text(brace_delimited)))), + trim_empty_text, + )(input) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::text::markdown::{lex_input, Tokens}; + + #[test] + fn test_basic() { + let text = Span::new("@red some red text"); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![Token::new( + DynamicSpan::new("@red".to_string(), 1, 1), + TokenType::Call(CallToken { + ident: "red".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new("some red text".to_string(), 6, 1), + TokenType::Text("some red text".to_string()) + )] + }) + )] + ); + + let text = Span::new("some red text"); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![Token::new( + DynamicSpan::new("some red text".to_string(), 1, 1), + TokenType::Text("some red text".to_string()) + )] + ); + + let text = Span::new("@red { Some red text }"); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![Token::new( + DynamicSpan::new("@red".to_string(), 1, 1), + TokenType::Call(CallToken { + ident: "red".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new("Some red text".to_string(), 8, 1), + TokenType::Text("Some red text".to_string()) + )] + }) + )] + ); + } + + #[test] + fn test_parse_delimited() { + let text = Span::new("@red { Delimited red text } Not red text"); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![ + Token::new( + DynamicSpan::new("@red".to_string(), 1, 1), + TokenType::Call(CallToken { + ident: "red".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new("Delimited red text".to_string(), 8, 1), + TokenType::Text("Delimited red text".to_string()) + )] + }) + ), + Token::new( + DynamicSpan::new("Not red text".to_string(), 29, 1), + TokenType::Text("Not red text".to_string()) + ) + ] + ); + } + + #[test] + fn test_parse_multiarg() { + let text = Span::new("@color #00FF00 { Some green text @bold { Green bold text } }"); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![Token::new( + DynamicSpan::new("@color".to_string(), 1, 1), + TokenType::Call(CallToken { + ident: "color".to_string(), + args: Some(vec!["#00FF00".to_string()]), + body: vec![ + Token::new( + DynamicSpan::new("Some green text".to_string(), 18, 1), + TokenType::Text("Some green text".to_string()) + ), + Token::new( + DynamicSpan::new("@bold".to_string(), 34, 1), + TokenType::Call(CallToken { + ident: "bold".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new("Green bold text".to_string(), 42, 1), + TokenType::Text("Green bold text".to_string()) + )] + }) + ) + ] + }) + )] + ); + } + + #[test] + fn test_parse_nested() { + let text = Span::new( + "@red { Some red text @bold { Some red bold text } more red text } Normal text", + ); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![ + Token::new( + DynamicSpan::new("@red".to_string(), 1, 1), + TokenType::Call(CallToken { + ident: "red".to_string(), + args: None, + body: vec![ + Token::new( + DynamicSpan::new("Some red text".to_string(), 8, 1), + TokenType::Text("Some red text".to_string()) + ), + Token::new( + DynamicSpan::new("@bold".to_string(), 22, 1), + TokenType::Call(CallToken { + ident: "bold".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new("Some red bold text".to_string(), 30, 1), + TokenType::Text("Some red bold text".to_string()) + )] + }) + ), + Token::new( + DynamicSpan::new("more red text".to_string(), 51, 1), + TokenType::Text("more red text".to_string()) + ) + ] + }) + ), + Token::new( + DynamicSpan::new("Normal text".to_string(), 67, 1), + TokenType::Text("Normal text".to_string()) + ) + ] + ); + + let text = Span::new("@red Some red text @bold { Some red bold text } more red text"); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![Token::new( + DynamicSpan::new("@red".to_string(), 1, 1), + TokenType::Call(CallToken { + ident: "red".to_string(), + args: None, + body: vec![ + Token::new( + DynamicSpan::new("Some red text".to_string(), 6, 1), + TokenType::Text("Some red text".to_string()) + ), + Token::new( + DynamicSpan::new("@bold".to_string(), 20, 1), + TokenType::Call(CallToken { + ident: "bold".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new("Some red bold text".to_string(), 28, 1), + TokenType::Text("Some red bold text".to_string()) + )] + }) + ), + Token::new( + DynamicSpan::new("more red text".to_string(), 49, 1), + TokenType::Text("more red text".to_string()) + ) + ] + }) + )] + ); + + let text = Span::new("@red { Some red text @bold Some red bold text } more text"); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![ + Token::new( + DynamicSpan::new("@red".to_string(), 1, 1), + TokenType::Call(CallToken { + ident: "red".to_string(), + args: None, + body: vec![ + Token::new( + DynamicSpan::new("Some red text".to_string(), 8, 1), + TokenType::Text("Some red text".to_string()) + ), + Token::new( + DynamicSpan::new("@bold".to_string(), 22, 1), + TokenType::Call(CallToken { + ident: "bold".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new("Some red bold text".to_string(), 28, 1), + TokenType::Text("Some red bold text".to_string()) + )] + }) + ), + ] + }) + ), + Token::new( + DynamicSpan::new("more text".to_string(), 49, 1), + TokenType::Text("more text".to_string()) + ), + ] + ); + + let text = Span::new("@red Some red text @bold Some red bold text and more red bold text"); + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![Token::new( + DynamicSpan::new("@red".to_string(), 1, 1), + TokenType::Call(CallToken { + ident: "red".to_string(), + args: None, + body: vec![ + Token::new( + DynamicSpan::new("Some red text".to_string(), 6, 1), + TokenType::Text("Some red text".to_string()) + ), + Token::new( + DynamicSpan::new("@bold".to_string(), 20, 1), + TokenType::Call(CallToken { + ident: "bold".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new( + "Some red bold text and more red bold text".to_string(), + 26, + 1 + ), + TokenType::Text( + "Some red bold text and more red bold text".to_string() + ) + )] + }) + ), + ] + }) + )] + ); + } + + #[test] + fn test_parse_event() { + let text = Span::new("Some text @on_hover @show_text @green Some green hover text"); + + let (_, lexed) = lex_input(text).unwrap(); + let (_, parsed) = parse_tokens(false)(Tokens::new(&lexed)).unwrap(); + + assert_eq!( + parsed, + vec![ + Token::new( + DynamicSpan::new("Some text".to_string(), 1, 1), + TokenType::Text("Some text".to_string()) + ), + Token::new( + DynamicSpan::new("@on_hover".to_string(), 11, 1), + TokenType::Call(CallToken { + ident: "on_hover".to_string(), + args: Some(vec!["show_text".to_string()]), + body: vec![Token::new( + DynamicSpan::new("@green".to_string(), 32, 1), + TokenType::Call(CallToken { + ident: "green".to_string(), + args: None, + body: vec![Token::new( + DynamicSpan::new("Some green hover text".to_string(), 39, 1), + TokenType::Text("Some green hover text".to_string()) + )] + }) + )] + }) + ) + ] + ) + } +} diff --git a/libcraft/text/src/text/markdown/parser/events.rs b/libcraft/text/src/text/markdown/parser/events.rs new file mode 100644 index 000000000..73932a840 --- /dev/null +++ b/libcraft/text/src/text/markdown/parser/events.rs @@ -0,0 +1,41 @@ +#[derive(Debug, Clone)] +pub enum EventParseError<'a> { + InvalidEventType(&'a str), + InvalidEventAction(&'a str), +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum EventType { + OnHover, + OnClick, +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum EventAction { + ShowText, + OpenUrl, + OpenFile, + RunCommand, + SuggestCommand, + CopyToClipboard, +} + +pub fn parse_event_type_word(i: &str) -> Result<EventType, EventParseError> { + match i { + "on_hover" => Ok(EventType::OnHover), + "on_click" => Ok(EventType::OnClick), + _ => Err(EventParseError::InvalidEventType(i)), + } +} + +pub fn parse_event_action_word(i: &str) -> Result<EventAction, EventParseError> { + match i { + "show_text" => Ok(EventAction::ShowText), + "open_url" => Ok(EventAction::OpenUrl), + "open_file" => Ok(EventAction::OpenFile), + "run_command" => Ok(EventAction::RunCommand), + "suggest_command" => Ok(EventAction::SuggestCommand), + "copy_to_clipboard" => Ok(EventAction::CopyToClipboard), + _ => Err(EventParseError::InvalidEventAction(i)), + } +} diff --git a/libcraft/text/src/text/markdown/translator.rs b/libcraft/text/src/text/markdown/translator.rs new file mode 100644 index 000000000..4382cbce0 --- /dev/null +++ b/libcraft/text/src/text/markdown/translator.rs @@ -0,0 +1,178 @@ +use super::{events::*, lex_input, parse_tokens, Span, Token, TokenType, Tokens}; +use crate::text::{Color, Style, Text, TextComponent, TextComponentBuilder}; +use nom::error::{convert_error, ErrorKind, VerboseError}; +use nom::Err; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum TextMarkupError<'a> { + #[error("Incomplete input.")] + Incomplete, + #[error("Error while lexing data: {}", convert_error(.0, .1.clone()))] + LexError(&'a str, VerboseError<&'a str>), + #[error("Error while parsing data: {0:?}")] + ParseError(ErrorKind), + #[error("Error while evaluating data: \n{0}")] + EvalError(String), +} + +impl<'a> From<(&'a str, Err<VerboseError<Span<'a>>>)> for TextMarkupError<'a> { + fn from((i, e): (&'a str, Err<VerboseError<Span<'a>>>)) -> Self { + match e { + Err::Incomplete(_) => TextMarkupError::Incomplete, + Err::Error(e) => TextMarkupError::LexError( + i, + VerboseError { + errors: e + .errors + .iter() + .map(|(i, ek)| (*i.fragment(), ek.clone())) + .collect(), + }, + ), + Err::Failure(e) => TextMarkupError::LexError( + i, + VerboseError { + errors: e + .errors + .iter() + .map(|(i, ek)| (*i.fragment(), ek.clone())) + .collect(), + }, + ), + } + } +} + +//TODO: Convert to returning a nice Result type that isn't IResult +pub fn translate_text(text: &str) -> Result<TextComponent, TextMarkupError> { + let input = Span::new(text); + let (_, lexed) = lex_input(input).map_err(|e| (text, e))?; + + match parse_tokens(false)(Tokens::new(&lexed)) { + Ok((_, parsed)) => apply_tokens(parsed), + Err(e) => match e { + Err::Incomplete(_) => Err(TextMarkupError::Incomplete), + Err::Error((_, e)) => Err(TextMarkupError::ParseError(e)), + Err::Failure((_, e)) => Err(TextMarkupError::ParseError(e)), + }, + } +} + +pub fn apply_tokens(tokens: Vec<Token>) -> Result<TextComponent, TextMarkupError<'static>> { + let mut component = TextComponent::default(); + + for token in tokens { + match token.tok { + TokenType::Text(s) => component = component.push_extra(Text::of(s)), + TokenType::Call(call) => match ( + call.ident.parse::<Color>(), + call.ident.parse::<Style>(), + call.ident.as_str(), + ) { + (Ok(color), _, _) => { + component = component.push_extra(apply_tokens(call.body.clone())?.color(color)) + } + (_, Ok(style), _) => { + component = component.push_extra(apply_tokens(call.body.clone())?.style(style)) + } + (_, _, "color") => match &call.args { + Some(v) => { + component = component.push_extra( + apply_tokens(call.body.clone())?.color(Color::Custom(v[0].clone())), + ) + } + None => { + return Err(TextMarkupError::EvalError(format!( + "Error at {}:{}. @color call not provided with any arguments.", + token.span.line, token.span.col + ))) + } + }, + (_, _, event_name) => { + let ty = parse_event_type_word(event_name); + match &call.args { + Some(v) => { + let action = parse_event_action_word(&v[0]); + match ty { + Ok(EventType::OnHover) => match action { + Ok(EventAction::ShowText) => { + component = component + .on_hover_show_text(apply_tokens(call.body.clone())?) + } + Ok(_) => return Err(TextMarkupError::EvalError(format!("Error at {}:{}. The only supported action type for @on_hover is @show_text.", token.span.line, token.span.col))), + Err(e) => return Err(TextMarkupError::EvalError(format!("Error at {}:{}. Invalid event action specified. {:?}", token.span.line, token.span.col, e))), + }, + Ok(EventType::OnClick) => return Err(TextMarkupError::EvalError(format!("Error at {}:{}. @on_click is unimplemented", token.span.line, token.span.col))), + Err(e) => return Err(TextMarkupError::EvalError(format!("Error at {}:{} when parsing event: {:?}", token.span.line, token.span.col, e))), + } + } + None => { + return Err(TextMarkupError::EvalError(format!( + "Error at {}:{}. Text event not provided a target action.", + token.span.line, token.span.col + ))) + } + } + } + }, + } + } + + Ok(component) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_translate_simple() { + let text = "@red Some red text"; + + let component = translate_text(text).unwrap(); + let s = serde_json::to_string_pretty(&component).unwrap(); + println!("{}", s); + assert_eq!( + component, + TextComponent::default().push_extra( + TextComponent::default() + .color(Color::Red) + .push_extra(Text::of("Some red text")) + ) + ); + } + + #[test] + fn test_error() { + let text = "@color { Some red text }"; + + assert_eq!( + translate_text(text), + Err(TextMarkupError::EvalError( + "Error at 1:1. @color call not provided with any arguments.".to_string() + )) + ); + } + + #[test] + fn test_component_with_event() { + let text = "Some text @on_hover @show_text @green Some green hover text"; + + let component = translate_text(text).unwrap(); + let s = serde_json::to_string_pretty(&component).unwrap(); + println!("{}", s); + assert_eq!( + component, + TextComponent::default() + .push_extra(Text::of("Some text")) + .on_hover_show_text( + TextComponent::default().push_extra( + TextComponent::default() + .color(Color::Green) + .push_extra(Text::of("Some green hover text")) + ) + ) + ); + } +} diff --git a/libcraft/text/src/title.rs b/libcraft/text/src/title.rs new file mode 100644 index 000000000..a77c4782f --- /dev/null +++ b/libcraft/text/src/title.rs @@ -0,0 +1,30 @@ +use crate::Text; +use serde::{Deserialize, Serialize}; + +// Based on https://wiki.vg/index.php?title=Protocol&oldid=16459#Title +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] +pub struct Title { + pub title: Option<Text>, + pub sub_title: Option<Text>, + pub fade_in: u32, + pub stay: u32, + pub fade_out: u32, +} + +impl Title { + pub const HIDE: Title = Title { + title: None, + sub_title: None, + fade_in: 0, + stay: 0, + fade_out: 0, + }; + + pub const RESET: Title = Title { + title: None, + sub_title: None, + fade_in: 0, + stay: 0, + fade_out: 0, + }; +} diff --git a/minecraft-data b/minecraft-data new file mode 160000 index 000000000..a4fde646c --- /dev/null +++ b/minecraft-data @@ -0,0 +1 @@ +Subproject commit a4fde646c6571e97ec77a57662ca3470718bfa41 diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml new file mode 100644 index 000000000..e739e7555 --- /dev/null +++ b/proxy/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "proxy" +version = "0.1.0" +edition = "2021" + +[dependencies] +feather-protocol = { path = "../feather/protocol" } +clap = { version = "3.0.5", features = ["derive"] } +pretty-hex = "0.2.1" +log = "0.4.14" +fern = "0.6.0" +anyhow = "1.0.52" +colored = "2.0.0" +time = { version = "0.3", features = ["local-offset", "formatting", "macros"] } diff --git a/proxy/README.md b/proxy/README.md new file mode 100644 index 000000000..cf14e7075 --- /dev/null +++ b/proxy/README.md @@ -0,0 +1,24 @@ +A simple proxy for use during development. It proxies a connection between +client and server and prints out packets going over the network. + +This tool is useful when figuring out how Minecraft implements features +over the protocol. + +#### Usage + +To set up the proxy with a vanilla server and client: + +* Start the vanilla 1.16.5 server. Make sure to set `online-mode=false` + or the proxy will not work for the time being. +* Run the proxy with `cargo run --bin proxy -- --proxy-address 127.0.0.1:25577 --server-address 127.0.0.1:25565`. +* Connect your client to `localhost:25577`. + +To set up the proxy with feather server: + +* Build and start feather (See main [`README.md`](../../README.md)) +* In the `config.toml` set `online_mode = false`. +* Run the proxy with `cargo run --bin proxy -- --proxy-address 127.0.0.1:25577 --server-address 127.0.0.1:25565`. +* Connect your client to `localhost:25577`. + +The proxy supports multiple client connections, in case you need +to debug protocol semantics with multiple players. diff --git a/proxy/src/main.rs b/proxy/src/main.rs new file mode 100644 index 000000000..161e747c5 --- /dev/null +++ b/proxy/src/main.rs @@ -0,0 +1,366 @@ +use std::fmt::{Display, Formatter}; +use std::io::{Read, Write}; +use std::net::SocketAddr; +use std::net::{TcpListener, TcpStream}; +use std::num::ParseIntError; +use std::sync::{Arc, Mutex}; + +use anyhow::Context; +use clap::{ArgEnum, Parser}; +use colored::Colorize; +use log::{Level, LevelFilter}; +use time::macros::format_description; +use time::OffsetDateTime; + +use feather_protocol::codec::CompressionThreshold; +use feather_protocol::packets::client::HandshakeState; +use feather_protocol::{ + ClientHandshakePacket, ClientPacket, ClientPacketCodec, ProtocolState, ServerLoginPacket, + ServerPacket, ServerPacketCodec, VarInt, +}; + +/// A simple proxy server that logs transmitted packets +#[derive(Parser)] +#[clap(about, version)] +struct Args { + /// The Minecraft server address (ip:port) + #[clap(short = 'a', long)] + server_address: SocketAddr, + /// The address that the proxy should listen on (ip:port) + #[clap(short, long)] + proxy_address: SocketAddr, + /// Only log clientside/serverside packets + #[clap(arg_enum, short, long, default_value_t)] + side: ConnectionSide, + /// Show the contents of the packets. `-vv` will also display hexdump + #[clap(short, long, parse(from_occurrences))] + verbose: usize, + /// Don't log packets with the specified IDs (hexadecimal, comma-separated) + #[clap(short, long, use_delimiter = true, parse(try_from_str = parse_hex), conflicts_with = "whitelist")] + blacklist: Option<Vec<u32>>, + /// Log only packets with the specified IDs (hexadecimal, comma-separated) + #[clap(short, long, use_delimiter = true, parse(try_from_str = parse_hex), conflicts_with = "blacklist")] + whitelist: Option<Vec<u32>>, +} + +fn parse_hex(src: &str) -> Result<u32, ParseIntError> { + u32::from_str_radix(src, 16) +} + +#[derive(ArgEnum, Copy, Clone)] +enum ConnectionSide { + Client, + Server, + Both, +} + +impl Default for ConnectionSide { + fn default() -> Self { + ConnectionSide::Both + } +} + +fn main() { + let args: Args = Args::parse(); + fern::Dispatch::new() + .format(|out, message, record| { + let level_string = match record.level() { + Level::Error => record.level().to_string().red(), + Level::Warn => record.level().to_string().yellow(), + Level::Info => record.level().to_string().cyan(), + Level::Debug => record.level().to_string().purple(), + Level::Trace => record.level().to_string().normal(), + }; + let target = if !record.target().is_empty() { + record.target() + } else { + record.module_path().unwrap_or_default() + }; + let datetime: OffsetDateTime = + OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc()); + out.finish(format_args!( + "{} {:<5} [{}] {}", + datetime + .format(format_description!( + "[year]-[month]-[day] [hour]:[minute]:[second],[subsecond digits:3]" + )) + .unwrap(), + level_string, + target, + message, + )); + }) + .level(match args.verbose { + 0 => LevelFilter::Info, + 1 => LevelFilter::Debug, + _ => LevelFilter::Trace, + }) + .chain(std::io::stdout()) + .apply() + .unwrap(); + + let listener = TcpListener::bind(args.proxy_address).unwrap(); + + log::info!("Listening on {}", args.proxy_address); + while let Ok((client, addr)) = listener.accept() { + log::info!("Accepting connection from {}", addr); + + let server = match TcpStream::connect(args.server_address) { + Ok(server) => server, + Err(err) => { + log::error!( + "failed to connect to server at {}: {}", + args.server_address, + err + ); + continue; + } + }; + + let connection = Arc::new(Mutex::new(Connection { + username: None, + client_codec: ClientPacketCodec::new(), + server_codec: ServerPacketCodec::new(), + })); + + let client_read = client; + let client_write = client_read.try_clone().unwrap(); + let server_read = server; + let server_write = server_read.try_clone().unwrap(); + + std::thread::spawn({ + let connection = connection.clone(); + let blacklist = args.blacklist.clone(); + let whitelist = args.whitelist.clone(); + move || match handle_client( + matches!(args.side, ConnectionSide::Both | ConnectionSide::Client), + blacklist, + whitelist, + &connection, + client_read, + server_write, + ) { + Ok(()) => { + log::info!( + "{}: client disconnected", + connection + .lock() + .unwrap() + .username + .clone() + .unwrap_or_default() + ); + } + Err(err) => { + log::error!("Client error: {:?}", err); + } + } + }); + + std::thread::spawn({ + let connection = connection.clone(); + let blacklist = args.blacklist.clone(); + let whitelist = args.whitelist.clone(); + move || match handle_server( + matches!(args.side, ConnectionSide::Both | ConnectionSide::Server), + blacklist, + whitelist, + &connection, + server_read, + client_write, + ) { + Ok(()) => { + log::info!( + "{}: server disconnected", + connection + .lock() + .unwrap() + .username + .clone() + .unwrap_or_default() + ) + } + Err(err) => { + log::error!("Server error: {:?}", err); + } + } + }); + } +} + +struct Connection { + /// The client's username. + username: Option<PlayerName>, + client_codec: ClientPacketCodec, + server_codec: ServerPacketCodec, +} + +impl Connection { + fn set_state(&mut self, state: ProtocolState) { + log::info!( + "{}: switching to state {:?}", + self.username.clone().unwrap_or_default(), + state + ); + self.client_codec.set_state(state); + self.server_codec.set_state(state); + } + + fn set_compression(&mut self, threshold: CompressionThreshold) { + self.client_codec.set_compression(threshold); + self.server_codec.set_compression(threshold); + } +} + +#[derive(Clone)] +struct PlayerName(String); + +impl Default for PlayerName { + fn default() -> Self { + PlayerName("<unknown>".to_string()) + } +} + +impl Display for PlayerName { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0) + } +} + +fn handle_client( + log: bool, + blacklist: Option<Vec<u32>>, + whitelist: Option<Vec<u32>>, + connection: &Arc<Mutex<Connection>>, + mut client_read: TcpStream, + mut server_write: TcpStream, +) -> anyhow::Result<()> { + loop { + let length = VarInt::read_from(&mut client_read) + .map(|var_int| var_int.0) + .unwrap_or_default(); + if length == 0 { + break; + } + let mut buf = vec![0; length as usize]; + client_read.read_exact(&mut buf)?; + let mut vec = Vec::new(); + VarInt(length).write_to(&mut vec)?; + vec.extend(buf); + if vec.is_empty() { + break; + } + + let mut connection = connection.lock().unwrap(); + if let Some(packet) = connection + .client_codec + .decode(&vec) + .context("failed to decode client packet")? + { + if log && !hide(packet.id(), blacklist.as_ref(), whitelist.as_ref()) { + log::info!( + "{} -> #{:02X}", + connection.username.clone().unwrap_or_default(), + packet.id() + ); + log::debug!( + "{} -> {:?}", + connection.username.clone().unwrap_or_default(), + packet + ); + log::trace!("{}", pretty_hex::pretty_hex(&&vec)); + } + + // Detect state switches. + if let ClientPacket::Handshake(packet) = packet { + let state = match packet { + ClientHandshakePacket::Handshake(packet) => match packet.next_state { + HandshakeState::Login => ProtocolState::Login, + HandshakeState::Status => ProtocolState::Status, + }, + }; + connection.set_state(state) + } + + drop(connection); + // Forward the packet to the server. + server_write.write_all(&vec)?; + } + } + Ok(()) +} + +fn handle_server( + log: bool, + blacklist: Option<Vec<u32>>, + whitelist: Option<Vec<u32>>, + connection: &Arc<Mutex<Connection>>, + mut server_read: TcpStream, + mut client_write: TcpStream, +) -> anyhow::Result<()> { + loop { + let length = VarInt::read_from(&mut server_read) + .map(|var_int| var_int.0) + .unwrap_or_default(); + if length == 0 { + break; + } + let mut buf = vec![0; length as usize]; + server_read.read_exact(&mut buf)?; + let mut vec = Vec::new(); + VarInt(length).write_to(&mut vec)?; + vec.extend(buf); + if vec.is_empty() { + break; + } + + let mut connection = connection.lock().unwrap(); + if let Some(packet) = connection + .server_codec + .decode(&vec) + .context("failed to decode client packet")? + { + if log && !hide(packet.id(), blacklist.as_ref(), whitelist.as_ref()) { + log::info!( + "{} <- #{:02X}", + connection.username.clone().unwrap_or_default(), + packet.id() + ); + log::debug!( + "{} <- {:?}", + connection.username.clone().unwrap_or_default(), + packet + ); + log::trace!("{}", pretty_hex::pretty_hex(&&vec)); + } + + match packet { + // Detect state switches + ServerPacket::Login(ServerLoginPacket::LoginSuccess(packet)) => { + connection.username = Some(PlayerName(packet.username)); + connection.set_state(ProtocolState::Play); + } + // Detect SetCompression + ServerPacket::Login(ServerLoginPacket::SetCompression(packet)) => { + connection.set_compression(packet.threshold as CompressionThreshold) + } + _ => (), + } + + drop(connection); + // Forward the packet to the server. + client_write.write_all(&vec)?; + } + } + Ok(()) +} + +fn hide(packet_id: u32, blacklist: Option<&Vec<u32>>, whitelist: Option<&Vec<u32>>) -> bool { + if let Some(blacklist) = blacklist { + blacklist.contains(&packet_id) + } else if let Some(whitelist) = whitelist { + !whitelist.contains(&packet_id) + } else { + false + } +} diff --git a/quill/LICENSE-APACHE b/quill/LICENSE-APACHE new file mode 100644 index 000000000..f49a4e16e --- /dev/null +++ b/quill/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/quill/LICENSE-MIT b/quill/LICENSE-MIT new file mode 100644 index 000000000..91b794d42 --- /dev/null +++ b/quill/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright 2019 Caelum van Ispelen + +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: + +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. \ No newline at end of file diff --git a/quill/README.md b/quill/README.md new file mode 100644 index 000000000..fb7d5a81e --- /dev/null +++ b/quill/README.md @@ -0,0 +1,14 @@ +# quill +[![Discord](https://img.shields.io/discord/619316022800809995)](https://discordapp.com/invite/4eYmK69) + +A WebAssembly-based plugin API for Minecraft servers. Currently in development. + +Plugins written for [Feather](https://github.com/feather-rs/feather) servers use `quill`. + +## For Feather developers +See [`docs`](./docs) for information on Quill internals. + +## __**Important Notice For Plugin Developers**__ +There is currently a miscompilation issue with the latest versions of rustc! + +__**1.51.0 IS CONFIRMED STABLE, PLEASE USE IT IF YOU ARE COMPILING PLUGINS**__ diff --git a/quill/api/Cargo.toml b/quill/api/Cargo.toml new file mode 100644 index 000000000..33dfdc59c --- /dev/null +++ b/quill/api/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "quill" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +plugin-macro = { path = "./plugin-macro" } +libcraft-core = { path = "../../libcraft/core" } +libcraft-particles = { path = "../../libcraft/particles" } +libcraft-blocks = { path = "../../libcraft/blocks" } +libcraft-text = { path = "../../libcraft/text" } +bincode = "1" +bytemuck = "1" +quill-sys = { path = "../sys" } +quill-common = { path = "../common" } +thiserror = "1" +uuid = "0.8" +itertools = "0.10.0" +serde_json = "1" + diff --git a/quill/api/plugin-macro/Cargo.toml b/quill/api/plugin-macro/Cargo.toml new file mode 100644 index 000000000..b16c64f64 --- /dev/null +++ b/quill/api/plugin-macro/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "plugin-macro" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1.0.86", features = ["full"] } +quote = "1.0.14" \ No newline at end of file diff --git a/quill/api/plugin-macro/src/lib.rs b/quill/api/plugin-macro/src/lib.rs new file mode 100644 index 000000000..15ef5b4ed --- /dev/null +++ b/quill/api/plugin-macro/src/lib.rs @@ -0,0 +1,108 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Item}; + +/// Invoke this macro in your plugin's main.rs. +/// +/// Give it the name of your struct implementing `Plugin`. +/// +/// # Example +/// ```ignore +/// // main.rs +/// use quill::{Plugin, Setup, Game}; +/// +/// #[quill::plugin] +/// pub struct MyPlugin { +/// // plugin state goes here +/// } +/// +/// impl Plugin for MyPlugin { +/// fn enable(game: &mut Game, setup: &mut Setup<Self>) -> Self { +/// // Initialize plugin state... +/// Self {} +/// } +/// +/// fn disable(self, game: &mut Game) { +/// // Clean up... +/// } +/// } +/// ``` +#[proc_macro_attribute] +pub fn plugin(_attr: TokenStream, mut item: TokenStream) -> TokenStream { + let cloned_item = item.clone(); + let input = parse_macro_input!(cloned_item as Item); + + let name = match input { + Item::Enum(itm_enum) => itm_enum.ident, + Item::Struct(itm_str) => itm_str.ident, + _ => panic!("Only structs or enums can be #[quill::plugin]!"), + }; + let res = quote! { + // `static mut` can be used without synchronization because the host + // guarantees it will not invoke plugin systems outside of the main thread. + static mut PLUGIN: Option<#name> = None; + + // Exports to the host required for all plugins + #[no_mangle] + #[doc(hidden)] + #[cfg(target_arch = "wasm32")] + pub unsafe extern "C" fn quill_setup() { + let plugin: #name = + quill::Plugin::enable(&mut ::quill::Game::new(), &mut ::quill::Setup::new()); + PLUGIN = Some(plugin); + } + + #[no_mangle] + #[doc(hidden)] + #[cfg(not(target_arch = "wasm32"))] + pub unsafe extern "C" fn quill_setup( + context: *const (), + vtable_ptr: *const u8, + vtable_len: usize, + ) { + // Set up vtable and host context for quill_sys. + let vtable_bytes = ::std::slice::from_raw_parts(vtable_ptr, vtable_len); + let vtable: ::std::collections::HashMap<&str, usize> = + ::quill::bincode::deserialize(vtable_bytes).expect("invalid vtable"); + + ::quill::sys::init_host_context(context); + ::quill::sys::init_host_vtable(&vtable) + .expect("invalid vtable (check that the plugin and host are up to date)"); + + let plugin: #name = + quill::Plugin::enable(&mut ::quill::Game::new(), &mut ::quill::Setup::new()); + PLUGIN = Some(plugin); + } + + #[no_mangle] + #[doc(hidden)] + pub unsafe extern "C" fn quill_allocate(size: usize, align: usize) -> *mut u8 { + std::alloc::alloc(std::alloc::Layout::from_size_align_unchecked(size, align)) + } + + #[no_mangle] + #[doc(hidden)] + pub unsafe extern "C" fn quill_deallocate(ptr: *mut u8, size: usize, align: usize) { + std::alloc::dealloc( + ptr, + std::alloc::Layout::from_size_align_unchecked(size, align), + ) + } + + #[no_mangle] + #[doc(hidden)] + pub unsafe extern "C" fn quill_run_system(data: *mut u8) { + let system = &mut *data.cast::<Box<dyn FnMut(&mut #name, &mut ::quill::Game)>>(); + let plugin = PLUGIN.as_mut().expect("quill_setup never called"); + system(plugin, &mut ::quill::Game::new()); + } + + /// Never called by Quill, but this is needed + /// to avoid linker errors with WASI. + #[doc(hidden)] + fn main() {} + }; + item.extend(TokenStream::from(res)); + + item +} diff --git a/quill/api/src/entities.rs b/quill/api/src/entities.rs new file mode 100644 index 000000000..ec0cf6126 --- /dev/null +++ b/quill/api/src/entities.rs @@ -0,0 +1,17 @@ +//! Defines components for all Minecraft entities. +//! +//! # Marker components +//! Each entity has a "marker component": +//! just a struct (often with no fields) +//! that signifies the type of an entity. +//! +//! For example, all horse entities have the [`Horse`] +//! marker component. +//! +//! For certain entities, these components also +//! contain data. For example, the [`Item`] marker +//! component (for item entities) has an `ItemStack` +//! field that indicates the type of the item. + +#[doc(inline)] +pub use quill_common::entities::*; diff --git a/quill/api/src/entity.rs b/quill/api/src/entity.rs new file mode 100644 index 000000000..5d2ddcaa7 --- /dev/null +++ b/quill/api/src/entity.rs @@ -0,0 +1,143 @@ +use libcraft_text::Text; +use std::{marker::PhantomData, ptr}; + +use quill_common::{Component, Pointer, PointerMut}; + +/// Unique internal ID of an entity. +/// +/// Can be passed to [`crate::Game::entity`] to get an [`Entity`] +/// handle. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct EntityId(pub(crate) quill_common::EntityId); + +/// Error returned by [`Entity::get`] when +/// the entity is missing a component. +#[derive(Debug, thiserror::Error)] +#[error("entity does not have component of type {0}")] +pub struct MissingComponent(&'static str); + +/// A handle to an entity. +/// +/// Allows access to the entity's components, like +/// position and UUID. +/// +/// Use [`crate::Game::entity`] to get an `Entity` instance. +/// +/// An `Entity` be sent or shared between threads. However, +/// an [`EntityId`] can. +#[derive(Debug)] +#[repr(C)] +pub struct Entity { + id: EntityId, + _not_send_sync: PhantomData<*mut ()>, +} + +impl Entity { + pub(crate) fn new(id: EntityId) -> Self { + Self { + id, + _not_send_sync: PhantomData, + } + } + + /// Gets a component of this entity. Returns + /// `Err(MissingComponent)` if the entity does not have this component. + /// + /// # Examples + /// ```no_run + /// use quill::{Position, Entity}; + /// # let entity: Entity = unreachable!(); + /// let position = entity.get::<Position>().expect("entity has no position component"); + /// ``` + pub fn get<T: Component>(&self) -> Result<T, MissingComponent> { + let host_component = T::host_component(); + unsafe { + let mut bytes_ptr = Pointer::new(ptr::null()); + let mut bytes_len = 0u32; + quill_sys::entity_get_component( + self.id.0, + host_component, + PointerMut::new(&mut bytes_ptr), + PointerMut::new(&mut bytes_len), + ); + + if bytes_ptr.as_ptr().is_null() { + return Err(MissingComponent(std::any::type_name::<T>())); + } + + let bytes = std::slice::from_raw_parts(bytes_ptr.as_ptr(), bytes_len as usize); + Ok(T::from_bytes_unchecked(bytes).0) + } + } + + /// Inserts or replaces a component of this entity. + /// + /// If the entity already has this component, + /// the component is overwritten. + pub fn insert<T: Component>(&self, component: T) { + let host_component = T::host_component(); + let bytes = component.to_cow_bytes(); + + unsafe { + quill_sys::entity_set_component( + self.id.0, + host_component, + bytes.as_ptr().into(), + bytes.len() as u32, + ); + } + } + + /// Inserts an event to the entity. + /// + /// If the entity already has this event, + /// the event is overwritten. + pub fn insert_event<T: Component>(&self, event: T) { + let host_component = T::host_component(); + let bytes = event.to_cow_bytes(); + + unsafe { + quill_sys::entity_add_event( + self.id.0, + host_component, + bytes.as_ptr().into(), + bytes.len() as u32, + ); + } + } + + /// Sends the given message to this entity. + /// + /// The message sends as a "system" message. + /// See [the wiki](https://wiki.vg/Chat) for more details. + pub fn send_message(&self, message: impl Into<Text>) { + let message = message.into().to_string(); + unsafe { + quill_sys::entity_send_message(self.id.0, message.as_ptr().into(), message.len() as u32) + } + } + + /// Sends the given title to this entity. + pub fn send_title(&self, title: &libcraft_text::Title) { + let title = serde_json::to_string(title).expect("failed to serialize Title"); + unsafe { + quill_sys::entity_send_title(self.id.0, title.as_ptr().into(), title.len() as u32); + } + } + + /// Hides the currently visible title for this entity, will do nothing if the there's no title + pub fn hide_title(&self) { + self.send_title(&libcraft_text::title::Title::HIDE); + } + + /// Resets the currently visible title for this entity, will do nothing if there's no title + pub fn reset_title(&self) { + self.send_title(&libcraft_text::title::Title::RESET) + } + + /// Gets the unique ID of this entity. + pub fn id(&self) -> EntityId { + self.id + } +} diff --git a/quill/api/src/entity_builder.rs b/quill/api/src/entity_builder.rs new file mode 100644 index 000000000..7bafbe909 --- /dev/null +++ b/quill/api/src/entity_builder.rs @@ -0,0 +1,62 @@ +use std::marker::PhantomData; + +use quill_common::Component; + +use crate::{Entity, EntityId}; + +/// Builder for an entity. +/// +/// Created via [`Game::create_entity_builder`](crate::Game::create_entity_builder). +/// +/// Add components to the entity with [`EntityBuilder::add`]. +/// Finish building the entity with [`EntityBuilder::finish`]. +#[derive(Debug)] +pub struct EntityBuilder { + id: u32, + _not_send_sync: PhantomData<*mut ()>, +} + +impl EntityBuilder { + pub(crate) fn new(id: u32) -> Self { + Self { + id, + _not_send_sync: PhantomData, + } + } + + /// Adds a component to the entity. + /// + /// If the builder already has this component, + /// it is overriden. + pub fn add<T: Component>(&mut self, component: T) -> &mut Self { + let host_component = T::host_component(); + let bytes = component.to_cow_bytes(); + unsafe { + quill_sys::entity_builder_add_component( + self.id, + host_component, + bytes.as_ptr().into(), + bytes.len() as u32, + ); + } + self + } + + /// Adds a component to the entity and returns + /// `self` for method chaining. + /// + /// If the builder already has this component, + /// it is override. + pub fn with<T: Component>(mut self, component: T) -> Self { + self.add(component); + self + } + + /// Finishes building the entity and spawns it. + /// + /// Returns the built entity. + pub fn finish(self) -> Entity { + let id = unsafe { quill_sys::entity_builder_finish(self.id) }; + Entity::new(EntityId(id)) + } +} diff --git a/quill/api/src/game.rs b/quill/api/src/game.rs new file mode 100644 index 000000000..7fd5657c8 --- /dev/null +++ b/quill/api/src/game.rs @@ -0,0 +1,289 @@ +use std::marker::PhantomData; + +use libcraft_blocks::BlockState; +use libcraft_core::{BlockPosition, ChunkPosition, Position, CHUNK_HEIGHT}; +use libcraft_particles::Particle; +use quill_common::entity_init::EntityInit; +use quill_common::Component; + +use crate::{ + query::{Query, QueryIter}, + EntityBuilder, +}; +use crate::{Entity, EntityId}; + +/// Error returned when getting or setting a block fails. +#[derive(Debug, thiserror::Error)] +pub enum BlockAccessError { + #[error("the block's Y coordinate is outside the range [0, 256)")] + YOutOfBounds, + #[error("the block's chunk is not loaded")] + ChunkNotLoaded, +} + +/// Error returned from [`Game::entity`] if the entity +/// did not exist. +#[derive(Debug, thiserror::Error)] +#[error("entity no longer exists - they either died or were unloaded")] +pub struct EntityRemoved; + +/// Provides access to the server's game state for a single world. +/// +/// Includes entities, blocks, chunks, etc. All interaction with +/// the game happens through this struct. +/// +/// A `Game` is passed to systems when they run. +#[derive(Debug)] +pub struct Game { + _not_send_sync: PhantomData<*mut ()>, +} + +impl Game { + /// For Quill internal use only. Do not call. + #[doc(hidden)] + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self { + _not_send_sync: PhantomData, + } + } + + /// Gets an [`Entity`] from its [`EntityId`]. + /// + /// Returns `None` if the entity no longer exists. This + /// could be the case if: + /// * The entity has been unloaded (and possibly saved to disk) + /// * The entity has died + pub fn entity(&self, id: EntityId) -> Result<Entity, EntityRemoved> { + unsafe { + if !quill_sys::entity_exists(id.0) { + return Err(EntityRemoved); + } + } + Ok(Entity::new(id)) + } + + /// Creates an empty [`EntityBuilder`](crate::EntityBuilder) + /// to add entities to the ecs. + /// + /// The builder isn initialised without any components. + pub fn create_empty_entity_builder(&self) -> EntityBuilder { + let id = unsafe { quill_sys::entity_builder_new_empty() }; + + EntityBuilder::new(id) + } + + /// Creates an [`EntityBuilder`](crate::EntityBuilder) + /// to spawn an entity at the given position. + /// + /// The builder is initialized with the default components + /// for the given `EntityInit`. The default components + /// include (at least): + /// * Position` + /// * `Uuid` + /// * `EntityType` + /// * `Velocity` (set to zero) + /// * the marker component for this entity + #[must_use = "call `finish` on an EntityBuilder to spawn the entity"] + pub fn create_entity_builder(&self, position: Position, entity: EntityInit) -> EntityBuilder { + let entity_init = bincode::serialize(&entity).expect("failed to serialize EntityInit"); + let position: &[u8] = bytemuck::cast_slice(std::slice::from_ref(&position)); + let id = unsafe { + quill_sys::entity_builder_new( + position.as_ptr().into(), + entity_init.as_ptr().into(), + entity_init.len() as u32, + ) + }; + EntityBuilder::new(id) + } + + /// Returns an iterator over all entities + /// with the given components. + /// + /// # Example + /// Iterate over all entities with positions and UUIDs: + /// ```no_run + /// use quill::{Position, Uuid}; + /// # let game: quill::Game = todo!(); + /// for (entity, (position, uuid)) in game.query::<(&Position, &Uuid)>() { + /// println!("Found an entity with position {:?} and UUID {}", position, uuid); + /// } + /// ``` + pub fn query<Q: Query>(&mut self) -> QueryIter<Q> { + QueryIter::new() + } + + /// Spawn a particle effect at the position + /// + /// # Example + /// Spawn a flame particle at 0, 0, 0: + /// ```no_run + /// # let game: quill::Game = unreachable!(); + /// use quill::{Position, Particle, ParticleKind}; + /// + /// let position = Position {x: 0.0, y: 0.0, z: 0.0, pitch: 0.0, yaw: 0.0}; + /// let particle = Particle { + /// kind: ParticleKind::Flame, + /// offset_x: 0.0, + /// offset_y: 0.0, + /// offset_z: 0.0, + /// count: 1, + /// }; + /// + /// game.spawn_particle(position, particle); + /// ``` + pub fn spawn_particle(&self, position: Position, particle: Particle) { + let mut entity_builder = self.create_empty_entity_builder(); + + entity_builder.add(position); + entity_builder.add(particle); + entity_builder.finish(); + } + + /// Gets the block at `pos`. + /// + /// This function returns an error if the block's + /// chunk is not loaded. Unlike in Bukkit, calling this method + /// will not cause chunks to be loaded. + /// + /// Mutating the returned [`BlockState`](libcraft_blocks::BlockState) + /// will _not_ cause the block to be modified in the world. In other + /// words, the `BlockState` is a copy, not a reference. To update + /// the block, call [`Game::set_block`]. + pub fn block(&self, pos: BlockPosition) -> Result<BlockState, BlockAccessError> { + check_y_bound(pos)?; + + let result = unsafe { quill_sys::block_get(pos.x, pos.y, pos.z) }; + + result + .get() + .ok_or(BlockAccessError::ChunkNotLoaded) + .map(|block_id| BlockState::from_id(block_id).expect("host gave invalid block ID")) + } + + /// Sets the block at `pos`. + /// + /// This function returns an error if the block's + /// chunk is not loaded. Unlike in Bukkit, calling this method + /// will not cause chunks to be loaded. + pub fn set_block(&self, pos: BlockPosition, block: BlockState) -> Result<(), BlockAccessError> { + check_y_bound(pos)?; + + let was_successful = unsafe { quill_sys::block_set(pos.x, pos.y, pos.z, block.id()) }; + + if was_successful { + Ok(()) + } else { + Err(BlockAccessError::ChunkNotLoaded) + } + } + + /// Efficiently overwrites all blocks in the given chunk section (16x16x16 blocks). + /// + /// All blocks in the chunk section are replaced with `block`. + /// + /// This function returns an error if the block's + /// chunk is not loaded. Unlike in Bukkit, calling this method + /// will not cause chunks to be loaded. + pub fn fill_chunk_section( + &self, + chunk: ChunkPosition, + section_y: u32, + block: BlockState, + ) -> Result<(), BlockAccessError> { + check_section_y(section_y)?; + + let block_id = block.id(); + let was_successful = + unsafe { quill_sys::block_fill_chunk_section(chunk.x, section_y, chunk.z, block_id) }; + + if was_successful { + Ok(()) + } else { + Err(BlockAccessError::ChunkNotLoaded) + } + } + + /// Sends a custom packet to an entity. + pub fn send_plugin_message(entity: EntityId, channel: &str, data: &[u8]) { + let channel_ptr = channel.as_ptr().into(); + let data_ptr = data.as_ptr().into(); + unsafe { + quill_sys::plugin_message_send( + entity.0, + channel_ptr, + channel.len() as u32, + data_ptr, + data.len() as u32, + ) + } + } + + /// Inserts an event to the world. + pub fn insert_event<T: Component>(&self, event: T) { + let host_component = T::host_component(); + let bytes = event.to_cow_bytes(); + + unsafe { + quill_sys::add_event(host_component, bytes.as_ptr().into(), bytes.len() as u32); + } + } +} + +fn check_y_bound(pos: BlockPosition) -> Result<(), BlockAccessError> { + if pos.y < 0 || pos.y >= CHUNK_HEIGHT as i32 { + Err(BlockAccessError::YOutOfBounds) + } else { + Ok(()) + } +} + +fn check_section_y(section_y: u32) -> Result<(), BlockAccessError> { + if section_y >= 16 { + Err(BlockAccessError::YOutOfBounds) + } else { + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn check_y_bound_in_bounds() { + assert!(check_y_bound(BlockPosition::new(0, 0, 0)).is_ok()); + assert!(check_y_bound(BlockPosition::new(0, 255, 0)).is_ok()); + } + + #[test] + fn check_y_bound_out_of_bounds() { + assert!(matches!( + check_y_bound(BlockPosition::new(0, -1, 0)), + Err(BlockAccessError::YOutOfBounds) + )); + assert!(matches!( + check_y_bound(BlockPosition::new(0, 256, 0)), + Err(BlockAccessError::YOutOfBounds) + )); + } + + #[test] + fn check_section_y_in_bounds() { + assert!(check_section_y(0).is_ok()); + assert!(check_section_y(15).is_ok()); + } + + #[test] + fn check_section_y_out_of_bounds() { + assert!(matches!( + check_section_y(16), + Err(BlockAccessError::YOutOfBounds) + )); + assert!(matches!( + check_section_y(u32::MAX), + Err(BlockAccessError::YOutOfBounds) + )); + } +} diff --git a/quill/api/src/lib.rs b/quill/api/src/lib.rs new file mode 100644 index 000000000..3334382ad --- /dev/null +++ b/quill/api/src/lib.rs @@ -0,0 +1,59 @@ +//! A WebAssembly-based plugin API for Minecraft servers. + +pub mod entities; +mod entity; +mod entity_builder; +mod game; +pub mod query; +mod setup; + +pub use entity::{Entity, EntityId}; +pub use entity_builder::EntityBuilder; +pub use game::Game; +pub use setup::Setup; + +#[doc(inline)] +pub use libcraft_blocks::{BlockKind, BlockState}; +#[doc(inline)] +pub use libcraft_core::{BlockPosition, ChunkPosition, Gamemode, Position}; +#[doc(inline)] +pub use libcraft_particles::{Particle, ParticleKind}; +#[doc(inline)] +pub use libcraft_text::*; + +#[doc(inline)] +pub use quill_common::{components, entity_init::EntityInit, events, Component}; +#[doc(inline)] +pub use uuid::Uuid; + +// Needed for macros +#[doc(hidden)] +pub extern crate bincode; +#[doc(hidden)] +pub extern crate quill_sys as sys; + +pub use plugin_macro::plugin; + +/// Implement this trait for your plugin's struct. +pub trait Plugin: Sized { + /// Invoked when the plugin is enabled. + /// + /// Here, you should register systems and initialize + /// any plugin state. + /// + /// # Warning + /// This function is called when your plugin _enabled_. That + /// is not guaranteed to coincide with the time the server starts + /// up. Do not assume that the server has just started when + /// this method is called. + fn enable(game: &mut Game, setup: &mut Setup<Self>) -> Self; + + /// Invoked before the plugin is disabled. + /// + /// # Warning + /// Like [`Plugin::enable`], this method is not necessarily called + /// when the server shuts down. Users may choose to disable + /// plugins at another time. Therefore, do not assume that + /// the server is shutting down when this method is called. + fn disable(self, game: &mut Game); +} diff --git a/quill/api/src/query.rs b/quill/api/src/query.rs new file mode 100644 index 000000000..3602c25cc --- /dev/null +++ b/quill/api/src/query.rs @@ -0,0 +1,271 @@ +//! Query for all entities with a certain set of components. + +use std::{ + marker::PhantomData, + mem::MaybeUninit, + ops::{Deref, DerefMut}, +}; + +use quill_common::{entity::QueryData, Component, HostComponent, PointerMut}; + +use itertools::Itertools; + +use crate::{Entity, EntityId}; + +/// A type that can be used for a query. +/// +/// Implemented for tuples of `Query`s as well. +pub trait Query { + type Item; + type Target; + + fn add_component_types(types: &mut Vec<HostComponent>); + + fn borrowed_mut(ty: HostComponent) -> bool; + + /// # Safety + /// `component_index` must be a valid index less + /// than the number of entities in the query data. + /// + /// `component_offsets` must contain the proper byte offset + /// of the current component index. + unsafe fn get_unchecked( + data: &QueryData, + component_index: &mut usize, + component_offsets: &mut [usize], + entity: Entity, + ) -> Self::Target; +} + +impl<'a, T> Query for &'a T +where + T: Component, + [T]: ToOwned, +{ + type Item = T; + type Target = T; + + fn add_component_types(types: &mut Vec<HostComponent>) { + types.push(T::host_component()); + } + + fn borrowed_mut(_: HostComponent) -> bool { + false + } + + unsafe fn get_unchecked( + data: &QueryData, + component_index: &mut usize, + component_offsets: &mut [usize], + _: Entity, + ) -> Self::Target { + let component_len = *((data.component_lens.as_mut_ptr()).add(*component_index)) as usize; + let component_ptr = + (*(data.component_ptrs.as_mut_ptr().add(*component_index))).as_mut_ptr(); + + let offset = component_offsets[*component_index]; + let component_ptr = component_ptr.add(offset); + let component_len = component_len - offset; + + let component_bytes = std::slice::from_raw_parts(component_ptr, component_len); + let (value, advance) = T::from_bytes_unchecked(component_bytes); + + component_offsets[*component_index] += advance; + + *component_index += 1; + + value + } +} + +impl<'a, T> Query for &'a mut T +where + T: Component, + [T]: ToOwned, +{ + type Item = T; + type Target = Mut<T>; + + fn add_component_types(types: &mut Vec<HostComponent>) { + types.push(T::host_component()); + } + + fn borrowed_mut(ty: HostComponent) -> bool { + ty == T::host_component() + } + + unsafe fn get_unchecked( + data: &QueryData, + component_index: &mut usize, + component_offsets: &mut [usize], + entity: Entity, + ) -> Self::Target { + let component_len = *((data.component_lens.as_mut_ptr()).add(*component_index)) as usize; + let component_ptr = + (*(data.component_ptrs.as_mut_ptr().add(*component_index))).as_mut_ptr(); + + let offset = component_offsets[*component_index]; + let component_ptr = component_ptr.add(offset); + let component_len = component_len - offset; + + let component_bytes = std::slice::from_raw_parts(component_ptr, component_len); + let (value, advance) = T::from_bytes_unchecked(component_bytes); + + component_offsets[*component_index] += advance; + + *component_index += 1; + + Mut(value, entity) + } +} + +macro_rules! impl_query_tuple { + ($($query:ident),* $(,)?) => { + impl <$($query: Query),*> Query for ($($query,)*) { + type Item = ($($query::Item),*); + type Target = ($($query::Target),*); + + fn borrowed_mut(ty: HostComponent) -> bool { + $(if $query::borrowed_mut(ty) { return true; })* + + return false; + } + + fn add_component_types(types: &mut Vec<HostComponent>) { + $( + $query::add_component_types(types); + )* + } + + unsafe fn get_unchecked(data: &QueryData, component_index: &mut usize, component_offsets: &mut [usize], entity: Entity) -> Self::Target { + ( + $( + $query::get_unchecked(data, component_index, component_offsets, Entity::new(entity.id())) + ),* + ) + } + } + } +} + +impl_query_tuple!(A, B); +impl_query_tuple!(A, B, C); +impl_query_tuple!(A, B, C, D); +impl_query_tuple!(A, B, C, D, E); +impl_query_tuple!(A, B, C, D, E, F); +impl_query_tuple!(A, B, C, D, E, F, G); +impl_query_tuple!(A, B, C, D, E, F, G, H); +impl_query_tuple!(A, B, C, D, E, F, G, H, I); +impl_query_tuple!(A, B, C, D, E, F, G, H, I, J); +impl_query_tuple!(A, B, C, D, E, F, G, H, I, J, K); +impl_query_tuple!(A, B, C, D, E, F, G, H, I, J, K, L); +impl_query_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M); + +/// An iterator over all entities matching a query. +pub struct QueryIter<Q> { + data: QueryData, + entity_index: usize, + component_offsets: Vec<usize>, + _marker: PhantomData<Q>, +} + +impl<Q> QueryIter<Q> +where + Q: Query, +{ + pub(crate) fn new() -> Self { + let mut component_types = Vec::new(); + Q::add_component_types(&mut component_types); + + for (component_type, count) in component_types.clone().into_iter().counts() { + if count > 1 && Q::borrowed_mut(component_type) { + panic!( + "{:?} was borrowed mutably and immutably at the same time", + component_type + ) + } + } + + let mut data = MaybeUninit::uninit(); + let data = unsafe { + quill_sys::entity_query( + component_types.as_ptr().into(), + component_types.len() as u32, + PointerMut::new(&mut data), + ); + // SAFETY: `entity_query` initializes `query_data`. + data.assume_init() + }; + + let component_offsets = vec![0; component_types.len()]; + + Self { + data, + entity_index: 0, + component_offsets, + _marker: PhantomData, + } + } +} + +impl<Q> Iterator for QueryIter<Q> +where + Q: Query, +{ + type Item = (Entity, Q::Target); + + fn next(&mut self) -> Option<Self::Item> { + if self.entity_index >= self.data.num_entities as usize { + return None; + } + + let entity_id = unsafe { *(self.data.entities_ptr.as_mut_ptr()).add(self.entity_index) }; + let entity = Entity::new(EntityId(entity_id)); + + let components = unsafe { + let mut component_index = 0; + Q::get_unchecked( + &self.data, + &mut component_index, + &mut self.component_offsets, + Entity::new(entity.id()), + ) + }; + + self.entity_index += 1; + + Some((entity, components)) + } +} + +pub struct Mut<T: Component>(T, Entity); + +impl<T: Component> Deref for Mut<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<T: Component> DerefMut for Mut<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl<T: Component> std::ops::Drop for Mut<T> { + fn drop(&mut self) { + let host_component = T::host_component(); + let bytes = self.0.to_cow_bytes(); + + unsafe { + quill_sys::entity_set_component( + self.1.id().0, + host_component, + bytes.as_ptr().into(), + bytes.len() as u32, + ); + } + } +} diff --git a/quill/api/src/setup.rs b/quill/api/src/setup.rs new file mode 100644 index 000000000..0b555b25f --- /dev/null +++ b/quill/api/src/setup.rs @@ -0,0 +1,39 @@ +use std::marker::PhantomData; + +use crate::Game; + +/// Struct passed to your plugin's `enable()` function. +/// +/// Allows you to register systems, etc. +pub struct Setup<Plugin> { + _marker: PhantomData<Plugin>, +} + +impl<Plugin> Setup<Plugin> { + /// For Quill internal use only. Do not call. + #[doc(hidden)] + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self { + _marker: PhantomData, + } + } + + /// Registers a function as system to be invoked + /// every tick. + /// + /// The function should take as parameters your + /// plugin instance and an `&mut Game` and return nothing. + pub fn add_system<T: FnMut(&mut Plugin, &mut Game)>(&mut self, system: T) -> &mut Self { + let system: Box<dyn FnMut(&mut Plugin, &mut Game)> = Box::new(system); + let system_data = Box::leak(Box::new(system)) as *mut Box<_> as *mut u8; + + let name = std::any::type_name::<T>(); + + unsafe { + quill_sys::register_system(system_data.into(), name.as_ptr().into(), name.len() as u32); + } + + self + } +} diff --git a/quill/cargo-quill/Cargo.toml b/quill/cargo-quill/Cargo.toml new file mode 100644 index 000000000..c2c0ff565 --- /dev/null +++ b/quill/cargo-quill/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "cargo-quill" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +quill-plugin-format = { path = "../plugin-format" } +cargo_metadata = "0.12" +anyhow = "1" +argh = "0.1" +heck = "0.3" diff --git a/quill/cargo-quill/src/main.rs b/quill/cargo-quill/src/main.rs new file mode 100644 index 000000000..404c76118 --- /dev/null +++ b/quill/cargo-quill/src/main.rs @@ -0,0 +1,185 @@ +use anyhow::{bail, Context}; +use argh::FromArgs; +use cargo_metadata::Metadata; +use heck::CamelCase; +use quill_plugin_format::{PluginFile, PluginMetadata, PluginTarget, Triple}; +use std::{ + fs, + path::PathBuf, + process::{Command, Stdio}, +}; + +const WASM_TARGET_FEATURES: &str = "target-feature=+bulk-memory,+mutable-globals,+simd128"; +const WASM_TARGET: &str = "wasm32-wasi"; + +#[derive(Debug, FromArgs)] +/// Cargo subcommand to build and test Quill/Feather plugins. +struct CargoQuill { + #[argh(subcommand)] + subcommand: Subcommand, +} + +#[derive(Debug, FromArgs)] +#[argh(subcommand)] +enum Subcommand { + Build(Build), +} + +#[derive(Debug, FromArgs)] +#[argh(subcommand, name = "build")] +/// Build a Quill plugin. +struct Build { + #[argh(switch)] + /// whether to build in release mode + release: bool, + #[argh(switch)] + /// whether to compile to a native shared library + /// instead of a WebAssembly module + native: bool, + #[argh(option, default = "6")] + /// the compression level to compress the plugin + /// binary. 0 is worst and 9 is best. + compression_level: u32, +} + +impl Build { + pub fn module_extension(&self) -> &'static str { + if !self.native { + "wasm" + } else if cfg!(windows) { + "dll" + } else if cfg!(target_vendor = "apple") { + "dylib" + } else { + // assume Linux / other Unix + "so" + } + } + + pub fn target_dir(&self, cargo_meta: &Metadata) -> PathBuf { + let mut target_dir = cargo_meta.target_directory.clone(); + if !self.native { + target_dir.push(WASM_TARGET); + } + + if self.release { + target_dir.push("release"); + } else { + target_dir.push("debug"); + } + + target_dir + } + + pub fn module_path(&self, cargo_meta: &Metadata, plugin_meta: &PluginMetadata) -> PathBuf { + let target_dir = self.target_dir(cargo_meta); + let module_filename = plugin_meta.identifier.replace('-', "_"); + + let module_extension = self.module_extension(); + let lib_prefix = if self.native && cfg!(unix) { "lib" } else { "" }; + + target_dir.join(format!( + "{}{}.{}", + lib_prefix, module_filename, module_extension + )) + } +} + +fn main() -> anyhow::Result<()> { + let args: CargoQuill = argh::from_env(); + match args.subcommand { + Subcommand::Build(args) => build(args), + } +} + +fn build(args: Build) -> anyhow::Result<()> { + let cargo_meta = get_cargo_metadata()?; + validate_cargo_metadata(&cargo_meta)?; + + let mut command = cargo_build_command(&args); + let status = command.spawn()?.wait()?; + if !status.success() { + bail!("build failed"); + } + + let meta = find_metadata(&cargo_meta, &args)?; + let module_path = args.module_path(&cargo_meta, &meta); + let module = fs::read(&module_path) + .with_context(|| format!("failed to read {}", module_path.display()))?; + + let file = PluginFile::new(module, meta.clone()); + let target_path = module_path + .parent() + .unwrap() + .join(format!("{}.plugin", meta.identifier)); + fs::write(&target_path, file.encode(args.compression_level))?; + + println!("Wrote plugin file to {}", target_path.display()); + Ok(()) +} + +fn cargo_build_command(args: &Build) -> Command { + let mut cmd = Command::new("cargo"); + cmd.arg("rustc"); + if args.release { + cmd.arg("--release"); + } + + if !args.native { + cmd.args(&["--target", WASM_TARGET]); + cmd.args(&["--", "-C", WASM_TARGET_FEATURES]); + } + + cmd.stdout(Stdio::piped()); + + cmd +} + +fn get_cargo_metadata() -> anyhow::Result<Metadata> { + let cmd = cargo_metadata::MetadataCommand::new(); + let cargo_meta = cmd.exec()?; + Ok(cargo_meta) +} + +fn validate_cargo_metadata(cargo_meta: &Metadata) -> anyhow::Result<()> { + let package = cargo_meta.root_package().context("missing root package")?; + if !package + .targets + .iter() + .any(|t| t.crate_types.contains(&"cdylib".to_owned())) + { + bail!("crate-type = [\"cdylib\"] must be set in the plugin Cargo.toml"); + } + + Ok(()) +} + +fn find_metadata(cargo_meta: &Metadata, args: &Build) -> anyhow::Result<PluginMetadata> { + let package = cargo_meta.root_package().context("missing root package")?; + + let quill_dependency = package + .dependencies + .iter() + .find(|d| d.name == "quill") + .context("plugin does not depend on the `quill` crate")?; + + let target = if args.native { + PluginTarget::Native { + target_triple: Triple::host(), + } + } else { + PluginTarget::Wasm + }; + + let plugin_meta = PluginMetadata { + name: package.name.to_camel_case(), + identifier: package.name.clone(), + version: package.version.to_string(), + api_version: quill_dependency.req.to_string(), + description: package.description.clone(), + authors: package.authors.clone(), + target, + }; + + Ok(plugin_meta) +} diff --git a/quill/common/Cargo.toml b/quill/common/Cargo.toml new file mode 100644 index 000000000..a01736a76 --- /dev/null +++ b/quill/common/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "quill-common" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +bincode = "1" +bytemuck = { version = "1", features = ["derive"] } +derive_more = "0.99.16" +libcraft-core = { path = "../../libcraft/core" } +libcraft-particles = { path = "../../libcraft/particles" } +libcraft-text = { path = "../../libcraft/text" } +serde = { version = "1", features = ["derive"] } +smartstring = { version = "0.2", features = ["serde"] } +uuid = { version = "0.8", features = ["serde"] } + +[dev-dependencies] +quill = { path = "../api" } diff --git a/quill/common/src/block.rs b/quill/common/src/block.rs new file mode 100644 index 000000000..b997ff5e8 --- /dev/null +++ b/quill/common/src/block.rs @@ -0,0 +1,49 @@ +/// Returned from `block_get`. +/// +/// This is an FFI-safe representation of `Option<u16>`. +#[repr(transparent)] +pub struct BlockGetResult(u32); + +impl BlockGetResult { + pub fn new(block_id: Option<u16>) -> Self { + let tag = block_id.is_some() as u32; + let value = (tag << 16) | block_id.unwrap_or_default() as u32; + Self(value) + } + + /// Gets the ID of the block. + pub fn get(self) -> Option<u16> { + if self.0 >> 16 == 0 { + None + } else { + Some(self.0 as u16) + } + } + + pub fn to_u32(&self) -> u32 { + self.0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn block_get_result_some() { + let result = BlockGetResult::new(Some(311)); + assert_eq!(result.get(), Some(311)); + } + + #[test] + fn block_get_result_some_all_bits_set() { + let result = BlockGetResult::new(Some(u16::MAX)); + assert_eq!(result.get(), Some(u16::MAX)); + } + + #[test] + fn block_get_result_none() { + let result = BlockGetResult::new(None); + assert_eq!(result.get(), None); + } +} diff --git a/quill/common/src/component.rs b/quill/common/src/component.rs new file mode 100644 index 000000000..11e4c4651 --- /dev/null +++ b/quill/common/src/component.rs @@ -0,0 +1,379 @@ +//! Defines the components available to Quill plugins. + +use std::{any::TypeId, borrow::Cow as CloneOnWrite}; + +use libcraft_core::{Gamemode, Position}; +use libcraft_particles::Particle; +use uuid::Uuid; + +use crate::components::*; +use crate::entities::*; +use crate::events::*; + +/// Used to convert dynamic `HostComponent`s to +/// statically-typed generic `T`s. +/// +/// Use with [`HostComponent::visit`]. +pub trait ComponentVisitor<R> { + fn visit<T: Component>(self) -> R; +} + +/// Generates the [`HostComponent`] enum. +/// +/// Adds a method `type_id` that returns the TypeId +/// of the component's type. This is used on the +/// host to construct queries. +macro_rules! host_component_enum { + ( + $(#[$outer:meta])* + pub enum $ident:ident { + $( + $component:ident = $x:literal + ),* $(,)? + } + ) => { + c_enum! { + $(#[$outer])* + pub enum $ident { + $($component = $x,)* + } + } + + impl $ident { + pub fn type_id(self) -> TypeId { + match self { + $(Self::$component => TypeId::of::<$component>(),)* + } + } + + /// Invokes a `ComponentVisitor`'s `visit` + /// method where the type `T` is the type of this component. + pub fn visit<R>(self, visitor: impl ComponentVisitor<R>) -> R { + match self { + $(Self::$component => visitor.visit::<$component>(),)* + } + } + } + } +} + +host_component_enum! { + /// A component that is stored on the host + /// and accessible from plugins. + pub enum HostComponent { + // `Pod` components + Position = 0, + + // Entity marker components + AreaEffectCloud = 100, + ArmorStand = 101, + Arrow = 102, + Bat = 103, + Bee = 104, + Blaze = 105, + Boat = 106, + Cat = 107, + CaveSpider = 108, + Chicken = 109, + Cod = 110, + Cow = 111, + Creeper = 112, + Dolphin = 113, + Donkey = 114, + DragonFireball = 115, + Drowned = 116, + ElderGuardian = 117, + EndCrystal = 118, + EnderDragon = 119, + Enderman = 120, + Endermite = 121, + Evoker = 122, + EvokerFangs = 123, + ExperienceOrb = 124, + EyeOfEnder = 125, + FallingBlock = 126, + FireworkRocket = 127, + Fox = 128, + Ghast = 129, + Giant = 130, + Guardian = 131, + Hoglin = 132, + Horse = 133, + Husk = 134, + Illusioner = 135, + IronGolem = 136, + Item = 137, + ItemFrame = 138, + Fireball = 139, + LeashKnot = 140, + LightningBolt = 141, + Llama = 142, + LlamaSpit = 143, + MagmaCube = 144, + Minecart = 145, + ChestMinecart = 146, + CommandBlockMinecart = 147, + FurnaceMinecart = 148, + HopperMinecart = 149, + SpawnerMinecart = 150, + TntMinecart = 151, + Mule = 152, + Mooshroom = 153, + Ocelot = 154, + Painting = 155, + Panda = 156, + Parrot = 157, + Phantom = 158, + Pig = 159, + Piglin = 160, + Pillager = 161, + PolarBear = 162, + Tnt = 163, + Pufferfish = 164, + Rabbit = 165, + Ravager = 166, + Salmon = 167, + Sheep = 168, + Shulker = 169, + ShulkerBullet = 170, + Silverfish = 171, + Skeleton = 172, + SkeletonHorse = 173, + Slime = 174, + SmallFireball = 175, + SnowGolem = 176, + Snowball = 177, + SpectralArrow = 178, + Spider = 179, + Squid = 180, + Stray = 181, + Strider = 182, + Egg = 183, + EnderPearl = 184, + ExperienceBottle = 185, + Potion = 186, + Trident = 187, + TraderLlama = 188, + TropicalFish = 189, + Turtle = 190, + Vex = 191, + Villager = 192, + Vindicator = 193, + WanderingTrader = 194, + Witch = 195, + Wither = 196, + WitherSkeleton = 197, + WitherSkull = 198, + Wolf = 199, + Zoglin = 200, + Zombie = 201, + ZombieHorse = 202, + ZombieVillager = 203, + ZombifiedPiglin = 204, + Player = 205, + FishingBobber = 206, + PiglinBrute = 207, + + // `bincode` components + Gamemode = 1000, + Uuid = 1001, + OnGround = 1002, + Name = 1003, + CustomName = 1004, + Particle = 1005, + InteractEntityEvent = 1006, + BlockPlacementEvent = 1007, + BlockInteractEvent = 1008, + CreativeFlying = 1009, + CreativeFlyingEvent = 1010, + Sneaking = 1011, + SneakEvent = 1012, + Sprinting = 1013, + SprintEvent = 1014, + PreviousGamemode = 1015, + Health = 1016, + WalkSpeed = 1017, + CreativeFlyingSpeed = 1018, + CanCreativeFly = 1019, + CanBuild = 1020, + Instabreak = 1021, + Invulnerable = 1022, + PlayerJoinEvent = 1023, + EntityRemoveEvent = 1024, + EntityCreateEvent = 1025, + GamemodeEvent = 1026, + InstabreakEvent = 1027, + FlyingAbilityEvent = 1028, + BuildingAbilityEvent = 1029, + InvulnerabilityEvent = 1030, + } +} + +/// How a component will be serialized. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum SerializationMethod { + /// Copy raw bytes with `bytemuck`. + Bytemuck, + /// Serialize into a `Vec` with `bincode. + Bincode, +} + +/// A type that can be used as a component. +/// +/// # Safety +/// [`Component::from_bytes`] must return `Some(_)` if given +/// any byte slice returned by [`Component::to_bytes`]. A violation +/// if this contract may result in undefined behavior +/// on the plugin side. +pub unsafe trait Component: Send + Sync + Sized + 'static { + /// How this component will be serialized. + const SERIALIZATION_METHOD: SerializationMethod; + + /// Returns the [`HostComponent`] corresponding to this + /// component. + /// + /// # Contract + /// A sound implementation of this method _must_ + /// return the `HostComponent` corresponding to + /// this type. + fn host_component() -> HostComponent; + + /// Serializes this component to bytes suitable + /// for deserialization by `from_bytes`. + /// + /// Should panic if `Self::SERIALIZATION_METHOD == SerializationMethod::Bytemuck`. + fn to_bytes(&self, target: &mut Vec<u8>); + + /// Gets this component as a byte slice. + /// + /// Should panic if `Self::SERIALIZATION_METHOD != SerializationMethod::Bytemuck`. + fn as_bytes(&self) -> &[u8]; + + /// Deserializes this component from bytes + /// returned by [`Component::to_bytes`]. + /// + /// Returns the number of bytes used to deserialize + /// `self`. `bytes` may have a greater length than is needed. + /// + /// # Contract + /// A sound implementation of this method _must_ + /// return `Some(_)` for all values of `bytes` + /// that can be returned by `Self::to_bytes`. + fn from_bytes(bytes: &[u8]) -> Option<(Self, usize)>; + + /// Deserializes this component from bytes returned by [`Component::to_bytes`] + /// without validating correctness. + /// + /// The default implementation of this method calls [`Self::from_bytes`] + /// and then performs an unchecked unwrap. + /// + /// # Safety + /// Behavior is undefined if `bytes` was not previously + /// returned from a call to `Self::to_bytes`. + unsafe fn from_bytes_unchecked(bytes: &[u8]) -> (Self, usize) { + // Do an unchecked unwrap of `from_bytes`. + // This should cause the optimizer to + // remove safety checks in `bincode`, + // which may improve performance on the plugin side. + match Self::from_bytes(bytes) { + Some(this) => this, + None => std::hint::unreachable_unchecked(), + } + } + + /// Serializes `self` into bytes using + /// the appropriate `SerializationMethod`. + fn to_cow_bytes(&self) -> CloneOnWrite<[u8]> { + match Self::SERIALIZATION_METHOD { + SerializationMethod::Bytemuck => CloneOnWrite::Borrowed(self.as_bytes()), + SerializationMethod::Bincode => { + let mut buffer = Vec::new(); + self.to_bytes(&mut buffer); + CloneOnWrite::Owned(buffer) + } + } + } +} + +macro_rules! pod_component_impl { + ($type:ident) => { + unsafe impl crate::component::Component for $type { + const SERIALIZATION_METHOD: crate::component::SerializationMethod = + crate::component::SerializationMethod::Bytemuck; + + fn host_component() -> crate::component::HostComponent { + crate::component::HostComponent::$type + } + + fn to_bytes(&self, _target: &mut Vec<u8>) { + unreachable!() + } + + fn as_bytes(&self) -> &[u8] { + bytemuck::cast_slice(std::slice::from_ref(self)) + } + + fn from_bytes(bytes: &[u8]) -> Option<(Self, usize)> { + let this = bytemuck::try_from_bytes(&bytes[..std::mem::size_of::<Self>()]) + .ok() + .copied()?; + Some((this, std::mem::size_of::<Self>())) + } + } + }; +} + +pod_component_impl!(Position); + +/** +If you are using this macro and you get the error: +``` + error[E0599]: no variant or associated item named `...` found for enum `HostComponent` in the current scope. +``` +Then you need to go to the top of the file were this macro is defined. There you find the HostCompoent enum, that +you need to add your component to. +*/ +macro_rules! bincode_component_impl { + ($type:ident) => { + unsafe impl crate::Component for $type { + const SERIALIZATION_METHOD: crate::component::SerializationMethod = + crate::component::SerializationMethod::Bincode; + + fn host_component() -> crate::component::HostComponent { + crate::component::HostComponent::$type + } + + fn to_bytes(&self, target: &mut Vec<u8>) { + bincode::serialize_into(target, self).expect("failed to serialize component"); + } + + fn as_bytes(&self) -> &[u8] { + unreachable!() + } + + fn from_bytes(bytes: &[u8]) -> Option<(Self, usize)> { + let mut cursor = std::io::Cursor::new(bytes); + let this = bincode::deserialize_from(&mut cursor).ok()?; + Some((this, cursor.position() as usize)) + } + } + }; +} + +bincode_component_impl!(Gamemode); +bincode_component_impl!(Uuid); +bincode_component_impl!(Particle); +bincode_component_impl!(InteractEntityEvent); +bincode_component_impl!(BlockPlacementEvent); +bincode_component_impl!(BlockInteractEvent); +bincode_component_impl!(CreativeFlyingEvent); +bincode_component_impl!(SneakEvent); +bincode_component_impl!(SprintEvent); +bincode_component_impl!(PlayerJoinEvent); +bincode_component_impl!(EntityRemoveEvent); +bincode_component_impl!(EntityCreateEvent); +bincode_component_impl!(GamemodeEvent); +bincode_component_impl!(InstabreakEvent); +bincode_component_impl!(FlyingAbilityEvent); +bincode_component_impl!(BuildingAbilityEvent); +bincode_component_impl!(InvulnerabilityEvent); diff --git a/quill/common/src/components.rs b/quill/common/src/components.rs new file mode 100644 index 000000000..352c45b69 --- /dev/null +++ b/quill/common/src/components.rs @@ -0,0 +1,286 @@ +//! Components not associated with a specific type of entity. +//! +//! See the [entities module](crate::entities) for entity-specific +//! components. + +use std::fmt::Display; + +use serde::{Deserialize, Serialize}; +use smartstring::{LazyCompact, SmartString}; + +use libcraft_core::Gamemode; + +/// Whether an entity is touching the ground. +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct OnGround(pub bool); + +bincode_component_impl!(OnGround); + +/// A player's username. +/// +/// This component is immutable. Do not +/// attempt to change it. +/// +/// Non-player entities cannot have this component. See [`CustomName`] +/// if you need to name an entity. +#[derive(Clone, Debug, Serialize, Deserialize, derive_more::Deref)] +pub struct Name(SmartString<LazyCompact>); + +bincode_component_impl!(Name); + +impl Name { + pub fn new(string: &str) -> Self { + Self(string.into()) + } + + pub fn as_str(&self) -> &str { + &*self + } +} + +impl Display for Name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +/// An entity's custom name. +/// +/// Adding this component to an entity +/// will give it a custom name, visible on the client. +/// +/// Giving a player a custom name has no effect. +#[derive(Clone, Debug, Serialize, Deserialize, derive_more::Deref, derive_more::DerefMut)] +pub struct CustomName(SmartString<LazyCompact>); + +bincode_component_impl!(CustomName); + +impl CustomName { + /// Creates a custom name from a string. + pub fn new(string: &str) -> Self { + Self(string.into()) + } + + pub fn as_str(&self) -> &str { + &*self + } + + pub fn as_mut_str(&mut self) -> &mut str { + &mut *self + } +} + +impl Display for CustomName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +/// A player's walk speed +#[derive( + Copy, Clone, Debug, PartialEq, Serialize, Deserialize, derive_more::Deref, derive_more::DerefMut, +)] +pub struct WalkSpeed(pub f32); + +bincode_component_impl!(WalkSpeed); + +impl Default for WalkSpeed { + fn default() -> Self { + WalkSpeed(0.1) + } +} + +/// A player's fly speed +#[derive( + Copy, Clone, Debug, PartialEq, Serialize, Deserialize, derive_more::Deref, derive_more::DerefMut, +)] +pub struct CreativeFlyingSpeed(pub f32); + +bincode_component_impl!(CreativeFlyingSpeed); + +impl Default for CreativeFlyingSpeed { + fn default() -> Self { + CreativeFlyingSpeed(0.05) + } +} + +/// Whether a player can fly like in creative mode +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct CanCreativeFly(pub bool); + +bincode_component_impl!(CanCreativeFly); + +/// Whether a player is flying (like in creative mode, so it does not reflect if the player is flying by other means) +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct CreativeFlying(pub bool); + +bincode_component_impl!(CreativeFlying); + +/// Whether a player can place and destroy blocks +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct CanBuild(pub bool); + +bincode_component_impl!(CanBuild); + +/// Whether a player breaks blocks instantly (like in creative mode) +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct Instabreak(pub bool); + +bincode_component_impl!(Instabreak); + +/// Whether a player is immune to damage +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct Invulnerable(pub bool); + +bincode_component_impl!(Invulnerable); + +/// Whether an entity is sneaking, like in pressing shift. +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct Sneaking(pub bool); +bincode_component_impl!(Sneaking); + +/// A player's previous gamemode +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct PreviousGamemode(pub Option<Gamemode>); + +bincode_component_impl!(PreviousGamemode); + +impl PreviousGamemode { + /// Gets a previous gamemode from its ID. + pub fn from_id(id: i8) -> Self { + PreviousGamemode(match id { + 0 => Some(Gamemode::Survival), + 1 => Some(Gamemode::Creative), + 2 => Some(Gamemode::Adventure), + 3 => Some(Gamemode::Spectator), + _ => None, + }) + } + + /// Gets this gamemode's id + pub fn id(&self) -> i8 { + match self.0 { + Some(Gamemode::Survival) => 0, + Some(Gamemode::Creative) => 1, + Some(Gamemode::Adventure) => 2, + Some(Gamemode::Spectator) => 3, + None => -1, + } + } +} + +/// Represents an entity's health +#[derive( + Copy, Clone, Debug, PartialEq, Serialize, Deserialize, derive_more::Deref, derive_more::DerefMut, +)] +pub struct Health(pub f32); +bincode_component_impl!(Health); + +/// A component on players that tracks if they are sprinting or not. +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Deref, + derive_more::DerefMut, +)] +pub struct Sprinting(pub bool); +impl Sprinting { + pub fn new(value: bool) -> Self { + Sprinting(value) + } +} +bincode_component_impl!(Sprinting); diff --git a/quill/common/src/entities.rs b/quill/common/src/entities.rs new file mode 100644 index 000000000..452be357c --- /dev/null +++ b/quill/common/src/entities.rs @@ -0,0 +1,216 @@ +pub mod area_effect_cloud; +pub use area_effect_cloud::AreaEffectCloud; +pub mod armor_stand; +pub use armor_stand::ArmorStand; +pub mod arrow; +pub use arrow::Arrow; +pub mod bat; +pub use bat::Bat; +pub mod bee; +pub use bee::Bee; +pub mod blaze; +pub use blaze::Blaze; +pub mod boat; +pub use boat::Boat; +pub mod cat; +pub use cat::Cat; +pub mod cave_spider; +pub use cave_spider::CaveSpider; +pub mod chicken; +pub use chicken::Chicken; +pub mod cod; +pub use cod::Cod; +pub mod cow; +pub use cow::Cow; +pub mod creeper; +pub use creeper::Creeper; +pub mod dolphin; +pub use dolphin::Dolphin; +pub mod donkey; +pub use donkey::Donkey; +pub mod dragon_fireball; +pub use dragon_fireball::DragonFireball; +pub mod drowned; +pub use drowned::Drowned; +pub mod elder_guardian; +pub use elder_guardian::ElderGuardian; +pub mod end_crystal; +pub use end_crystal::EndCrystal; +pub mod ender_dragon; +pub use ender_dragon::EnderDragon; +pub mod enderman; +pub use enderman::Enderman; +pub mod endermite; +pub use endermite::Endermite; +pub mod evoker; +pub use evoker::Evoker; +pub mod evoker_fangs; +pub use evoker_fangs::EvokerFangs; +pub mod experience_orb; +pub use experience_orb::ExperienceOrb; +pub mod eye_of_ender; +pub use eye_of_ender::EyeOfEnder; +pub mod falling_block; +pub use falling_block::FallingBlock; +pub mod firework_rocket; +pub use firework_rocket::FireworkRocket; +pub mod fox; +pub use fox::Fox; +pub mod ghast; +pub use ghast::Ghast; +pub mod giant; +pub use giant::Giant; +pub mod guardian; +pub use guardian::Guardian; +pub mod hoglin; +pub use hoglin::Hoglin; +pub mod horse; +pub use horse::Horse; +pub mod husk; +pub use husk::Husk; +pub mod illusioner; +pub use illusioner::Illusioner; +pub mod iron_golem; +pub use iron_golem::IronGolem; +pub mod item; +pub use item::Item; +pub mod item_frame; +pub use item_frame::ItemFrame; +pub mod fireball; +pub use fireball::Fireball; +pub mod leash_knot; +pub use leash_knot::LeashKnot; +pub mod lightning_bolt; +pub use lightning_bolt::LightningBolt; +pub mod llama; +pub use llama::Llama; +pub mod llama_spit; +pub use llama_spit::LlamaSpit; +pub mod magma_cube; +pub use magma_cube::MagmaCube; +pub mod minecart; +pub use minecart::Minecart; +pub mod chest_minecart; +pub use chest_minecart::ChestMinecart; +pub mod command_block_minecart; +pub use command_block_minecart::CommandBlockMinecart; +pub mod furnace_minecart; +pub use furnace_minecart::FurnaceMinecart; +pub mod hopper_minecart; +pub use hopper_minecart::HopperMinecart; +pub mod spawner_minecart; +pub use spawner_minecart::SpawnerMinecart; +pub mod tnt_minecart; +pub use tnt_minecart::TntMinecart; +pub mod mule; +pub use mule::Mule; +pub mod mooshroom; +pub use mooshroom::Mooshroom; +pub mod ocelot; +pub use ocelot::Ocelot; +pub mod painting; +pub use painting::Painting; +pub mod panda; +pub use panda::Panda; +pub mod parrot; +pub use parrot::Parrot; +pub mod phantom; +pub use phantom::Phantom; +pub mod pig; +pub use pig::Pig; +pub mod piglin; +pub use piglin::Piglin; +pub mod piglin_brute; +pub use piglin_brute::PiglinBrute; +pub mod pillager; +pub use pillager::Pillager; +pub mod polar_bear; +pub use polar_bear::PolarBear; +pub mod tnt; +pub use tnt::Tnt; +pub mod pufferfish; +pub use pufferfish::Pufferfish; +pub mod rabbit; +pub use rabbit::Rabbit; +pub mod ravager; +pub use ravager::Ravager; +pub mod salmon; +pub use salmon::Salmon; +pub mod sheep; +pub use sheep::Sheep; +pub mod shulker; +pub use shulker::Shulker; +pub mod shulker_bullet; +pub use shulker_bullet::ShulkerBullet; +pub mod silverfish; +pub use silverfish::Silverfish; +pub mod skeleton; +pub use skeleton::Skeleton; +pub mod skeleton_horse; +pub use skeleton_horse::SkeletonHorse; +pub mod slime; +pub use slime::Slime; +pub mod small_fireball; +pub use small_fireball::SmallFireball; +pub mod snow_golem; +pub use snow_golem::SnowGolem; +pub mod snowball; +pub use snowball::Snowball; +pub mod spectral_arrow; +pub use spectral_arrow::SpectralArrow; +pub mod spider; +pub use spider::Spider; +pub mod squid; +pub use squid::Squid; +pub mod stray; +pub use stray::Stray; +pub mod strider; +pub use strider::Strider; +pub mod egg; +pub use egg::Egg; +pub mod ender_pearl; +pub use ender_pearl::EnderPearl; +pub mod experience_bottle; +pub use experience_bottle::ExperienceBottle; +pub mod potion; +pub use potion::Potion; +pub mod trident; +pub use trident::Trident; +pub mod trader_llama; +pub use trader_llama::TraderLlama; +pub mod tropical_fish; +pub use tropical_fish::TropicalFish; +pub mod turtle; +pub use turtle::Turtle; +pub mod vex; +pub use vex::Vex; +pub mod villager; +pub use villager::Villager; +pub mod vindicator; +pub use vindicator::Vindicator; +pub mod wandering_trader; +pub use wandering_trader::WanderingTrader; +pub mod witch; +pub use witch::Witch; +pub mod wither; +pub use wither::Wither; +pub mod wither_skeleton; +pub use wither_skeleton::WitherSkeleton; +pub mod wither_skull; +pub use wither_skull::WitherSkull; +pub mod wolf; +pub use wolf::Wolf; +pub mod zoglin; +pub use zoglin::Zoglin; +pub mod zombie; +pub use zombie::Zombie; +pub mod zombie_horse; +pub use zombie_horse::ZombieHorse; +pub mod zombie_villager; +pub use zombie_villager::ZombieVillager; +pub mod zombified_piglin; +pub use zombified_piglin::ZombifiedPiglin; +pub mod player; +pub use player::Player; +pub mod fishing_bobber; +pub use fishing_bobber::FishingBobber; diff --git a/quill/common/src/entities/area_effect_cloud.rs b/quill/common/src/entities/area_effect_cloud.rs new file mode 100644 index 000000000..da07f1ab0 --- /dev/null +++ b/quill/common/src/entities/area_effect_cloud.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for area effect cloud entities. +/// +/// # Example +/// A system that queries for all area effect clouds: +/// ```no_run +/// use quill::{Game, Position, entities::AreaEffectCloud}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &AreaEffectCloud)>() { +/// println!("Found a area effect cloud with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct AreaEffectCloud; + +pod_component_impl!(AreaEffectCloud); diff --git a/quill/common/src/entities/armor_stand.rs b/quill/common/src/entities/armor_stand.rs new file mode 100644 index 000000000..53edaf229 --- /dev/null +++ b/quill/common/src/entities/armor_stand.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for armor stand entities. +/// +/// # Example +/// A system that queries for all armor stands: +/// ```no_run +/// use quill::{Game, Position, entities::ArmorStand}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ArmorStand)>() { +/// println!("Found a armor stand with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ArmorStand; + +pod_component_impl!(ArmorStand); diff --git a/quill/common/src/entities/arrow.rs b/quill/common/src/entities/arrow.rs new file mode 100644 index 000000000..6267a47c3 --- /dev/null +++ b/quill/common/src/entities/arrow.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for arrow entities. +/// +/// # Example +/// A system that queries for all arrows: +/// ```no_run +/// use quill::{Game, Position, entities::Arrow}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Arrow)>() { +/// println!("Found a arrow with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Arrow; + +pod_component_impl!(Arrow); diff --git a/quill/common/src/entities/bat.rs b/quill/common/src/entities/bat.rs new file mode 100644 index 000000000..82a6f13d5 --- /dev/null +++ b/quill/common/src/entities/bat.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for bat entities. +/// +/// # Example +/// A system that queries for all bats: +/// ```no_run +/// use quill::{Game, Position, entities::Bat}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Bat)>() { +/// println!("Found a bat with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Bat; + +pod_component_impl!(Bat); diff --git a/quill/common/src/entities/bee.rs b/quill/common/src/entities/bee.rs new file mode 100644 index 000000000..ee81b1567 --- /dev/null +++ b/quill/common/src/entities/bee.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for bee entities. +/// +/// # Example +/// A system that queries for all bees: +/// ```no_run +/// use quill::{Game, Position, entities::Bee}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Bee)>() { +/// println!("Found a bee with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Bee; + +pod_component_impl!(Bee); diff --git a/quill/common/src/entities/blaze.rs b/quill/common/src/entities/blaze.rs new file mode 100644 index 000000000..abf9c986e --- /dev/null +++ b/quill/common/src/entities/blaze.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for blaze entities. +/// +/// # Example +/// A system that queries for all blazes: +/// ```no_run +/// use quill::{Game, Position, entities::Blaze}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Blaze)>() { +/// println!("Found a blaze with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Blaze; + +pod_component_impl!(Blaze); diff --git a/quill/common/src/entities/boat.rs b/quill/common/src/entities/boat.rs new file mode 100644 index 000000000..21d260449 --- /dev/null +++ b/quill/common/src/entities/boat.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for boat entities. +/// +/// # Example +/// A system that queries for all boats: +/// ```no_run +/// use quill::{Game, Position, entities::Boat}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Boat)>() { +/// println!("Found a boat with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Boat; + +pod_component_impl!(Boat); diff --git a/quill/common/src/entities/cat.rs b/quill/common/src/entities/cat.rs new file mode 100644 index 000000000..b8f0721e3 --- /dev/null +++ b/quill/common/src/entities/cat.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for cat entities. +/// +/// # Example +/// A system that queries for all cats: +/// ```no_run +/// use quill::{Game, Position, entities::Cat}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Cat)>() { +/// println!("Found a cat with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Cat; + +pod_component_impl!(Cat); diff --git a/quill/common/src/entities/cave_spider.rs b/quill/common/src/entities/cave_spider.rs new file mode 100644 index 000000000..c600f48b3 --- /dev/null +++ b/quill/common/src/entities/cave_spider.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for cave spider entities. +/// +/// # Example +/// A system that queries for all cave spiders: +/// ```no_run +/// use quill::{Game, Position, entities::CaveSpider}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &CaveSpider)>() { +/// println!("Found a cave spider with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct CaveSpider; + +pod_component_impl!(CaveSpider); diff --git a/quill/common/src/entities/chest_minecart.rs b/quill/common/src/entities/chest_minecart.rs new file mode 100644 index 000000000..010a314c7 --- /dev/null +++ b/quill/common/src/entities/chest_minecart.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for chest minecart entities. +/// +/// # Example +/// A system that queries for all chest minecarts: +/// ```no_run +/// use quill::{Game, Position, entities::ChestMinecart}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ChestMinecart)>() { +/// println!("Found a chest minecart with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ChestMinecart; + +pod_component_impl!(ChestMinecart); diff --git a/quill/common/src/entities/chicken.rs b/quill/common/src/entities/chicken.rs new file mode 100644 index 000000000..236399d04 --- /dev/null +++ b/quill/common/src/entities/chicken.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for chicken entities. +/// +/// # Example +/// A system that queries for all chickens: +/// ```no_run +/// use quill::{Game, Position, entities::Chicken}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Chicken)>() { +/// println!("Found a chicken with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Chicken; + +pod_component_impl!(Chicken); diff --git a/quill/common/src/entities/cod.rs b/quill/common/src/entities/cod.rs new file mode 100644 index 000000000..528b8d369 --- /dev/null +++ b/quill/common/src/entities/cod.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for cod entities. +/// +/// # Example +/// A system that queries for all cods: +/// ```no_run +/// use quill::{Game, Position, entities::Cod}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Cod)>() { +/// println!("Found a cod with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Cod; + +pod_component_impl!(Cod); diff --git a/quill/common/src/entities/command_block_minecart.rs b/quill/common/src/entities/command_block_minecart.rs new file mode 100644 index 000000000..33c0ca053 --- /dev/null +++ b/quill/common/src/entities/command_block_minecart.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for command block minecart entities. +/// +/// # Example +/// A system that queries for all command block minecarts: +/// ```no_run +/// use quill::{Game, Position, entities::CommandBlockMinecart}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &CommandBlockMinecart)>() { +/// println!("Found a command block minecart with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct CommandBlockMinecart; + +pod_component_impl!(CommandBlockMinecart); diff --git a/quill/common/src/entities/cow.rs b/quill/common/src/entities/cow.rs new file mode 100644 index 000000000..adb540b9c --- /dev/null +++ b/quill/common/src/entities/cow.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for cow entities. +/// +/// # Example +/// A system that queries for all cows: +/// ```no_run +/// use quill::{Game, Position, entities::Cow}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Cow)>() { +/// println!("Found a cow with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Cow; + +pod_component_impl!(Cow); diff --git a/quill/common/src/entities/creeper.rs b/quill/common/src/entities/creeper.rs new file mode 100644 index 000000000..48261737f --- /dev/null +++ b/quill/common/src/entities/creeper.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for creeper entities. +/// +/// # Example +/// A system that queries for all creepers: +/// ```no_run +/// use quill::{Game, Position, entities::Creeper}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Creeper)>() { +/// println!("Found a creeper with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Creeper; + +pod_component_impl!(Creeper); diff --git a/quill/common/src/entities/dolphin.rs b/quill/common/src/entities/dolphin.rs new file mode 100644 index 000000000..c763c7a65 --- /dev/null +++ b/quill/common/src/entities/dolphin.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for dolphin entities. +/// +/// # Example +/// A system that queries for all dolphins: +/// ```no_run +/// use quill::{Game, Position, entities::Dolphin}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Dolphin)>() { +/// println!("Found a dolphin with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Dolphin; + +pod_component_impl!(Dolphin); diff --git a/quill/common/src/entities/donkey.rs b/quill/common/src/entities/donkey.rs new file mode 100644 index 000000000..5c9565572 --- /dev/null +++ b/quill/common/src/entities/donkey.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for donkey entities. +/// +/// # Example +/// A system that queries for all donkeys: +/// ```no_run +/// use quill::{Game, Position, entities::Donkey}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Donkey)>() { +/// println!("Found a donkey with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Donkey; + +pod_component_impl!(Donkey); diff --git a/quill/common/src/entities/dragon_fireball.rs b/quill/common/src/entities/dragon_fireball.rs new file mode 100644 index 000000000..2ecb539ff --- /dev/null +++ b/quill/common/src/entities/dragon_fireball.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for dragon fireball entities. +/// +/// # Example +/// A system that queries for all dragon fireballs: +/// ```no_run +/// use quill::{Game, Position, entities::DragonFireball}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &DragonFireball)>() { +/// println!("Found a dragon fireball with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct DragonFireball; + +pod_component_impl!(DragonFireball); diff --git a/quill/common/src/entities/drowned.rs b/quill/common/src/entities/drowned.rs new file mode 100644 index 000000000..bcf1fa93f --- /dev/null +++ b/quill/common/src/entities/drowned.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for drowned entities. +/// +/// # Example +/// A system that queries for all drowneds: +/// ```no_run +/// use quill::{Game, Position, entities::Drowned}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Drowned)>() { +/// println!("Found a drowned with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Drowned; + +pod_component_impl!(Drowned); diff --git a/quill/common/src/entities/egg.rs b/quill/common/src/entities/egg.rs new file mode 100644 index 000000000..0c89551cc --- /dev/null +++ b/quill/common/src/entities/egg.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for egg entities. +/// +/// # Example +/// A system that queries for all eggs: +/// ```no_run +/// use quill::{Game, Position, entities::Egg}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Egg)>() { +/// println!("Found a egg with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Egg; + +pod_component_impl!(Egg); diff --git a/quill/common/src/entities/elder_guardian.rs b/quill/common/src/entities/elder_guardian.rs new file mode 100644 index 000000000..ea2503448 --- /dev/null +++ b/quill/common/src/entities/elder_guardian.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for elder guardian entities. +/// +/// # Example +/// A system that queries for all elder guardians: +/// ```no_run +/// use quill::{Game, Position, entities::ElderGuardian}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ElderGuardian)>() { +/// println!("Found a elder guardian with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ElderGuardian; + +pod_component_impl!(ElderGuardian); diff --git a/quill/common/src/entities/end_crystal.rs b/quill/common/src/entities/end_crystal.rs new file mode 100644 index 000000000..2ceaa8fa7 --- /dev/null +++ b/quill/common/src/entities/end_crystal.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for end crystal entities. +/// +/// # Example +/// A system that queries for all end crystals: +/// ```no_run +/// use quill::{Game, Position, entities::EndCrystal}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &EndCrystal)>() { +/// println!("Found a end crystal with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct EndCrystal; + +pod_component_impl!(EndCrystal); diff --git a/quill/common/src/entities/ender_dragon.rs b/quill/common/src/entities/ender_dragon.rs new file mode 100644 index 000000000..0ab804da3 --- /dev/null +++ b/quill/common/src/entities/ender_dragon.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for ender dragon entities. +/// +/// # Example +/// A system that queries for all ender dragons: +/// ```no_run +/// use quill::{Game, Position, entities::EnderDragon}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &EnderDragon)>() { +/// println!("Found a ender dragon with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct EnderDragon; + +pod_component_impl!(EnderDragon); diff --git a/quill/common/src/entities/ender_pearl.rs b/quill/common/src/entities/ender_pearl.rs new file mode 100644 index 000000000..4f44365cf --- /dev/null +++ b/quill/common/src/entities/ender_pearl.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for ender pearl entities. +/// +/// # Example +/// A system that queries for all ender pearls: +/// ```no_run +/// use quill::{Game, Position, entities::EnderPearl}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &EnderPearl)>() { +/// println!("Found a ender pearl with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct EnderPearl; + +pod_component_impl!(EnderPearl); diff --git a/quill/common/src/entities/enderman.rs b/quill/common/src/entities/enderman.rs new file mode 100644 index 000000000..393fce912 --- /dev/null +++ b/quill/common/src/entities/enderman.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for enderman entities. +/// +/// # Example +/// A system that queries for all endermans: +/// ```no_run +/// use quill::{Game, Position, entities::Enderman}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Enderman)>() { +/// println!("Found a enderman with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Enderman; + +pod_component_impl!(Enderman); diff --git a/quill/common/src/entities/endermite.rs b/quill/common/src/entities/endermite.rs new file mode 100644 index 000000000..cc4b19dd9 --- /dev/null +++ b/quill/common/src/entities/endermite.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for endermite entities. +/// +/// # Example +/// A system that queries for all endermites: +/// ```no_run +/// use quill::{Game, Position, entities::Endermite}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Endermite)>() { +/// println!("Found a endermite with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Endermite; + +pod_component_impl!(Endermite); diff --git a/quill/common/src/entities/evoker.rs b/quill/common/src/entities/evoker.rs new file mode 100644 index 000000000..118fb90da --- /dev/null +++ b/quill/common/src/entities/evoker.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for evoker entities. +/// +/// # Example +/// A system that queries for all evokers: +/// ```no_run +/// use quill::{Game, Position, entities::Evoker}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Evoker)>() { +/// println!("Found a evoker with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Evoker; + +pod_component_impl!(Evoker); diff --git a/quill/common/src/entities/evoker_fangs.rs b/quill/common/src/entities/evoker_fangs.rs new file mode 100644 index 000000000..48cbb3d78 --- /dev/null +++ b/quill/common/src/entities/evoker_fangs.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for evoker fangs entities. +/// +/// # Example +/// A system that queries for all evoker fangss: +/// ```no_run +/// use quill::{Game, Position, entities::EvokerFangs}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &EvokerFangs)>() { +/// println!("Found a evoker fangs with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct EvokerFangs; + +pod_component_impl!(EvokerFangs); diff --git a/quill/common/src/entities/experience_bottle.rs b/quill/common/src/entities/experience_bottle.rs new file mode 100644 index 000000000..034e71d58 --- /dev/null +++ b/quill/common/src/entities/experience_bottle.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for experience bottle entities. +/// +/// # Example +/// A system that queries for all experience bottles: +/// ```no_run +/// use quill::{Game, Position, entities::ExperienceBottle}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ExperienceBottle)>() { +/// println!("Found a experience bottle with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ExperienceBottle; + +pod_component_impl!(ExperienceBottle); diff --git a/quill/common/src/entities/experience_orb.rs b/quill/common/src/entities/experience_orb.rs new file mode 100644 index 000000000..f3aa27199 --- /dev/null +++ b/quill/common/src/entities/experience_orb.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for experience orb entities. +/// +/// # Example +/// A system that queries for all experience orbs: +/// ```no_run +/// use quill::{Game, Position, entities::ExperienceOrb}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ExperienceOrb)>() { +/// println!("Found a experience orb with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ExperienceOrb; + +pod_component_impl!(ExperienceOrb); diff --git a/quill/common/src/entities/eye_of_ender.rs b/quill/common/src/entities/eye_of_ender.rs new file mode 100644 index 000000000..6c1e83cd4 --- /dev/null +++ b/quill/common/src/entities/eye_of_ender.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for eye of ender entities. +/// +/// # Example +/// A system that queries for all eye of enders: +/// ```no_run +/// use quill::{Game, Position, entities::EyeOfEnder}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &EyeOfEnder)>() { +/// println!("Found a eye of ender with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct EyeOfEnder; + +pod_component_impl!(EyeOfEnder); diff --git a/quill/common/src/entities/falling_block.rs b/quill/common/src/entities/falling_block.rs new file mode 100644 index 000000000..abc223edf --- /dev/null +++ b/quill/common/src/entities/falling_block.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for falling block entities. +/// +/// # Example +/// A system that queries for all falling blocks: +/// ```no_run +/// use quill::{Game, Position, entities::FallingBlock}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &FallingBlock)>() { +/// println!("Found a falling block with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct FallingBlock; + +pod_component_impl!(FallingBlock); diff --git a/quill/common/src/entities/fireball.rs b/quill/common/src/entities/fireball.rs new file mode 100644 index 000000000..d524648be --- /dev/null +++ b/quill/common/src/entities/fireball.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for fireball entities. +/// +/// # Example +/// A system that queries for all fireballs: +/// ```no_run +/// use quill::{Game, Position, entities::Fireball}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Fireball)>() { +/// println!("Found a fireball with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Fireball; + +pod_component_impl!(Fireball); diff --git a/quill/common/src/entities/firework_rocket.rs b/quill/common/src/entities/firework_rocket.rs new file mode 100644 index 000000000..f03f2edc3 --- /dev/null +++ b/quill/common/src/entities/firework_rocket.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for firework rocket entities. +/// +/// # Example +/// A system that queries for all firework rockets: +/// ```no_run +/// use quill::{Game, Position, entities::FireworkRocket}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &FireworkRocket)>() { +/// println!("Found a firework rocket with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct FireworkRocket; + +pod_component_impl!(FireworkRocket); diff --git a/quill/common/src/entities/fishing_bobber.rs b/quill/common/src/entities/fishing_bobber.rs new file mode 100644 index 000000000..c49a726f4 --- /dev/null +++ b/quill/common/src/entities/fishing_bobber.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for fishing bobber entities. +/// +/// # Example +/// A system that queries for all fishing bobbers: +/// ```no_run +/// use quill::{Game, Position, entities::FishingBobber}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &FishingBobber)>() { +/// println!("Found a fishing bobber with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct FishingBobber; + +pod_component_impl!(FishingBobber); diff --git a/quill/common/src/entities/fox.rs b/quill/common/src/entities/fox.rs new file mode 100644 index 000000000..c8c367585 --- /dev/null +++ b/quill/common/src/entities/fox.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for fox entities. +/// +/// # Example +/// A system that queries for all foxs: +/// ```no_run +/// use quill::{Game, Position, entities::Fox}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Fox)>() { +/// println!("Found a fox with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Fox; + +pod_component_impl!(Fox); diff --git a/quill/common/src/entities/furnace_minecart.rs b/quill/common/src/entities/furnace_minecart.rs new file mode 100644 index 000000000..259647d1d --- /dev/null +++ b/quill/common/src/entities/furnace_minecart.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for furnace minecart entities. +/// +/// # Example +/// A system that queries for all furnace minecarts: +/// ```no_run +/// use quill::{Game, Position, entities::FurnaceMinecart}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &FurnaceMinecart)>() { +/// println!("Found a furnace minecart with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct FurnaceMinecart; + +pod_component_impl!(FurnaceMinecart); diff --git a/quill/common/src/entities/ghast.rs b/quill/common/src/entities/ghast.rs new file mode 100644 index 000000000..ee1b579d3 --- /dev/null +++ b/quill/common/src/entities/ghast.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for ghast entities. +/// +/// # Example +/// A system that queries for all ghasts: +/// ```no_run +/// use quill::{Game, Position, entities::Ghast}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Ghast)>() { +/// println!("Found a ghast with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Ghast; + +pod_component_impl!(Ghast); diff --git a/quill/common/src/entities/giant.rs b/quill/common/src/entities/giant.rs new file mode 100644 index 000000000..4dd05874a --- /dev/null +++ b/quill/common/src/entities/giant.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for giant entities. +/// +/// # Example +/// A system that queries for all giants: +/// ```no_run +/// use quill::{Game, Position, entities::Giant}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Giant)>() { +/// println!("Found a giant with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Giant; + +pod_component_impl!(Giant); diff --git a/quill/common/src/entities/guardian.rs b/quill/common/src/entities/guardian.rs new file mode 100644 index 000000000..29ec01eef --- /dev/null +++ b/quill/common/src/entities/guardian.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for guardian entities. +/// +/// # Example +/// A system that queries for all guardians: +/// ```no_run +/// use quill::{Game, Position, entities::Guardian}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Guardian)>() { +/// println!("Found a guardian with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Guardian; + +pod_component_impl!(Guardian); diff --git a/quill/common/src/entities/hoglin.rs b/quill/common/src/entities/hoglin.rs new file mode 100644 index 000000000..621867f00 --- /dev/null +++ b/quill/common/src/entities/hoglin.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for hoglin entities. +/// +/// # Example +/// A system that queries for all hoglins: +/// ```no_run +/// use quill::{Game, Position, entities::Hoglin}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Hoglin)>() { +/// println!("Found a hoglin with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Hoglin; + +pod_component_impl!(Hoglin); diff --git a/quill/common/src/entities/hopper_minecart.rs b/quill/common/src/entities/hopper_minecart.rs new file mode 100644 index 000000000..04f1453ea --- /dev/null +++ b/quill/common/src/entities/hopper_minecart.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for hopper minecart entities. +/// +/// # Example +/// A system that queries for all hopper minecarts: +/// ```no_run +/// use quill::{Game, Position, entities::HopperMinecart}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &HopperMinecart)>() { +/// println!("Found a hopper minecart with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct HopperMinecart; + +pod_component_impl!(HopperMinecart); diff --git a/quill/common/src/entities/horse.rs b/quill/common/src/entities/horse.rs new file mode 100644 index 000000000..dd6d52ea7 --- /dev/null +++ b/quill/common/src/entities/horse.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for horse entities. +/// +/// # Example +/// A system that queries for all horses: +/// ```no_run +/// use quill::{Game, Position, entities::Horse}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Horse)>() { +/// println!("Found a horse with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Horse; + +pod_component_impl!(Horse); diff --git a/quill/common/src/entities/husk.rs b/quill/common/src/entities/husk.rs new file mode 100644 index 000000000..37a7cc2e9 --- /dev/null +++ b/quill/common/src/entities/husk.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for husk entities. +/// +/// # Example +/// A system that queries for all husks: +/// ```no_run +/// use quill::{Game, Position, entities::Husk}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Husk)>() { +/// println!("Found a husk with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Husk; + +pod_component_impl!(Husk); diff --git a/quill/common/src/entities/illusioner.rs b/quill/common/src/entities/illusioner.rs new file mode 100644 index 000000000..4efc89bbe --- /dev/null +++ b/quill/common/src/entities/illusioner.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for illusioner entities. +/// +/// # Example +/// A system that queries for all illusioners: +/// ```no_run +/// use quill::{Game, Position, entities::Illusioner}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Illusioner)>() { +/// println!("Found a illusioner with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Illusioner; + +pod_component_impl!(Illusioner); diff --git a/quill/common/src/entities/iron_golem.rs b/quill/common/src/entities/iron_golem.rs new file mode 100644 index 000000000..6ee2f96bd --- /dev/null +++ b/quill/common/src/entities/iron_golem.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for iron golem entities. +/// +/// # Example +/// A system that queries for all iron golems: +/// ```no_run +/// use quill::{Game, Position, entities::IronGolem}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &IronGolem)>() { +/// println!("Found a iron golem with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct IronGolem; + +pod_component_impl!(IronGolem); diff --git a/quill/common/src/entities/item.rs b/quill/common/src/entities/item.rs new file mode 100644 index 000000000..9c37e4a45 --- /dev/null +++ b/quill/common/src/entities/item.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for item entities. +/// +/// # Example +/// A system that queries for all items: +/// ```no_run +/// use quill::{Game, Position, entities::Item}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Item)>() { +/// println!("Found a item with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Item; + +pod_component_impl!(Item); diff --git a/quill/common/src/entities/item_frame.rs b/quill/common/src/entities/item_frame.rs new file mode 100644 index 000000000..1eb6157d6 --- /dev/null +++ b/quill/common/src/entities/item_frame.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for item frame entities. +/// +/// # Example +/// A system that queries for all item frames: +/// ```no_run +/// use quill::{Game, Position, entities::ItemFrame}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ItemFrame)>() { +/// println!("Found a item frame with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ItemFrame; + +pod_component_impl!(ItemFrame); diff --git a/quill/common/src/entities/leash_knot.rs b/quill/common/src/entities/leash_knot.rs new file mode 100644 index 000000000..548f0b546 --- /dev/null +++ b/quill/common/src/entities/leash_knot.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for leash knot entities. +/// +/// # Example +/// A system that queries for all leash knots: +/// ```no_run +/// use quill::{Game, Position, entities::LeashKnot}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &LeashKnot)>() { +/// println!("Found a leash knot with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct LeashKnot; + +pod_component_impl!(LeashKnot); diff --git a/quill/common/src/entities/lightning_bolt.rs b/quill/common/src/entities/lightning_bolt.rs new file mode 100644 index 000000000..e02e12761 --- /dev/null +++ b/quill/common/src/entities/lightning_bolt.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for lightning bolt entities. +/// +/// # Example +/// A system that queries for all lightning bolts: +/// ```no_run +/// use quill::{Game, Position, entities::LightningBolt}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &LightningBolt)>() { +/// println!("Found a lightning bolt with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct LightningBolt; + +pod_component_impl!(LightningBolt); diff --git a/quill/common/src/entities/llama.rs b/quill/common/src/entities/llama.rs new file mode 100644 index 000000000..0d6ebab54 --- /dev/null +++ b/quill/common/src/entities/llama.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for llama entities. +/// +/// # Example +/// A system that queries for all llamas: +/// ```no_run +/// use quill::{Game, Position, entities::Llama}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Llama)>() { +/// println!("Found a llama with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Llama; + +pod_component_impl!(Llama); diff --git a/quill/common/src/entities/llama_spit.rs b/quill/common/src/entities/llama_spit.rs new file mode 100644 index 000000000..f6a4948de --- /dev/null +++ b/quill/common/src/entities/llama_spit.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for llama spit entities. +/// +/// # Example +/// A system that queries for all llama spits: +/// ```no_run +/// use quill::{Game, Position, entities::LlamaSpit}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &LlamaSpit)>() { +/// println!("Found a llama spit with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct LlamaSpit; + +pod_component_impl!(LlamaSpit); diff --git a/quill/common/src/entities/magma_cube.rs b/quill/common/src/entities/magma_cube.rs new file mode 100644 index 000000000..ab0b18736 --- /dev/null +++ b/quill/common/src/entities/magma_cube.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for magma cube entities. +/// +/// # Example +/// A system that queries for all magma cubes: +/// ```no_run +/// use quill::{Game, Position, entities::MagmaCube}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &MagmaCube)>() { +/// println!("Found a magma cube with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct MagmaCube; + +pod_component_impl!(MagmaCube); diff --git a/quill/common/src/entities/minecart.rs b/quill/common/src/entities/minecart.rs new file mode 100644 index 000000000..25919dfbf --- /dev/null +++ b/quill/common/src/entities/minecart.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for minecart entities. +/// +/// # Example +/// A system that queries for all minecarts: +/// ```no_run +/// use quill::{Game, Position, entities::Minecart}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Minecart)>() { +/// println!("Found a minecart with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Minecart; + +pod_component_impl!(Minecart); diff --git a/quill/common/src/entities/mooshroom.rs b/quill/common/src/entities/mooshroom.rs new file mode 100644 index 000000000..2f5a6403d --- /dev/null +++ b/quill/common/src/entities/mooshroom.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for mooshroom entities. +/// +/// # Example +/// A system that queries for all mooshrooms: +/// ```no_run +/// use quill::{Game, Position, entities::Mooshroom}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Mooshroom)>() { +/// println!("Found a mooshroom with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Mooshroom; + +pod_component_impl!(Mooshroom); diff --git a/quill/common/src/entities/mule.rs b/quill/common/src/entities/mule.rs new file mode 100644 index 000000000..fcebeabd9 --- /dev/null +++ b/quill/common/src/entities/mule.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for mule entities. +/// +/// # Example +/// A system that queries for all mules: +/// ```no_run +/// use quill::{Game, Position, entities::Mule}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Mule)>() { +/// println!("Found a mule with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Mule; + +pod_component_impl!(Mule); diff --git a/quill/common/src/entities/ocelot.rs b/quill/common/src/entities/ocelot.rs new file mode 100644 index 000000000..31b474209 --- /dev/null +++ b/quill/common/src/entities/ocelot.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for ocelot entities. +/// +/// # Example +/// A system that queries for all ocelots: +/// ```no_run +/// use quill::{Game, Position, entities::Ocelot}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Ocelot)>() { +/// println!("Found a ocelot with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Ocelot; + +pod_component_impl!(Ocelot); diff --git a/quill/common/src/entities/painting.rs b/quill/common/src/entities/painting.rs new file mode 100644 index 000000000..e14abff7d --- /dev/null +++ b/quill/common/src/entities/painting.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for painting entities. +/// +/// # Example +/// A system that queries for all paintings: +/// ```no_run +/// use quill::{Game, Position, entities::Painting}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Painting)>() { +/// println!("Found a painting with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Painting; + +pod_component_impl!(Painting); diff --git a/quill/common/src/entities/panda.rs b/quill/common/src/entities/panda.rs new file mode 100644 index 000000000..8bcd8b544 --- /dev/null +++ b/quill/common/src/entities/panda.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for panda entities. +/// +/// # Example +/// A system that queries for all pandas: +/// ```no_run +/// use quill::{Game, Position, entities::Panda}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Panda)>() { +/// println!("Found a panda with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Panda; + +pod_component_impl!(Panda); diff --git a/quill/common/src/entities/parrot.rs b/quill/common/src/entities/parrot.rs new file mode 100644 index 000000000..f06afd167 --- /dev/null +++ b/quill/common/src/entities/parrot.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for parrot entities. +/// +/// # Example +/// A system that queries for all parrots: +/// ```no_run +/// use quill::{Game, Position, entities::Parrot}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Parrot)>() { +/// println!("Found a parrot with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Parrot; + +pod_component_impl!(Parrot); diff --git a/quill/common/src/entities/phantom.rs b/quill/common/src/entities/phantom.rs new file mode 100644 index 000000000..c5a839b8e --- /dev/null +++ b/quill/common/src/entities/phantom.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for phantom entities. +/// +/// # Example +/// A system that queries for all phantoms: +/// ```no_run +/// use quill::{Game, Position, entities::Phantom}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Phantom)>() { +/// println!("Found a phantom with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Phantom; + +pod_component_impl!(Phantom); diff --git a/quill/common/src/entities/pig.rs b/quill/common/src/entities/pig.rs new file mode 100644 index 000000000..753e2f019 --- /dev/null +++ b/quill/common/src/entities/pig.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for pig entities. +/// +/// # Example +/// A system that queries for all pigs: +/// ```no_run +/// use quill::{Game, Position, entities::Pig}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Pig)>() { +/// println!("Found a pig with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Pig; + +pod_component_impl!(Pig); diff --git a/quill/common/src/entities/piglin.rs b/quill/common/src/entities/piglin.rs new file mode 100644 index 000000000..9f5ea2633 --- /dev/null +++ b/quill/common/src/entities/piglin.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for piglin entities. +/// +/// # Example +/// A system that queries for all piglins: +/// ```no_run +/// use quill::{Game, Position, entities::Piglin}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Piglin)>() { +/// println!("Found a piglin with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Piglin; + +pod_component_impl!(Piglin); diff --git a/quill/common/src/entities/piglin_brute.rs b/quill/common/src/entities/piglin_brute.rs new file mode 100644 index 000000000..0c27b5f6f --- /dev/null +++ b/quill/common/src/entities/piglin_brute.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for piglin brute entities. +/// +/// # Example +/// A system that queries for all piglin brutes: +/// ```no_run +/// use quill::{Game, Position, entities::PiglinBrute}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &PiglinBrute)>() { +/// println!("Found a piglin brute with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct PiglinBrute; + +pod_component_impl!(PiglinBrute); diff --git a/quill/common/src/entities/pillager.rs b/quill/common/src/entities/pillager.rs new file mode 100644 index 000000000..8fb27bf60 --- /dev/null +++ b/quill/common/src/entities/pillager.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for pillager entities. +/// +/// # Example +/// A system that queries for all pillagers: +/// ```no_run +/// use quill::{Game, Position, entities::Pillager}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Pillager)>() { +/// println!("Found a pillager with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Pillager; + +pod_component_impl!(Pillager); diff --git a/quill/common/src/entities/player.rs b/quill/common/src/entities/player.rs new file mode 100644 index 000000000..d971ca5d7 --- /dev/null +++ b/quill/common/src/entities/player.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for player entities. +/// +/// # Example +/// A system that queries for all players: +/// ```no_run +/// use quill::{Game, Position, entities::Player}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Player)>() { +/// println!("Found a player with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Player; + +pod_component_impl!(Player); diff --git a/quill/common/src/entities/polar_bear.rs b/quill/common/src/entities/polar_bear.rs new file mode 100644 index 000000000..b3f0e45c9 --- /dev/null +++ b/quill/common/src/entities/polar_bear.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for polar bear entities. +/// +/// # Example +/// A system that queries for all polar bears: +/// ```no_run +/// use quill::{Game, Position, entities::PolarBear}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &PolarBear)>() { +/// println!("Found a polar bear with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct PolarBear; + +pod_component_impl!(PolarBear); diff --git a/quill/common/src/entities/potion.rs b/quill/common/src/entities/potion.rs new file mode 100644 index 000000000..77c898d86 --- /dev/null +++ b/quill/common/src/entities/potion.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for potion entities. +/// +/// # Example +/// A system that queries for all potions: +/// ```no_run +/// use quill::{Game, Position, entities::Potion}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Potion)>() { +/// println!("Found a potion with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Potion; + +pod_component_impl!(Potion); diff --git a/quill/common/src/entities/pufferfish.rs b/quill/common/src/entities/pufferfish.rs new file mode 100644 index 000000000..d400b1c6d --- /dev/null +++ b/quill/common/src/entities/pufferfish.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for pufferfish entities. +/// +/// # Example +/// A system that queries for all pufferfishs: +/// ```no_run +/// use quill::{Game, Position, entities::Pufferfish}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Pufferfish)>() { +/// println!("Found a pufferfish with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Pufferfish; + +pod_component_impl!(Pufferfish); diff --git a/quill/common/src/entities/rabbit.rs b/quill/common/src/entities/rabbit.rs new file mode 100644 index 000000000..989fde181 --- /dev/null +++ b/quill/common/src/entities/rabbit.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for rabbit entities. +/// +/// # Example +/// A system that queries for all rabbits: +/// ```no_run +/// use quill::{Game, Position, entities::Rabbit}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Rabbit)>() { +/// println!("Found a rabbit with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Rabbit; + +pod_component_impl!(Rabbit); diff --git a/quill/common/src/entities/ravager.rs b/quill/common/src/entities/ravager.rs new file mode 100644 index 000000000..e73a9e98a --- /dev/null +++ b/quill/common/src/entities/ravager.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for ravager entities. +/// +/// # Example +/// A system that queries for all ravagers: +/// ```no_run +/// use quill::{Game, Position, entities::Ravager}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Ravager)>() { +/// println!("Found a ravager with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Ravager; + +pod_component_impl!(Ravager); diff --git a/quill/common/src/entities/salmon.rs b/quill/common/src/entities/salmon.rs new file mode 100644 index 000000000..996a3b8e5 --- /dev/null +++ b/quill/common/src/entities/salmon.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for salmon entities. +/// +/// # Example +/// A system that queries for all salmons: +/// ```no_run +/// use quill::{Game, Position, entities::Salmon}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Salmon)>() { +/// println!("Found a salmon with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Salmon; + +pod_component_impl!(Salmon); diff --git a/quill/common/src/entities/sheep.rs b/quill/common/src/entities/sheep.rs new file mode 100644 index 000000000..cd7202db2 --- /dev/null +++ b/quill/common/src/entities/sheep.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for sheep entities. +/// +/// # Example +/// A system that queries for all sheeps: +/// ```no_run +/// use quill::{Game, Position, entities::Sheep}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Sheep)>() { +/// println!("Found a sheep with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Sheep; + +pod_component_impl!(Sheep); diff --git a/quill/common/src/entities/shulker.rs b/quill/common/src/entities/shulker.rs new file mode 100644 index 000000000..f33b15624 --- /dev/null +++ b/quill/common/src/entities/shulker.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for shulker entities. +/// +/// # Example +/// A system that queries for all shulkers: +/// ```no_run +/// use quill::{Game, Position, entities::Shulker}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Shulker)>() { +/// println!("Found a shulker with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Shulker; + +pod_component_impl!(Shulker); diff --git a/quill/common/src/entities/shulker_bullet.rs b/quill/common/src/entities/shulker_bullet.rs new file mode 100644 index 000000000..edd923bc4 --- /dev/null +++ b/quill/common/src/entities/shulker_bullet.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for shulker bullet entities. +/// +/// # Example +/// A system that queries for all shulker bullets: +/// ```no_run +/// use quill::{Game, Position, entities::ShulkerBullet}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ShulkerBullet)>() { +/// println!("Found a shulker bullet with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ShulkerBullet; + +pod_component_impl!(ShulkerBullet); diff --git a/quill/common/src/entities/silverfish.rs b/quill/common/src/entities/silverfish.rs new file mode 100644 index 000000000..990808a38 --- /dev/null +++ b/quill/common/src/entities/silverfish.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for silverfish entities. +/// +/// # Example +/// A system that queries for all silverfishs: +/// ```no_run +/// use quill::{Game, Position, entities::Silverfish}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Silverfish)>() { +/// println!("Found a silverfish with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Silverfish; + +pod_component_impl!(Silverfish); diff --git a/quill/common/src/entities/skeleton.rs b/quill/common/src/entities/skeleton.rs new file mode 100644 index 000000000..7162a368d --- /dev/null +++ b/quill/common/src/entities/skeleton.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for skeleton entities. +/// +/// # Example +/// A system that queries for all skeletons: +/// ```no_run +/// use quill::{Game, Position, entities::Skeleton}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Skeleton)>() { +/// println!("Found a skeleton with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Skeleton; + +pod_component_impl!(Skeleton); diff --git a/quill/common/src/entities/skeleton_horse.rs b/quill/common/src/entities/skeleton_horse.rs new file mode 100644 index 000000000..0c14ff853 --- /dev/null +++ b/quill/common/src/entities/skeleton_horse.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for skeleton horse entities. +/// +/// # Example +/// A system that queries for all skeleton horses: +/// ```no_run +/// use quill::{Game, Position, entities::SkeletonHorse}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &SkeletonHorse)>() { +/// println!("Found a skeleton horse with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct SkeletonHorse; + +pod_component_impl!(SkeletonHorse); diff --git a/quill/common/src/entities/slime.rs b/quill/common/src/entities/slime.rs new file mode 100644 index 000000000..756c503b5 --- /dev/null +++ b/quill/common/src/entities/slime.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for slime entities. +/// +/// # Example +/// A system that queries for all slimes: +/// ```no_run +/// use quill::{Game, Position, entities::Slime}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Slime)>() { +/// println!("Found a slime with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Slime; + +pod_component_impl!(Slime); diff --git a/quill/common/src/entities/small_fireball.rs b/quill/common/src/entities/small_fireball.rs new file mode 100644 index 000000000..07d50e0a2 --- /dev/null +++ b/quill/common/src/entities/small_fireball.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for small fireball entities. +/// +/// # Example +/// A system that queries for all small fireballs: +/// ```no_run +/// use quill::{Game, Position, entities::SmallFireball}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &SmallFireball)>() { +/// println!("Found a small fireball with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct SmallFireball; + +pod_component_impl!(SmallFireball); diff --git a/quill/common/src/entities/snow_golem.rs b/quill/common/src/entities/snow_golem.rs new file mode 100644 index 000000000..df0491083 --- /dev/null +++ b/quill/common/src/entities/snow_golem.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for snow golem entities. +/// +/// # Example +/// A system that queries for all snow golems: +/// ```no_run +/// use quill::{Game, Position, entities::SnowGolem}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &SnowGolem)>() { +/// println!("Found a snow golem with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct SnowGolem; + +pod_component_impl!(SnowGolem); diff --git a/quill/common/src/entities/snowball.rs b/quill/common/src/entities/snowball.rs new file mode 100644 index 000000000..ea823c696 --- /dev/null +++ b/quill/common/src/entities/snowball.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for snowball entities. +/// +/// # Example +/// A system that queries for all snowballs: +/// ```no_run +/// use quill::{Game, Position, entities::Snowball}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Snowball)>() { +/// println!("Found a snowball with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Snowball; + +pod_component_impl!(Snowball); diff --git a/quill/common/src/entities/spawner_minecart.rs b/quill/common/src/entities/spawner_minecart.rs new file mode 100644 index 000000000..c5584a9cd --- /dev/null +++ b/quill/common/src/entities/spawner_minecart.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for spawner minecart entities. +/// +/// # Example +/// A system that queries for all spawner minecarts: +/// ```no_run +/// use quill::{Game, Position, entities::SpawnerMinecart}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &SpawnerMinecart)>() { +/// println!("Found a spawner minecart with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct SpawnerMinecart; + +pod_component_impl!(SpawnerMinecart); diff --git a/quill/common/src/entities/spectral_arrow.rs b/quill/common/src/entities/spectral_arrow.rs new file mode 100644 index 000000000..8a78f908c --- /dev/null +++ b/quill/common/src/entities/spectral_arrow.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for spectral arrow entities. +/// +/// # Example +/// A system that queries for all spectral arrows: +/// ```no_run +/// use quill::{Game, Position, entities::SpectralArrow}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &SpectralArrow)>() { +/// println!("Found a spectral arrow with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct SpectralArrow; + +pod_component_impl!(SpectralArrow); diff --git a/quill/common/src/entities/spider.rs b/quill/common/src/entities/spider.rs new file mode 100644 index 000000000..85c5fcdc3 --- /dev/null +++ b/quill/common/src/entities/spider.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for spider entities. +/// +/// # Example +/// A system that queries for all spiders: +/// ```no_run +/// use quill::{Game, Position, entities::Spider}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Spider)>() { +/// println!("Found a spider with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Spider; + +pod_component_impl!(Spider); diff --git a/quill/common/src/entities/squid.rs b/quill/common/src/entities/squid.rs new file mode 100644 index 000000000..479364cb9 --- /dev/null +++ b/quill/common/src/entities/squid.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for squid entities. +/// +/// # Example +/// A system that queries for all squids: +/// ```no_run +/// use quill::{Game, Position, entities::Squid}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Squid)>() { +/// println!("Found a squid with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Squid; + +pod_component_impl!(Squid); diff --git a/quill/common/src/entities/stray.rs b/quill/common/src/entities/stray.rs new file mode 100644 index 000000000..92c952bc9 --- /dev/null +++ b/quill/common/src/entities/stray.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for stray entities. +/// +/// # Example +/// A system that queries for all strays: +/// ```no_run +/// use quill::{Game, Position, entities::Stray}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Stray)>() { +/// println!("Found a stray with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Stray; + +pod_component_impl!(Stray); diff --git a/quill/common/src/entities/strider.rs b/quill/common/src/entities/strider.rs new file mode 100644 index 000000000..63194fd1e --- /dev/null +++ b/quill/common/src/entities/strider.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for strider entities. +/// +/// # Example +/// A system that queries for all striders: +/// ```no_run +/// use quill::{Game, Position, entities::Strider}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Strider)>() { +/// println!("Found a strider with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Strider; + +pod_component_impl!(Strider); diff --git a/quill/common/src/entities/tnt.rs b/quill/common/src/entities/tnt.rs new file mode 100644 index 000000000..6dbd66814 --- /dev/null +++ b/quill/common/src/entities/tnt.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for tnt entities. +/// +/// # Example +/// A system that queries for all tnts: +/// ```no_run +/// use quill::{Game, Position, entities::Tnt}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Tnt)>() { +/// println!("Found a tnt with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Tnt; + +pod_component_impl!(Tnt); diff --git a/quill/common/src/entities/tnt_minecart.rs b/quill/common/src/entities/tnt_minecart.rs new file mode 100644 index 000000000..e9b5e4962 --- /dev/null +++ b/quill/common/src/entities/tnt_minecart.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for tnt minecart entities. +/// +/// # Example +/// A system that queries for all tnt minecarts: +/// ```no_run +/// use quill::{Game, Position, entities::TntMinecart}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &TntMinecart)>() { +/// println!("Found a tnt minecart with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct TntMinecart; + +pod_component_impl!(TntMinecart); diff --git a/quill/common/src/entities/trader_llama.rs b/quill/common/src/entities/trader_llama.rs new file mode 100644 index 000000000..e8ef11d57 --- /dev/null +++ b/quill/common/src/entities/trader_llama.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for trader llama entities. +/// +/// # Example +/// A system that queries for all trader llamas: +/// ```no_run +/// use quill::{Game, Position, entities::TraderLlama}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &TraderLlama)>() { +/// println!("Found a trader llama with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct TraderLlama; + +pod_component_impl!(TraderLlama); diff --git a/quill/common/src/entities/trident.rs b/quill/common/src/entities/trident.rs new file mode 100644 index 000000000..41612484b --- /dev/null +++ b/quill/common/src/entities/trident.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for trident entities. +/// +/// # Example +/// A system that queries for all tridents: +/// ```no_run +/// use quill::{Game, Position, entities::Trident}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Trident)>() { +/// println!("Found a trident with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Trident; + +pod_component_impl!(Trident); diff --git a/quill/common/src/entities/tropical_fish.rs b/quill/common/src/entities/tropical_fish.rs new file mode 100644 index 000000000..2d6b02c25 --- /dev/null +++ b/quill/common/src/entities/tropical_fish.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for tropical fish entities. +/// +/// # Example +/// A system that queries for all tropical fishs: +/// ```no_run +/// use quill::{Game, Position, entities::TropicalFish}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &TropicalFish)>() { +/// println!("Found a tropical fish with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct TropicalFish; + +pod_component_impl!(TropicalFish); diff --git a/quill/common/src/entities/turtle.rs b/quill/common/src/entities/turtle.rs new file mode 100644 index 000000000..efe77937b --- /dev/null +++ b/quill/common/src/entities/turtle.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for turtle entities. +/// +/// # Example +/// A system that queries for all turtles: +/// ```no_run +/// use quill::{Game, Position, entities::Turtle}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Turtle)>() { +/// println!("Found a turtle with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Turtle; + +pod_component_impl!(Turtle); diff --git a/quill/common/src/entities/vex.rs b/quill/common/src/entities/vex.rs new file mode 100644 index 000000000..e165bd310 --- /dev/null +++ b/quill/common/src/entities/vex.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for vex entities. +/// +/// # Example +/// A system that queries for all vexs: +/// ```no_run +/// use quill::{Game, Position, entities::Vex}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Vex)>() { +/// println!("Found a vex with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Vex; + +pod_component_impl!(Vex); diff --git a/quill/common/src/entities/villager.rs b/quill/common/src/entities/villager.rs new file mode 100644 index 000000000..e42e253a4 --- /dev/null +++ b/quill/common/src/entities/villager.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for villager entities. +/// +/// # Example +/// A system that queries for all villagers: +/// ```no_run +/// use quill::{Game, Position, entities::Villager}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Villager)>() { +/// println!("Found a villager with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Villager; + +pod_component_impl!(Villager); diff --git a/quill/common/src/entities/vindicator.rs b/quill/common/src/entities/vindicator.rs new file mode 100644 index 000000000..9eb5e0092 --- /dev/null +++ b/quill/common/src/entities/vindicator.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for vindicator entities. +/// +/// # Example +/// A system that queries for all vindicators: +/// ```no_run +/// use quill::{Game, Position, entities::Vindicator}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Vindicator)>() { +/// println!("Found a vindicator with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Vindicator; + +pod_component_impl!(Vindicator); diff --git a/quill/common/src/entities/wandering_trader.rs b/quill/common/src/entities/wandering_trader.rs new file mode 100644 index 000000000..a8f0c9b7a --- /dev/null +++ b/quill/common/src/entities/wandering_trader.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for wandering trader entities. +/// +/// # Example +/// A system that queries for all wandering traders: +/// ```no_run +/// use quill::{Game, Position, entities::WanderingTrader}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &WanderingTrader)>() { +/// println!("Found a wandering trader with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct WanderingTrader; + +pod_component_impl!(WanderingTrader); diff --git a/quill/common/src/entities/witch.rs b/quill/common/src/entities/witch.rs new file mode 100644 index 000000000..fcb261562 --- /dev/null +++ b/quill/common/src/entities/witch.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for witch entities. +/// +/// # Example +/// A system that queries for all witchs: +/// ```no_run +/// use quill::{Game, Position, entities::Witch}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Witch)>() { +/// println!("Found a witch with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Witch; + +pod_component_impl!(Witch); diff --git a/quill/common/src/entities/wither.rs b/quill/common/src/entities/wither.rs new file mode 100644 index 000000000..1e0a0a765 --- /dev/null +++ b/quill/common/src/entities/wither.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for wither entities. +/// +/// # Example +/// A system that queries for all withers: +/// ```no_run +/// use quill::{Game, Position, entities::Wither}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Wither)>() { +/// println!("Found a wither with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Wither; + +pod_component_impl!(Wither); diff --git a/quill/common/src/entities/wither_skeleton.rs b/quill/common/src/entities/wither_skeleton.rs new file mode 100644 index 000000000..baaff5de5 --- /dev/null +++ b/quill/common/src/entities/wither_skeleton.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for wither skeleton entities. +/// +/// # Example +/// A system that queries for all wither skeletons: +/// ```no_run +/// use quill::{Game, Position, entities::WitherSkeleton}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &WitherSkeleton)>() { +/// println!("Found a wither skeleton with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct WitherSkeleton; + +pod_component_impl!(WitherSkeleton); diff --git a/quill/common/src/entities/wither_skull.rs b/quill/common/src/entities/wither_skull.rs new file mode 100644 index 000000000..641a0a729 --- /dev/null +++ b/quill/common/src/entities/wither_skull.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for wither skull entities. +/// +/// # Example +/// A system that queries for all wither skulls: +/// ```no_run +/// use quill::{Game, Position, entities::WitherSkull}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &WitherSkull)>() { +/// println!("Found a wither skull with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct WitherSkull; + +pod_component_impl!(WitherSkull); diff --git a/quill/common/src/entities/wolf.rs b/quill/common/src/entities/wolf.rs new file mode 100644 index 000000000..4376907d6 --- /dev/null +++ b/quill/common/src/entities/wolf.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for wolf entities. +/// +/// # Example +/// A system that queries for all wolfs: +/// ```no_run +/// use quill::{Game, Position, entities::Wolf}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Wolf)>() { +/// println!("Found a wolf with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Wolf; + +pod_component_impl!(Wolf); diff --git a/quill/common/src/entities/zoglin.rs b/quill/common/src/entities/zoglin.rs new file mode 100644 index 000000000..8793439a2 --- /dev/null +++ b/quill/common/src/entities/zoglin.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for zoglin entities. +/// +/// # Example +/// A system that queries for all zoglins: +/// ```no_run +/// use quill::{Game, Position, entities::Zoglin}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Zoglin)>() { +/// println!("Found a zoglin with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Zoglin; + +pod_component_impl!(Zoglin); diff --git a/quill/common/src/entities/zombie.rs b/quill/common/src/entities/zombie.rs new file mode 100644 index 000000000..3532a6362 --- /dev/null +++ b/quill/common/src/entities/zombie.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for zombie entities. +/// +/// # Example +/// A system that queries for all zombies: +/// ```no_run +/// use quill::{Game, Position, entities::Zombie}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &Zombie)>() { +/// println!("Found a zombie with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct Zombie; + +pod_component_impl!(Zombie); diff --git a/quill/common/src/entities/zombie_horse.rs b/quill/common/src/entities/zombie_horse.rs new file mode 100644 index 000000000..dc08fb6f7 --- /dev/null +++ b/quill/common/src/entities/zombie_horse.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for zombie horse entities. +/// +/// # Example +/// A system that queries for all zombie horses: +/// ```no_run +/// use quill::{Game, Position, entities::ZombieHorse}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ZombieHorse)>() { +/// println!("Found a zombie horse with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ZombieHorse; + +pod_component_impl!(ZombieHorse); diff --git a/quill/common/src/entities/zombie_villager.rs b/quill/common/src/entities/zombie_villager.rs new file mode 100644 index 000000000..b86ab2d97 --- /dev/null +++ b/quill/common/src/entities/zombie_villager.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for zombie villager entities. +/// +/// # Example +/// A system that queries for all zombie villagers: +/// ```no_run +/// use quill::{Game, Position, entities::ZombieVillager}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ZombieVillager)>() { +/// println!("Found a zombie villager with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ZombieVillager; + +pod_component_impl!(ZombieVillager); diff --git a/quill/common/src/entities/zombified_piglin.rs b/quill/common/src/entities/zombified_piglin.rs new file mode 100644 index 000000000..057fbbc25 --- /dev/null +++ b/quill/common/src/entities/zombified_piglin.rs @@ -0,0 +1,19 @@ +use bytemuck::{Pod, Zeroable}; +/// Marker component for zombified piglin entities. +/// +/// # Example +/// A system that queries for all zombified piglins: +/// ```no_run +/// use quill::{Game, Position, entities::ZombifiedPiglin}; +/// # struct MyPlugin; +/// fn print_entities_system(_plugin: &mut MyPlugin, game: &mut Game) { +/// for (entity, (position, _)) in game.query::<(&Position, &ZombifiedPiglin)>() { +/// println!("Found a zombified piglin with position {:?}", position); +/// } +/// } +/// ``` +#[derive(Debug, Copy, Clone, Zeroable, Pod)] +#[repr(C)] +pub struct ZombifiedPiglin; + +pod_component_impl!(ZombifiedPiglin); diff --git a/quill/common/src/entity.rs b/quill/common/src/entity.rs new file mode 100644 index 000000000..03a0b4d51 --- /dev/null +++ b/quill/common/src/entity.rs @@ -0,0 +1,31 @@ +use bytemuck::{Pod, Zeroable}; +use serde::{Deserialize, Serialize}; + +use crate::PointerMut; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Zeroable, Pod, Serialize, Deserialize)] +#[repr(transparent)] +pub struct EntityId(pub u64); + +/// Returned by `query_begin`. Contains pointers +/// to the data yielded by the query. +#[derive(Copy, Clone, Debug, Zeroable, Pod)] +#[repr(C)] +pub struct QueryData { + /// The number of (entity, component_1, ..., component_n) pairs + /// yielded by this query. + pub num_entities: u64, + /// Pointer to an array of `num_entities` entities. + pub entities_ptr: PointerMut<EntityId>, + /// Pointer to an array of component pointers, one for + /// each component in the call to `query_begin`. Each component + /// pointer points to `num_entities` components of the corresponding type, + /// serialized using the component's `to_bytes` method. + /// + /// Note that each component pointer is 64 bits regardless of target. + pub component_ptrs: PointerMut<PointerMut<u8>>, + /// Pointer to an array of `u32`s, one for each component. + /// Each `u32` is the number of bytes in the corresponding + /// component buffer. + pub component_lens: PointerMut<u32>, +} diff --git a/quill/common/src/entity_init.rs b/quill/common/src/entity_init.rs new file mode 100644 index 000000000..741659615 --- /dev/null +++ b/quill/common/src/entity_init.rs @@ -0,0 +1,330 @@ +use serde::{Deserialize, Serialize}; + +/// Initial state of an entity passed +/// to `Game::create_entity_builder`. +#[derive(Debug, Serialize, Deserialize)] +pub enum EntityInit { + /// Spawn an area effect cloud. + AreaEffectCloud, + + /// Spawn an armor stand. + ArmorStand, + + /// Spawn an arrow. + Arrow, + + /// Spawn a bat. + Bat, + + /// Spawn a bee. + Bee, + + /// Spawn a blaze. + Blaze, + + /// Spawn a boat. + Boat, + + /// Spawn a cat. + Cat, + + /// Spawn a cave spider. + CaveSpider, + + /// Spawn a chicken. + Chicken, + + /// Spawn a cod. + Cod, + + /// Spawn a cow. + Cow, + + /// Spawn a creeper. + Creeper, + + /// Spawn a dolphin. + Dolphin, + + /// Spawn a donkey. + Donkey, + + /// Spawn a dragon fireball. + DragonFireball, + + /// Spawn a drowned. + Drowned, + + /// Spawn an elder guardian. + ElderGuardian, + + /// Spawn an end crystal. + EndCrystal, + + /// Spawn an ender dragon. + EnderDragon, + + /// Spawn an enderman. + Enderman, + + /// Spawn an endermite. + Endermite, + + /// Spawn an evoker. + Evoker, + + /// Spawn an evoker fangs. + EvokerFangs, + + /// Spawn an experience orb. + ExperienceOrb, + + /// Spawn an eye of ender. + EyeOfEnder, + + /// Spawn a falling block. + FallingBlock, + + /// Spawn a firework rocket. + FireworkRocket, + + /// Spawn a fox. + Fox, + + /// Spawn a ghast. + Ghast, + + /// Spawn a giant. + Giant, + + /// Spawn a guardian. + Guardian, + + /// Spawn a hoglin. + Hoglin, + + /// Spawn a horse. + Horse, + + /// Spawn a husk. + Husk, + + /// Spawn an illusioner. + Illusioner, + + /// Spawn an iron golem. + IronGolem, + + /// Spawn an item. + Item, + + /// Spawn an item frame. + ItemFrame, + + /// Spawn a fireball. + Fireball, + + /// Spawn a leash knot. + LeashKnot, + + /// Spawn a lightning bolt. + LightningBolt, + + /// Spawn a llama. + Llama, + + /// Spawn a llama spit. + LlamaSpit, + + /// Spawn a magma cube. + MagmaCube, + + /// Spawn a minecart. + Minecart, + + /// Spawn a chest minecart. + ChestMinecart, + + /// Spawn a command block minecart. + CommandBlockMinecart, + + /// Spawn a furnace minecart. + FurnaceMinecart, + + /// Spawn a hopper minecart. + HopperMinecart, + + /// Spawn a spawner minecart. + SpawnerMinecart, + + /// Spawn a tnt minecart. + TntMinecart, + + /// Spawn a mule. + Mule, + + /// Spawn a mooshroom. + Mooshroom, + + /// Spawn an ocelot. + Ocelot, + + /// Spawn a painting. + Painting, + + /// Spawn a panda. + Panda, + + /// Spawn a parrot. + Parrot, + + /// Spawn a phantom. + Phantom, + + /// Spawn a pig. + Pig, + + /// Spawn a piglin. + Piglin, + + /// Spawn a piglin brute. + PiglinBrute, + + /// Spawn a pillager. + Pillager, + + /// Spawn a polar bear. + PolarBear, + + /// Spawn a tnt. + Tnt, + + /// Spawn a pufferfish. + Pufferfish, + + /// Spawn a rabbit. + Rabbit, + + /// Spawn a ravager. + Ravager, + + /// Spawn a salmon. + Salmon, + + /// Spawn a sheep. + Sheep, + + /// Spawn a shulker. + Shulker, + + /// Spawn a shulker bullet. + ShulkerBullet, + + /// Spawn a silverfish. + Silverfish, + + /// Spawn a skeleton. + Skeleton, + + /// Spawn a skeleton horse. + SkeletonHorse, + + /// Spawn a slime. + Slime, + + /// Spawn a small fireball. + SmallFireball, + + /// Spawn a snow golem. + SnowGolem, + + /// Spawn a snowball. + Snowball, + + /// Spawn a spectral arrow. + SpectralArrow, + + /// Spawn a spider. + Spider, + + /// Spawn a squid. + Squid, + + /// Spawn a stray. + Stray, + + /// Spawn a strider. + Strider, + + /// Spawn an egg. + Egg, + + /// Spawn an ender pearl. + EnderPearl, + + /// Spawn an experience bottle. + ExperienceBottle, + + /// Spawn a potion. + Potion, + + /// Spawn a trident. + Trident, + + /// Spawn a trader llama. + TraderLlama, + + /// Spawn a tropical fish. + TropicalFish, + + /// Spawn a turtle. + Turtle, + + /// Spawn a vex. + Vex, + + /// Spawn a villager. + Villager, + + /// Spawn a vindicator. + Vindicator, + + /// Spawn a wandering trader. + WanderingTrader, + + /// Spawn a witch. + Witch, + + /// Spawn a wither. + Wither, + + /// Spawn a wither skeleton. + WitherSkeleton, + + /// Spawn a wither skull. + WitherSkull, + + /// Spawn a wolf. + Wolf, + + /// Spawn a zoglin. + Zoglin, + + /// Spawn a zombie. + Zombie, + + /// Spawn a zombie horse. + ZombieHorse, + + /// Spawn a zombie villager. + ZombieVillager, + + /// Spawn a zombified piglin. + ZombifiedPiglin, + + /// Spawn a player. + Player, + + /// Spawn a fishing bobber. + FishingBobber, +} diff --git a/quill/common/src/events.rs b/quill/common/src/events.rs new file mode 100644 index 000000000..e253da176 --- /dev/null +++ b/quill/common/src/events.rs @@ -0,0 +1,12 @@ +pub use block_interact::{BlockInteractEvent, BlockPlacementEvent}; +pub use change::{ + BuildingAbilityEvent, CreativeFlyingEvent, FlyingAbilityEvent, GamemodeEvent, InstabreakEvent, + InvulnerabilityEvent, SneakEvent, SprintEvent, +}; +pub use entity::{EntityCreateEvent, EntityRemoveEvent, PlayerJoinEvent}; +pub use interact_entity::InteractEntityEvent; + +mod block_interact; +mod change; +mod entity; +mod interact_entity; diff --git a/quill/common/src/events/block_interact.rs b/quill/common/src/events/block_interact.rs new file mode 100644 index 000000000..c464025b4 --- /dev/null +++ b/quill/common/src/events/block_interact.rs @@ -0,0 +1,22 @@ +use libcraft_core::{BlockFace, BlockPosition, Hand, Vec3f}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct BlockInteractEvent { + pub hand: Hand, + pub location: BlockPosition, + pub face: BlockFace, + pub cursor_position: Vec3f, + /// If the client thinks its inside a block when the interaction is fired. + pub inside_block: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct BlockPlacementEvent { + pub hand: Hand, + pub location: BlockPosition, + pub face: BlockFace, + pub cursor_position: Vec3f, + /// If the client thinks its inside a block when the interaction is fired. + pub inside_block: bool, +} diff --git a/quill/common/src/events/change.rs b/quill/common/src/events/change.rs new file mode 100644 index 000000000..266846160 --- /dev/null +++ b/quill/common/src/events/change.rs @@ -0,0 +1,66 @@ +/* +All events in this file are triggered when there is a change in a certain value. +*/ + +use derive_more::Deref; +use libcraft_core::Gamemode; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CreativeFlyingEvent { + pub is_flying: bool, +} + +impl CreativeFlyingEvent { + pub fn new(changed_to: bool) -> Self { + Self { + is_flying: changed_to, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SneakEvent { + pub is_sneaking: bool, +} + +impl SneakEvent { + pub fn new(changed_to: bool) -> Self { + Self { + is_sneaking: changed_to, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SprintEvent { + pub is_sprinting: bool, +} + +impl SprintEvent { + pub fn new(changed_to: bool) -> Self { + Self { + is_sprinting: changed_to, + } + } +} + +/// This event is called when a player's gamemode is changed and every time the player joins. +#[derive(Debug, Serialize, Deserialize, Clone, Deref)] +pub struct GamemodeEvent(pub Gamemode); + +/// This event is called when player's ability to instantly break blocks changes. +#[derive(Debug, Serialize, Deserialize, Clone, Deref)] +pub struct InstabreakEvent(pub bool); + +/// This event is called when player's ability to fly changes. +#[derive(Debug, Serialize, Deserialize, Clone, Deref)] +pub struct FlyingAbilityEvent(pub bool); + +/// This event is called when player's ability to place or break blocks changes. +#[derive(Debug, Serialize, Deserialize, Clone, Deref)] +pub struct BuildingAbilityEvent(pub bool); + +/// This event is called when player's invulnerability property changes. +#[derive(Debug, Serialize, Deserialize, Clone, Deref)] +pub struct InvulnerabilityEvent(pub bool); diff --git a/quill/common/src/events/entity.rs b/quill/common/src/events/entity.rs new file mode 100644 index 000000000..073feb61a --- /dev/null +++ b/quill/common/src/events/entity.rs @@ -0,0 +1,16 @@ +use serde::{Deserialize, Serialize}; + +/// Triggered when a player joins the `Game`. +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct PlayerJoinEvent; + +/// Triggered when an entity is removed from the world. +/// +/// The entity will remain alive for one tick after it is +/// destroyed to allow systems to observe this event. +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EntityRemoveEvent; + +/// Triggered when an entity is added into the world. +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EntityCreateEvent; diff --git a/quill/common/src/events/interact_entity.rs b/quill/common/src/events/interact_entity.rs new file mode 100644 index 000000000..b77c80be0 --- /dev/null +++ b/quill/common/src/events/interact_entity.rs @@ -0,0 +1,12 @@ +use crate::EntityId; +use libcraft_core::{Hand, InteractionType, Vec3f}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct InteractEntityEvent { + pub target: EntityId, + pub ty: InteractionType, + pub target_pos: Option<Vec3f>, + pub hand: Option<Hand>, + pub sneaking: bool, +} diff --git a/quill/common/src/lib.rs b/quill/common/src/lib.rs new file mode 100644 index 000000000..53d8a262b --- /dev/null +++ b/quill/common/src/lib.rs @@ -0,0 +1,105 @@ +#[macro_use] +mod utils; +#[macro_use] +pub mod component; +pub mod block; +pub mod components; +pub mod entities; +pub mod entity; +pub mod entity_init; +pub mod events; + +use std::marker::PhantomData; + +use bytemuck::{Pod, Zeroable}; + +pub use component::{Component, HostComponent}; +pub use entity::EntityId; + +/// Wrapper type that enforces 64-bit pointers +/// for all targets. Needed for ABI compatibility +/// between WASM-compiled and native-compiled plugins. +#[derive(Debug, PartialEq, Eq, Zeroable)] +#[repr(transparent)] +pub struct Pointer<T> { + ptr: u64, + _marker: PhantomData<*const T>, +} + +impl<T> Clone for Pointer<T> { + fn clone(&self) -> Self { + Self { + ptr: self.ptr, + _marker: self._marker, + } + } +} + +impl<T> Copy for Pointer<T> {} + +impl<T> Pointer<T> { + pub fn new(ptr: *const T) -> Self { + Self { + ptr: ptr as usize as u64, + _marker: PhantomData, + } + } + + pub fn as_ptr(self) -> *const T { + self.ptr as usize as *const T + } +} + +impl<T> From<*const T> for Pointer<T> { + fn from(ptr: *const T) -> Self { + Self::new(ptr) + } +} + +// SAFETY: Pointer<T> contains a u64 regardless +// of T. bytemuck won't derive Pod for generic +// types because it cannot guarantee this. +unsafe impl<T: 'static> Pod for Pointer<T> {} + +/// Wrapper type that enforces 64-bit pointers +/// for all targets. Needed for ABI compatibility +/// between WASM-compiled and native-compiled plugins. +#[derive(Debug, PartialEq, Eq, Zeroable)] +#[repr(transparent)] +pub struct PointerMut<T> { + ptr: u64, + _marker: PhantomData<*mut T>, +} + +impl<T> Clone for PointerMut<T> { + fn clone(&self) -> Self { + Self { + ptr: self.ptr, + _marker: self._marker, + } + } +} + +impl<T> Copy for PointerMut<T> {} + +impl<T> PointerMut<T> { + pub fn new(ptr: *mut T) -> Self { + Self { + ptr: ptr as usize as u64, + _marker: PhantomData, + } + } + + pub fn as_mut_ptr(self) -> *mut T { + self.ptr as usize as *mut T + } +} + +impl<T> From<*mut T> for PointerMut<T> { + fn from(ptr: *mut T) -> Self { + Self::new(ptr) + } +} + +// SAFETY: see impl Pod for Pointer. +unsafe impl<T: 'static> Pod for PointerMut<T> {} diff --git a/quill/common/src/utils.rs b/quill/common/src/utils.rs new file mode 100644 index 000000000..54af94934 --- /dev/null +++ b/quill/common/src/utils.rs @@ -0,0 +1,28 @@ +macro_rules! c_enum { + ( + $(#[$outer:meta])* + pub enum $ident:ident { + $($variant:ident = $x:literal),* $(,)? + } + ) => { + $(#[$outer])* + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, ::serde::Serialize, ::serde::Deserialize)] + #[repr(u32)] + pub enum $ident { + $( + $variant = $x, + )* + } + + impl $ident { + pub fn from_u32(x: u32) -> Option<Self> { + match x { + $( + $x => Some(Self::$variant), + )* + _ => None, + } + } + } + } +} diff --git a/quill/docs/components.md b/quill/docs/components.md new file mode 100644 index 000000000..99c6fa6fd --- /dev/null +++ b/quill/docs/components.md @@ -0,0 +1,9 @@ +# Components and Queries in Quill + +There are two types of components accessed by a plugin: +* "Plain-old-data" components, typically implementing `Copy`. To transfer these to a plugin, +the raw struct bytes are copied into the plugin's memory, and the plugin gets a pointer to that data. +* Opaque components, i.e., those not implementing `Copy`. These typically hold more data. Examples: `Inventory` of , `Window`. +A plugin accesses these components via host calls without ever getting a copy of the component itself. For example, +to get an item from an inventory, a plugin calls `quill_entity_get_inventory_item`. (The high-level `quill` API wraps +this raw call with an `Inventory` struct, but the struct doesn't actually hold the inventory. It's just a marker.) diff --git a/util/rand-legacy/Cargo.toml b/quill/example-plugins/block-access/Cargo.toml similarity index 51% rename from util/rand-legacy/Cargo.toml rename to quill/example-plugins/block-access/Cargo.toml index 50146e4aa..f67453638 100644 --- a/util/rand-legacy/Cargo.toml +++ b/quill/example-plugins/block-access/Cargo.toml @@ -1,9 +1,11 @@ [package] -name = "rand-legacy" +name = "block-access" version = "0.1.0" authors = ["caelunshun <caelunshun@gmail.com>"] edition = "2018" -description = "Exports 0.6.5 rand API for use with old libraries" + +[lib] +crate-type = ["cdylib"] [dependencies] -rand = "0.6.5" \ No newline at end of file +quill = { path = "../../api" } diff --git a/quill/example-plugins/block-access/src/lib.rs b/quill/example-plugins/block-access/src/lib.rs new file mode 100644 index 000000000..9813d2b36 --- /dev/null +++ b/quill/example-plugins/block-access/src/lib.rs @@ -0,0 +1,26 @@ +//! A plugin to demonstrate getting and setting blocks in the world. + +use quill::{entities::Player, BlockState, Game, Plugin, Position}; + +#[quill::plugin] +pub struct BlockAccess; + +impl Plugin for BlockAccess { + fn enable(_game: &mut quill::Game, setup: &mut quill::Setup<Self>) -> Self { + setup.add_system(system); + Self + } + + fn disable(self, _game: &mut quill::Game) {} +} + +fn system(_plugin: &mut BlockAccess, game: &mut Game) { + // Set the blocks each player is standing on + // to bedrock. + for (_entity, (_, pos)) in game.query::<(&Player, &Position)>() { + let block_pos = pos.block(); + + game.set_block(block_pos, BlockState::from_id(33).unwrap()) + .ok(); + } +} diff --git a/quill/example-plugins/block-place/Cargo.toml b/quill/example-plugins/block-place/Cargo.toml new file mode 100644 index 000000000..26b61fa9d --- /dev/null +++ b/quill/example-plugins/block-place/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "block-place" +version = "0.1.0" +authors = ["Amber Kowalski <amberkowalski03@gmail.com>"] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +quill = { path = "../../api" } diff --git a/quill/example-plugins/block-place/src/lib.rs b/quill/example-plugins/block-place/src/lib.rs new file mode 100644 index 000000000..19913eb7f --- /dev/null +++ b/quill/example-plugins/block-place/src/lib.rs @@ -0,0 +1,21 @@ +//! Allows the user to place blocks. + +use quill::{events::BlockPlacementEvent, Game, Plugin}; + +#[quill::plugin] +pub struct BlockPlace; + +impl Plugin for BlockPlace { + fn enable(_game: &mut quill::Game, setup: &mut quill::Setup<Self>) -> Self { + setup.add_system(system); + Self + } + + fn disable(self, _game: &mut quill::Game) {} +} + +fn system(_plugin: &mut BlockPlace, game: &mut Game) { + for (_entity, _event) in game.query::<&BlockPlacementEvent>() { + println!("A client has placed a block!"); + } +} diff --git a/quill/example-plugins/observe-creativemode-flight-event/Cargo.toml b/quill/example-plugins/observe-creativemode-flight-event/Cargo.toml new file mode 100644 index 000000000..77fdfd2eb --- /dev/null +++ b/quill/example-plugins/observe-creativemode-flight-event/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "observe-creativemode-flight-event" +version = "0.1.0" +authors = ["Miro Andrin <miro.sveits@gmail.com>"] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +quill = { path = "../../api" } diff --git a/quill/example-plugins/observe-creativemode-flight-event/src/lib.rs b/quill/example-plugins/observe-creativemode-flight-event/src/lib.rs new file mode 100644 index 000000000..9d84f159d --- /dev/null +++ b/quill/example-plugins/observe-creativemode-flight-event/src/lib.rs @@ -0,0 +1,52 @@ +/* +This plugin observers the CreativeFlightEvent printing a msg when someone starts +flying. +*/ + +use quill::{ + components::Sprinting, + events::{CreativeFlyingEvent, SneakEvent}, + Game, Plugin, Setup, +}; + +#[quill::plugin] +struct FlightPlugin {} + +impl Plugin for FlightPlugin { + fn enable(_game: &mut Game, setup: &mut Setup<Self>) -> Self { + setup.add_system(flight_observer_system); + setup.add_system(sneak_observer_system); + setup.add_system(sprinting_observer_system); + FlightPlugin {} + } + + fn disable(self, _game: &mut Game) {} +} + +fn flight_observer_system(_plugin: &mut FlightPlugin, game: &mut Game) { + for (entity, change) in game.query::<&CreativeFlyingEvent>() { + if change.is_flying { + entity.send_message("Enjoy your flight!"); + } else { + entity.send_message("Hope you enjoyed your flight."); + } + } +} + +fn sneak_observer_system(_plugin: &mut FlightPlugin, game: &mut Game) { + for (player, change) in game.query::<&SneakEvent>() { + if change.is_sneaking { + player.send_message("Enjoy sneaking!"); + } else { + player.send_message("How was it to be sneaking?"); + } + } +} + +fn sprinting_observer_system(_plugin: &mut FlightPlugin, game: &mut Game) { + for (player, sprinting) in game.query::<&Sprinting>() { + if sprinting.0 { + player.send_message("Are you sprinting?"); + } + } +} diff --git a/quill/example-plugins/particle-example/Cargo.toml b/quill/example-plugins/particle-example/Cargo.toml new file mode 100644 index 000000000..8cf008b7c --- /dev/null +++ b/quill/example-plugins/particle-example/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "particle-example" +version = "0.1.0" +authors = ["Gijs de Jong <berichtaangijs@gmail.com>"] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +quill = { path = "../../api" } diff --git a/quill/example-plugins/particle-example/src/lib.rs b/quill/example-plugins/particle-example/src/lib.rs new file mode 100644 index 000000000..bd84bb58d --- /dev/null +++ b/quill/example-plugins/particle-example/src/lib.rs @@ -0,0 +1,59 @@ +use quill::{Game, Particle, ParticleKind, Plugin, Position}; + +#[quill::plugin] +struct ParticleExample {} + +impl Plugin for ParticleExample { + fn enable(_game: &mut quill::Game, setup: &mut quill::Setup<Self>) -> Self { + setup.add_system(particle_system); + + ParticleExample {} + } + + fn disable(self, _game: &mut quill::Game) {} +} + +fn particle_system(_plugin: &mut ParticleExample, game: &mut Game) { + let mut position = Position { + x: 0.0, + y: 65.0, + z: 0.0, + pitch: 0.0, + yaw: 0.0, + }; + + let particle = Particle { + kind: ParticleKind::SoulFireFlame, + offset_x: 0.0, + offset_y: 0.0, + offset_z: 0.0, + count: 1, + }; + + game.spawn_particle(position, particle); + + position.x += 1.0; + + let particle2 = Particle { + kind: ParticleKind::Dust { + red: 1.0, + green: 1.0, + blue: 0.0, + scale: 3.5, + }, + offset_x: 0.0, + offset_y: 0.0, + offset_z: 0.0, + count: 1, + }; + + // Initialise an empty ecs-entity builder + let mut builder = game.create_empty_entity_builder(); + + // Add the required components to display a particle effect + builder.add(position); + builder.add(particle2); + + // Finish the builder, this will spawn the ecs-entity in the ecs-world + builder.finish(); +} diff --git a/quill/example-plugins/plugin-message/Cargo.toml b/quill/example-plugins/plugin-message/Cargo.toml new file mode 100644 index 000000000..4624566a1 --- /dev/null +++ b/quill/example-plugins/plugin-message/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "plugin-message" +version = "0.1.0" +authors = ["Derek Lee <derek.scott.lee13@gmail.com>"] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +quill = { path = "../../api" } diff --git a/quill/example-plugins/plugin-message/src/lib.rs b/quill/example-plugins/plugin-message/src/lib.rs new file mode 100644 index 000000000..9b66f8c7a --- /dev/null +++ b/quill/example-plugins/plugin-message/src/lib.rs @@ -0,0 +1,33 @@ +//! An example plugin that uses BungeeCord's plugin messaging channel to +//! send a player to a server named lobby. +use quill::{entities::Player, BlockPosition, Game, Plugin, Position}; + +#[quill::plugin] +pub struct PluginMessage; + +impl Plugin for PluginMessage { + fn enable(_game: &mut quill::Game, setup: &mut quill::Setup<Self>) -> Self { + setup.add_system(plugin_message_system); + Self + } + + fn disable(self, _game: &mut quill::Game) {} +} + +fn plugin_message_system(_plugin: &mut PluginMessage, game: &mut Game) { + for (entity, (_, position)) in game.query::<(&Player, &Position)>() { + if let BlockPosition { + x: 10..=12, + y: _, + z: 10..=12, + } = position.block() + { + let mut data = Vec::new(); + data.extend_from_slice(&u16::to_be_bytes(7)); + data.extend_from_slice(b"Connect"); + data.extend_from_slice(&u16::to_be_bytes(5)); + data.extend_from_slice(b"lobby"); + Game::send_plugin_message(entity.id(), "bungeecord:main", &data); + } + } +} diff --git a/quill/example-plugins/query-entities/Cargo.toml b/quill/example-plugins/query-entities/Cargo.toml new file mode 100644 index 000000000..6c9815807 --- /dev/null +++ b/quill/example-plugins/query-entities/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "query-entities" +version = "0.1.0" +authors = ["Caelum van Ispelen <caelum12321@gmail.com>"] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +quill = { path = "../../api" } +rand = "0.8" diff --git a/quill/example-plugins/query-entities/src/lib.rs b/quill/example-plugins/query-entities/src/lib.rs new file mode 100644 index 000000000..527fd7546 --- /dev/null +++ b/quill/example-plugins/query-entities/src/lib.rs @@ -0,0 +1,43 @@ +//! An example plugin that spawns 10,000 entities +//! on startup, then moves them each tick using a query. + +use quill::{entities::PiglinBrute, EntityInit, Game, Plugin, Position}; +use rand::Rng; + +#[quill::plugin] +struct QueryEntities { + tick_counter: u64, +} + +impl Plugin for QueryEntities { + fn enable(game: &mut quill::Game, setup: &mut quill::Setup<Self>) -> Self { + // Spawn 10,000 piglin brutes + for x in 0..100 { + for z in 0..100 { + let pos = Position { + x: (x - 50) as f64 * 12.0, + y: 64.0, + z: (z - 50) as f64 * 12.0, + pitch: rand::thread_rng().gen_range(30.0..330.0), + yaw: rand::thread_rng().gen_range(0.0..360.0), + }; + game.create_entity_builder(pos, EntityInit::PiglinBrute) + .finish(); + } + } + + setup.add_system(query_system); + + Self { tick_counter: 0 } + } + + fn disable(self, _game: &mut quill::Game) {} +} + +fn query_system(plugin: &mut QueryEntities, game: &mut Game) { + // Make the piglin brutes float into the air. + plugin.tick_counter += 1; + for (_, (mut position, _piglin_brute)) in game.query::<(&mut Position, &PiglinBrute)>() { + position.y += 0.1 * ((plugin.tick_counter as f64 / 20.0).sin() + 1.0); + } +} diff --git a/quill/example-plugins/simple/Cargo.toml b/quill/example-plugins/simple/Cargo.toml new file mode 100644 index 000000000..145d598bc --- /dev/null +++ b/quill/example-plugins/simple/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "simple-plugin" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +quill = { path = "../../api" } +rand = "0.8" diff --git a/quill/example-plugins/simple/src/lib.rs b/quill/example-plugins/simple/src/lib.rs new file mode 100644 index 000000000..d6ac19dae --- /dev/null +++ b/quill/example-plugins/simple/src/lib.rs @@ -0,0 +1,60 @@ +use quill::{ + components::{CustomName, Name}, + entities::Cow, + EntityInit, Game, Gamemode, Plugin, Position, Setup, Uuid, +}; +use rand::Rng; + +#[quill::plugin] +struct SimplePlugin { + tick_counter: u64, +} + +impl Plugin for SimplePlugin { + fn enable(_game: &mut Game, setup: &mut Setup<Self>) -> Self { + setup.add_system(test_system); + SimplePlugin { tick_counter: 0 } + } + + fn disable(self, _game: &mut Game) {} +} + +fn test_system(plugin: &mut SimplePlugin, game: &mut Game) { + for (entity, (position, name, gamemode, uuid)) in + game.query::<(&Position, &Name, &Gamemode, &Uuid)>() + { + entity.send_message(format!( + "[{}] Hi {}. Your gamemode is {:?} and your position is {:.1?} and your UUID is {}", + plugin.tick_counter, + name, + gamemode, + position, + uuid.to_hyphenated() + )); + + if plugin.tick_counter % 100 == 0 { + entity.send_message("Spawning a mob on you"); + game.create_entity_builder(position, random_mob()) + .with(CustomName::new("Custom name")) + .finish(); + } + } + for (_, (mut position, _)) in game.query::<(&mut Position, &Cow)>() { + position.y += 0.1; + } + + plugin.tick_counter += 1; +} + +fn random_mob() -> EntityInit { + let mut entities = vec![ + EntityInit::Zombie, + EntityInit::Piglin, + EntityInit::Zoglin, + EntityInit::Skeleton, + EntityInit::Enderman, + EntityInit::Cow, + ]; + let index = rand::thread_rng().gen_range(0..entities.len()); + entities.remove(index) +} diff --git a/quill/example-plugins/titles/Cargo.toml b/quill/example-plugins/titles/Cargo.toml new file mode 100644 index 000000000..1041d93e1 --- /dev/null +++ b/quill/example-plugins/titles/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "titles" +version = "0.1.0" +authors = ["Gijs de Jong <berichtaangijs@gmail.com>"] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +quill = { path = "../../api" } diff --git a/quill/example-plugins/titles/src/lib.rs b/quill/example-plugins/titles/src/lib.rs new file mode 100644 index 000000000..634f5b003 --- /dev/null +++ b/quill/example-plugins/titles/src/lib.rs @@ -0,0 +1,53 @@ +use quill::{entities::Player, Game, Plugin, Text, TextComponent, TextComponentBuilder, Title}; + +#[quill::plugin] +struct TitleExample { + tick_count: u32, + title_active: bool, +} + +impl Plugin for TitleExample { + fn enable(_game: &mut quill::Game, setup: &mut quill::Setup<Self>) -> Self { + setup.add_system(title_system); + + TitleExample { + tick_count: 0, + title_active: false, + } + } + + fn disable(self, _game: &mut quill::Game) {} +} + +fn title_system(plugin: &mut TitleExample, game: &mut Game) { + // Run once every 100 ticks (5 seconds) + if plugin.tick_count % 100 == 0 && !plugin.title_active { + let component = TextComponentBuilder::gray(TextComponent::from("Wicked fast Minecraft!")); + let title_component = TextComponentBuilder::white(TextComponent::from("Hello Feather!")); + + // Create a title to send to the player + let title = Title { + title: Some(Text::from(title_component)), + sub_title: Some(Text::from(component)), + fade_in: 5, + stay: 400, + fade_out: 5, + }; + + // Send the title to all online players + for (entity, _) in game.query::<&Player>() { + entity.send_title(&title); + plugin.title_active = true; + } + } + + if plugin.tick_count % 250 == 0 && plugin.title_active { + // Reset the title for all players + for (entity, _) in game.query::<&Player>() { + entity.reset_title(); + plugin.title_active = false; + } + } + + plugin.tick_count += 1; +} diff --git a/quill/plugin-format/Cargo.toml b/quill/plugin-format/Cargo.toml new file mode 100644 index 000000000..7043f9c8f --- /dev/null +++ b/quill/plugin-format/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "quill-plugin-format" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +anyhow = "1" +tar = "0.4" +flate2 = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +serde_with = "1" +target-lexicon = "0.11" diff --git a/quill/plugin-format/src/lib.rs b/quill/plugin-format/src/lib.rs new file mode 100644 index 000000000..20a55c417 --- /dev/null +++ b/quill/plugin-format/src/lib.rs @@ -0,0 +1,206 @@ +//! Defines the file format used for compiled [`quill`](https://github.com/feather-rs/quill) +//! plugins. +//! +//! Currently, the file format is based on gzipped `tar` files. +mod metadata; + +use std::{ + borrow::Cow, + io::{Cursor, Read, Write}, +}; + +use anyhow::{anyhow, bail}; +use flate2::Compression; +use tar::Header; + +pub use metadata::{PluginMetadata, PluginTarget}; + +use target_lexicon::OperatingSystem; +pub use target_lexicon::Triple; + +const METADATA_PATH: &str = "metadata.json"; + +/// A plugin definition stored in the Quill file format. +pub struct PluginFile<'a> { + module: Cow<'a, [u8]>, + metadata: PluginMetadata, +} + +impl<'a> PluginFile<'a> { + pub fn new(module: impl Into<Cow<'a, [u8]>>, metadata: PluginMetadata) -> Self { + Self { + module: module.into(), + metadata, + } + } + + /// Returns the plugin's module. + /// + /// If the plugin is a WebAssembly plugin, + /// then this is the WASM bytecode. + /// + /// If the plugin is a native plugin, then + /// this is the contents of the shared library + /// containing the plugin. + pub fn module(&self) -> &[u8] { + &*self.module + } + + pub fn metadata(&self) -> &PluginMetadata { + &self.metadata + } + + /// Writes this plugin into a `Vec`. + /// + /// `compression_level` should be between 0 (worst) and 9 (best, but slow). + pub fn encode(&self, compression_level: u32) -> Vec<u8> { + let vec = Vec::new(); + let mut archive_builder = tar::Builder::new(flate2::write::GzEncoder::new( + vec, + Compression::new(compression_level), + )); + + self.write_metadata(&mut archive_builder); + self.write_module(&mut archive_builder).unwrap(); + + archive_builder + .into_inner() + .expect("write to Vec failed") + .finish() + .expect("compression failed") + } + + fn write_metadata(&self, archive_builder: &mut tar::Builder<impl Write>) { + let metadata = serde_json::to_string_pretty(&self.metadata) + .expect("failed to serialize PluginMetadata"); + + let mut header = Header::new_gnu(); + header.set_size(metadata.len() as u64); + header.set_mode(0o644); + + archive_builder + .append_data( + &mut header, + METADATA_PATH, + Cursor::new(metadata.into_bytes()), + ) + .expect("write to Vec failed"); + } + + fn write_module(&self, archive_builder: &mut tar::Builder<impl Write>) -> anyhow::Result<()> { + let mut header = Header::new_gnu(); + header.set_size(self.module.len() as u64); + header.set_mode(0o644); + + let path = get_module_path(&self.metadata.target)?; + + archive_builder + .append_data(&mut header, path, Cursor::new(self.module())) + .expect("write to Vec failed"); + + Ok(()) + } +} + +impl PluginFile<'static> { + /// Deserializes a plugin file. + pub fn decode(data: impl Read) -> anyhow::Result<Self> { + let mut archive = tar::Archive::new(flate2::read::GzDecoder::new(data)); + + // Current limitation: the metadata must appear + // in the tarball before the WASM module. + + let mut metadata = None; + let mut module = None; + let mut module_path = None; + for entry in archive.entries()? { + let entry = entry?; + + match &*entry.path()?.to_string_lossy() { + s if s == METADATA_PATH => { + let meta = Self::decode_metadata(entry)?; + module_path = Some(get_module_path(&meta.target)?); + metadata = Some(meta); + } + s if Some(s) == module_path => module = Some(Self::decode_wasm_bytecode(entry)?), + _ => (), + } + } + + let metadata = + metadata.ok_or_else(|| anyhow!("missing plugin metadata ({})", METADATA_PATH))?; + let module = module + .ok_or_else(|| anyhow!("missing module ({:?})", module_path))? + .into(); + Ok(Self { module, metadata }) + } + + fn decode_metadata(reader: impl Read) -> anyhow::Result<PluginMetadata> { + serde_json::from_reader(reader).map_err(anyhow::Error::from) + } + + fn decode_wasm_bytecode(mut reader: impl Read) -> anyhow::Result<Vec<u8>> { + let mut wasm = Vec::new(); + reader.read_to_end(&mut wasm)?; + Ok(wasm) + } +} + +fn get_module_path(target: &PluginTarget) -> anyhow::Result<&'static str> { + Ok(match target { + PluginTarget::Wasm => "module.wasm", + PluginTarget::Native { target_triple } => match target_triple.operating_system { + OperatingSystem::Linux => "module.so", + OperatingSystem::Darwin => "module.dylib", + OperatingSystem::Windows => "module.dll", + os => bail!("unsupported plugin operating system {:?}", os), + }, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn roundtrip_wasm() { + let module = vec![0xFF; 1024]; + let metadata = PluginMetadata { + name: "TestPlugin".to_owned(), + identifier: "test-plugin".to_owned(), + version: "0.1.0".to_owned(), + api_version: "0.1.0".to_owned(), + description: Some("test plugin".to_owned()), + authors: vec!["caelunshun".to_owned()], + target: PluginTarget::Wasm, + }; + let file = PluginFile::new(module.clone(), metadata.clone()); + let encoded = file.encode(8); + let decoded = PluginFile::decode(Cursor::new(encoded)).unwrap(); + + assert_eq!(decoded.metadata(), &metadata); + assert_eq!(decoded.module(), module); + } + + #[test] + fn roundtrip_native() { + let module = vec![0xEE; 1024]; + let metadata = PluginMetadata { + name: "TestPlugin".to_owned(), + identifier: "test-plugin".to_owned(), + version: "0.1.0".to_owned(), + api_version: "0.1.0".to_owned(), + description: Some("test plugin".to_owned()), + authors: vec!["caelunshun".to_owned()], + target: PluginTarget::Native { + target_triple: Triple::host(), + }, + }; + let file = PluginFile::new(module.clone(), metadata.clone()); + let encoded = file.encode(8); + let decoded = PluginFile::decode(Cursor::new(encoded)).unwrap(); + + assert_eq!(decoded.metadata(), &metadata); + assert_eq!(decoded.module(), module); + } +} diff --git a/quill/plugin-format/src/metadata.rs b/quill/plugin-format/src/metadata.rs new file mode 100644 index 000000000..66cd70eb5 --- /dev/null +++ b/quill/plugin-format/src/metadata.rs @@ -0,0 +1,36 @@ +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; +use target_lexicon::Triple; + +/// A plugin's metadata, stored alongside its WASM module. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct PluginMetadata { + /// Plugin name, no spaces + pub name: String, + /// Plugin identifier (crate name), snake_case or kebab-case + pub identifier: String, + /// Plugin version + pub version: String, + /// `quill` version used to compile the plugin + pub api_version: String, + + #[serde(default)] + pub description: Option<String>, + #[serde(default)] + pub authors: Vec<String>, + + pub target: PluginTarget, +} + +/// Type of a plugin +#[serde_as] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum PluginTarget { + Wasm, + Native { + /// The target the plugin has been compiled to. + #[serde_as(as = "DisplayFromStr")] + target_triple: Triple, + }, +} diff --git a/quill/sys-macros/Cargo.toml b/quill/sys-macros/Cargo.toml new file mode 100644 index 000000000..525d419ce --- /dev/null +++ b/quill/sys-macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "quill-sys-macros" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1" +syn = { version = "1", features = ["full"] } +quote = "1" diff --git a/quill/sys-macros/src/lib.rs b/quill/sys-macros/src/lib.rs new file mode 100644 index 000000000..687de7a07 --- /dev/null +++ b/quill/sys-macros/src/lib.rs @@ -0,0 +1,142 @@ +use quote::quote; +use syn::ForeignItem; + +/// Macro to redefine host functions depending +/// on whether we are compiling to the WebAssembly +/// or the native target. +/// +/// See the `quill-sys` crate-level documentation for more info. +#[proc_macro_attribute] +pub fn host_functions( + _args: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let input: syn::ItemForeignMod = syn::parse_macro_input!(input as syn::ItemForeignMod); + + let mut functions = Vec::new(); + for item in &input.items { + let item = match item { + ForeignItem::Fn(f) => f, + _ => panic!("only functions may be defined within the host calls module"), + }; + functions.push(item.clone()); + } + + let mut vtable_entries = Vec::new(); + for function in &functions { + let ident = &function.sig.ident; + let args: Vec<_> = function + .sig + .inputs + .iter() + .map(|arg| match arg { + syn::FnArg::Receiver(_) => panic!("self argument"), + syn::FnArg::Typed(arg) => arg.ty.clone(), + }) + .collect(); + let ret = &function.sig.output; + let ret = match ret { + syn::ReturnType::Default => None, + syn::ReturnType::Type(_, ty) => Some(quote! { -> #ty }), + }; + vtable_entries.push(quote! { + #ident: unsafe extern "C" fn(*const (), #(#args),*) #ret + }); + } + + let vtable = quote! { + struct HostVTable { + #(#vtable_entries,)* + } + }; + + let mut vtable_init_bindings = Vec::new(); + let mut vtable_init = Vec::new(); + for function in &functions { + let ident = &function.sig.ident; + let ident_string = ident.to_string(); + let missing_error = format!("missing vtable entry {}", ident_string); + + vtable_init_bindings.push(quote! { + let #ident = *vtable.get(#ident_string).ok_or_else(|| #missing_error)?; + // Safety: Transmute from a usize to a function pointer. + // This is valid on all targeted native platforms. + let #ident = std::mem::transmute::<usize, _>(#ident); + }); + + vtable_init.push(ident.clone()); + } + + let vtable_init = quote! { + #[doc = "Initializes the host vtable."] + #[doc = "Safety: the host vtable must not already be initialized."] + pub unsafe fn init_host_vtable(vtable: &std::collections::HashMap<&str, usize>) -> Result<(), &'static str> { + #(#vtable_init_bindings)* + HOST_VTABLE = Some(HostVTable { + #(#vtable_init,)* + }); + Ok(()) + } + }; + + let through_vtable_functions: Vec<_> = functions + .iter() + .map(|function| { + let ident = &function.sig.ident; + let args = &function.sig.inputs; + let ret = match &function.sig.output { + syn::ReturnType::Default => None, + syn::ReturnType::Type(_, ty) => Some(quote! { -> #ty }), + }; + let value_args: Vec<_> = args + .iter() + .map(|arg| match arg { + syn::FnArg::Receiver(_) => panic!("host functions cannot take self"), + syn::FnArg::Typed(arg) => arg.pat.clone(), + }) + .collect(); + let attrs = &function.attrs; + quote! { + #(#attrs)* + pub unsafe fn #ident(#args) #ret { + let vtable = HOST_VTABLE.as_ref().expect("vtable not initialized"); + let context = HOST_CONTEXT.expect("context not initialized"); + (vtable.#ident)(context, #(#value_args),*) + } + } + }) + .collect(); + + let attrs = &input.attrs; + + let result = quote! { + #[cfg(target_arch = "wasm32")] + #(#attrs)* + extern "C" { + #(#functions)* + } + + #[cfg(not(target_arch = "wasm32"))] + mod host_functions { + use super::*; + + static mut HOST_VTABLE: Option<HostVTable> = None; + static mut HOST_CONTEXT: Option<*const ()> = None; + + #vtable + + #vtable_init + + #[doc = "Sets the host context."] + #[doc = "Safety: can only be called once."] + pub unsafe fn init_host_context(context: *const ()) { + HOST_CONTEXT = Some(context); + } + + #(#through_vtable_functions)* + } + #[cfg(not(target_arch = "wasm32"))] + pub use host_functions::*; + }; + result.into() +} diff --git a/quill/sys/Cargo.toml b/quill/sys/Cargo.toml new file mode 100644 index 000000000..1ff2e6c0a --- /dev/null +++ b/quill/sys/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "quill-sys" +version = "0.1.0" +authors = ["caelunshun <caelunshun@gmail.com>"] +edition = "2018" + +[dependencies] +quill-common = { path = "../common" } +quill-sys-macros = { path = "../sys-macros" } diff --git a/quill/sys/src/lib.rs b/quill/sys/src/lib.rs new file mode 100644 index 000000000..c0b6d8f79 --- /dev/null +++ b/quill/sys/src/lib.rs @@ -0,0 +1,196 @@ +//! Raw FFI functions for host calls. +//! +//! # WASM vs Native +//! `quill-sys` exposes the same API on both WASM and native +//! targets, but there are internal differences in how +//! host functions are called. +//! +//! On WASM, host calls are `extern "C"` functions +//! that the linker adds as an import for the WASM module. +//! +//! On native, host calls are defined in a vtable struct +//! containing a function pointer for each call. The exported +//! functions in this crate defer to the vtable to make their host calls. +//! +//! Additionally, on native, `quill-sys` exports a `HOST_CONTEXT` constant +//! which is passed to every host call. The host expects this to be the +//! value passed to the `quill_setup` method. Failing to set this +//! constant correctly before making host calls +//! will result in undefined behavior. + +use std::mem::MaybeUninit; + +use quill_common::{ + block::BlockGetResult, entity::QueryData, EntityId, HostComponent, Pointer, PointerMut, +}; + +// The attribute macro transforms the block into either: +// 1. On WASM, an extern "C" block defining functions imported from the host. +// 2. On native targets, the necessary glue code to use the HOST_VTABLE +// to call host functions. +// The resulting public API is the same for both targets. +#[quill_sys_macros::host_functions] +#[link(wasm_import_module = "quill_01")] +extern "C" { + /// Registers a system. + /// + /// Each tick, the system is invoked + /// by calling the plugin's exported `quill_run_system` method. + /// `quill_run_system` is given the `system_data` pointer passed + /// to this host call. + pub fn register_system(system_data: PointerMut<u8>, name_ptr: Pointer<u8>, name_len: u32); + + /// Initiates a query. Returns the query data. + /// + /// The returned query buffers are allocated within + /// the plugin's bump allocator. They will be + /// freed automatically after the plugin finishes + /// executing the current system. + pub fn entity_query( + components_ptr: Pointer<HostComponent>, + components_len: u32, + query_data: PointerMut<MaybeUninit<QueryData>>, + ); + + /// Determines whether the given entity exists. + pub fn entity_exists(entity: EntityId) -> bool; + + /// Gets a component for an entity. + /// + /// Sets `bytes_ptr` to a pointer to the serialized + /// component bytes and `bytes_len` to the number of bytes. + /// + /// If the entity does not have the component, + /// then `bytes_ptr` is set to null, and `bytes_len` + /// is left untouched. + pub fn entity_get_component( + entity: EntityId, + component: HostComponent, + bytes_ptr: PointerMut<Pointer<u8>>, + bytes_len: PointerMut<u32>, + ); + + /// Sets or replaces a component for an entity. + /// + /// `bytes_ptr` is a pointer to the serialized + /// component. + /// + /// This will overwrite any existing component of the same type. + /// Does nothing if `entity` does not exist. + pub fn entity_set_component( + entity: EntityId, + component: HostComponent, + bytes_ptr: Pointer<u8>, + bytes_len: u32, + ); + + /// Adds an event for an entity. + /// + /// `bytes_ptr` is a pointer to the serialized + /// event. + /// + /// This will overwrite any existing event of the same type. + /// Does nothing if `entity` does not exist. + pub fn entity_add_event( + entity: EntityId, + event: HostComponent, + bytes_ptr: Pointer<u8>, + bytes_len: u32, + ); + + /// Adds a global event. + /// + /// `bytes_ptr` is a pointer to the serialized + /// component. + pub fn add_event(event: HostComponent, bytes_ptr: Pointer<u8>, bytes_len: u32); + + /// Sends a message to an entity. + /// + /// The given message should be in the JSON format. + /// + /// Does nothing if the entity does not exist or it does not have the `Chat` component. + pub fn entity_send_message(entity: EntityId, message_ptr: Pointer<u8>, message_len: u32); + + /// Sends a title to an entity. + /// + /// The given `Title` should contain at least a `title` or a `sub_title` + /// + /// Does nothing if the entity does not exist or if it does not have the `Chat` component. + pub fn entity_send_title(entity: EntityId, title_json_ptr: Pointer<u8>, title_len: u32); + + /// Creates an empty entity builder. + /// + /// This builder is used for creating an ecs-entity + /// + /// **This is NOT specifically for a minecraft entity!** + /// + pub fn entity_builder_new_empty() -> u32; + + /// Creates an entity builder. + /// + /// The builder is initialized with the default + /// components for the given `EntityInit`. + /// + /// `entity_init` is a `bincode`-serialized `EntityInit`. + pub fn entity_builder_new( + position: Pointer<u8>, + entity_init_ptr: Pointer<u8>, + entity_init_len: u32, + ) -> u32; + + /// Adds a component to an entity builder. + /// + /// `bytes` is the serialized component. + pub fn entity_builder_add_component( + builder: u32, + component: HostComponent, + bytes_ptr: Pointer<u8>, + bytes_len: u32, + ); + + /// Creates an entity from an entity builder. + /// + /// Returns the new entity. + /// + /// `builder` is consumed after this call. + /// Reusing it is undefined behavior. + pub fn entity_builder_finish(builder: u32) -> EntityId; + + /// Gets the block at the given position. + /// + /// Returns `None` if the block's chunk is unloaded + /// or if the Y coordinate is out of bounds. + pub fn block_get(x: i32, y: i32, z: i32) -> BlockGetResult; + + /// Sets the block at the given position. + /// + /// Returns `true` if successful and `false` + /// if the block's chunk is not loaded or + /// the Y coordinate is out of bounds. + /// + /// `block` is the vanilla ID of the block. + pub fn block_set(x: i32, y: i32, z: i32, block: u16) -> bool; + + /// Fills the given chunk section with `block`. + /// + /// Replaces all existing blocks in the section. + /// + /// This is an optimized bulk operation that will be significantly + /// faster than calling [`block_set`] on each block in the chunk section. + /// + /// Returns `true` if successful and `false` if the + /// block's chunk is not loaded or the section index is out of bounds. + pub fn block_fill_chunk_section(chunk_x: i32, section_y: u32, chunk_z: i32, block: u16) + -> bool; + + /// Sends a custom packet to an entity. + /// + /// Does nothing if the entity does not have the `ClientId` component. + pub fn plugin_message_send( + entity: EntityId, + channel_ptr: Pointer<u8>, + channel_len: u32, + data_ptr: Pointer<u8>, + data_len: u32, + ); +} diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 65b2df87f..000000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -beta diff --git a/server/Cargo.toml b/server/Cargo.toml deleted file mode 100644 index 7c76bc6f4..000000000 --- a/server/Cargo.toml +++ /dev/null @@ -1,78 +0,0 @@ -[package] -name = "feather-server" -version = "0.5.0" -authors = ["caelunshun <caelunshun@gmail.com>"] -edition = "2018" - -[lib] -name = "feather_server" -path = "src/lib.rs" - -[[bin]] -name = "feather-server" -path = "src/main.rs" - -[dependencies] -feather-blocks = { path = "../blocks" } -feather-core = { path = "../core" } -feather-item-block = { path = "../item_block" } -crossbeam = "0.7" -log = "0.4" -simple_logger = "1.3" -uuid = { version = "0.7", features = ["v4"] } -derive-new = "0.5" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -toml = "0.5" -rsa = "0.1" -# Match RSA git master -num-bigint = { version = "0.4", features = ["rand", "i128", "u64_digit", "prime", "zeroize"], package = "num-bigint-dig" } -rsa-der = "0.2" -rand = "0.7" -rand_xorshift = "0.2" -rand-legacy = { path = "../util/rand-legacy" } -bytes = "0.4" -hashbrown = { version = "0.6", features = ["rayon"] } -mojang-api = { git = "https://github.com/caelunshun/mojang-api-rs", rev = "6525e910ad53953fa16028f0fce74b1a19855733" } -multimap = "0.6" -hematite-nbt = "0.4" -specs = { version = "0.15", features = ["storage-event-control"] } -rayon = "1.2" -shrev = "1.1" -failure = "0.1" -num-derive = "0.3" -num-traits = "0.2" -smallvec = "0.6" -lazy_static = "1.4" -nalgebra-glm = "0.4" -nalgebra = "0.18" -ncollide3d = "0.20" -derive_deref = "1.1" -feather-codegen = { path = "../codegen" } -bitflags = "1.2" -fnv = "1.0" -base64 = "0.10" -bumpalo = "2.6" -thread_local = "1.0" -parking_lot = "0.9" -heapless = "0.5" -strum = "0.16" -simdnoise = "3.1" -simdeez = "0.6" -bitvec = "0.15" -tokio = "=0.2.0-alpha.6" -tokio-executor = "=0.2.0-alpha.6" -futures-preview = { version = "=0.3.0-alpha.19", features = ["async-await"] } -humantime-serde = "0.1" -ctrlc = "3.1" -arrayvec = "0.5" - -[dev-dependencies] -criterion = "0.3.0" - -[[bench]] -name = "worldgen" -harness = false - -[features] -nightly = ["specs/nightly", "parking_lot/nightly"] diff --git a/server/benches/worldgen.rs b/server/benches/worldgen.rs deleted file mode 100644 index fa2f2bdcd..000000000 --- a/server/benches/worldgen.rs +++ /dev/null @@ -1,120 +0,0 @@ -//! Benchmarking of world generation. We benchmark both the generation -//! of an entire chunk and each separate stage of the composable generator. - -#[macro_use] -extern crate criterion; - -use criterion::{BenchmarkId, Criterion}; -use feather_core::{Chunk, ChunkPosition}; -use feather_server::worldgen::{ - BasicCompositionGenerator, BiomeGenerator, ComposableGenerator, CompositionGenerator, - DensityMapGenerator, DensityMapGeneratorImpl, NearbyBiomes, TwoLevelBiomeGenerator, - WorldGenerator, -}; - -const POSITIONS: [ChunkPosition; 2] = [ - ChunkPosition::new(0, 0), - ChunkPosition::new(-2_000_000_000, 2_000_000_000), -]; - -const SEED: u64 = 7_867_835_453; - -pub fn generate_chunk(c: &mut Criterion) { - let mut group = c.benchmark_group("generate_chunk"); - - let generator = ComposableGenerator::default_with_seed(SEED); - - for position in POSITIONS.iter() { - group.bench_with_input( - BenchmarkId::from_parameter(*position), - position, - |b, position| b.iter(|| generator.generate_chunk(*position)), - ); - } -} - -pub fn generate_biome_grid(c: &mut Criterion) { - let mut group = c.benchmark_group("generate_biome_grid"); - - let generator = TwoLevelBiomeGenerator::default(); - - for position in POSITIONS.iter() { - group.bench_with_input( - BenchmarkId::from_parameter(*position), - position, - |b, position| b.iter(|| generator.generate_for_chunk(*position, SEED)), - ); - } -} - -pub fn generate_density_map(c: &mut Criterion) { - let mut group = c.benchmark_group("generate_density_map"); - - let generator = DensityMapGeneratorImpl::default(); - - for position in POSITIONS.iter() { - let mut biomes = vec![]; - - for z in -1..=1 { - for x in -1..=1 { - let pos = ChunkPosition::new(position.x + x, position.z + z); - biomes.push(TwoLevelBiomeGenerator::default().generate_for_chunk(pos, SEED)); - } - } - - let biomes = NearbyBiomes::from_vec(biomes); - group.bench_with_input( - BenchmarkId::from_parameter(*position), - position, - |b, position| b.iter(|| generator.generate_for_chunk(*position, &biomes, SEED)), - ); - } -} - -pub fn generate_composition(c: &mut Criterion) { - let mut group = c.benchmark_group("generate_composition"); - - let generator = BasicCompositionGenerator::default(); - - for position in POSITIONS.iter() { - let mut biomes = vec![]; - - for z in -1..=1 { - for x in -1..=1 { - let pos = ChunkPosition::new(position.x + x, position.z + z); - biomes.push(TwoLevelBiomeGenerator::default().generate_for_chunk(pos, SEED)); - } - } - - let biomes = NearbyBiomes::from_vec(biomes); - let density = - DensityMapGeneratorImpl::default().generate_for_chunk(*position, &biomes, SEED); - - let mut chunk = Chunk::new(*position); - - group.bench_with_input( - BenchmarkId::from_parameter(*position), - position, - |b, position| { - b.iter(|| { - generator.generate_for_chunk( - &mut chunk, - *position, - &biomes.biomes[4], - &density, - SEED, - ) - }) - }, - ); - } -} - -criterion_group!( - benches, - generate_chunk, - generate_biome_grid, - generate_density_map, - generate_composition -); -criterion_main!(benches); diff --git a/server/src/blocks/falling.rs b/server/src/blocks/falling.rs deleted file mode 100644 index d048f9b13..000000000 --- a/server/src/blocks/falling.rs +++ /dev/null @@ -1,70 +0,0 @@ -use shrev::ReaderId; -use specs::shrev::EventChannel; -use specs::{Builder, Entities, LazyUpdate, Read, System, Write}; - -use feather_core::world::ChunkMap; - -use feather_blocks::{Block, BlockExt}; - -use crate::blocks::{BlockNotifyEvent, BlockUpdateCause, BlockUpdateEvent}; -use crate::entity::{falling_block, PositionComponent, VelocityComponent}; -use feather_core::Position; - -/// This system listens to `BlockNotifyEvent`s. -#[derive(Default)] -pub struct FallingBlockCreationSystem { - reader: Option<ReaderId<BlockNotifyEvent>>, -} - -impl<'a> System<'a> for FallingBlockCreationSystem { - type SystemData = ( - Read<'a, EventChannel<BlockNotifyEvent>>, - Write<'a, EventChannel<BlockUpdateEvent>>, - Write<'a, ChunkMap>, - Read<'a, LazyUpdate>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (events, mut block_update, mut chunk_map, lazy, entities) = data; - - // Process events - for event in events.read(&mut self.reader.as_mut().unwrap()) { - match event.block { - Block::Sand | Block::RedSand | Block::Gravel => { - let mut below = event.pos; - below.y -= 1; - - if !chunk_map.block_at(below).unwrap_or(Block::Air).is_solid() { - chunk_map.set_block_at(event.pos, Block::Air).unwrap(); - - let update_event = BlockUpdateEvent { - cause: BlockUpdateCause::FallingBlock, - pos: event.pos, - old_block: event.block, - new_block: Block::Air, - }; - - block_update.single_write(update_event); - - let mut entity_pos: Position = event.pos.world_pos(); - // Center position on block - entity_pos.x += 0.5; - entity_pos.z += 0.5; - - falling_block::create(&lazy, &entities, event.block, entity_pos) - .with(PositionComponent { - current: entity_pos, - previous: entity_pos, - }) - .with(VelocityComponent::default()) - .build(); - } - } - _ => (), - } - } - } - - setup_impl!(reader); -} diff --git a/server/src/blocks/mod.rs b/server/src/blocks/mod.rs deleted file mode 100644 index 67d43a4f0..000000000 --- a/server/src/blocks/mod.rs +++ /dev/null @@ -1,128 +0,0 @@ -mod falling; - -pub use falling::FallingBlockCreationSystem; - -use shrev::{EventChannel, ReaderId}; -use specs::{DispatcherBuilder, Entity, Read, System, Write}; - -use feather_blocks::Block; -use feather_core::world::{BlockPosition, ChunkMap}; - -use crate::systems::{BLOCK_FALLING_CREATION, BLOCK_UPDATE_PROPAGATE}; -use hashbrown::HashSet; - -lazy_static! { - /// List of block types that need to be notified - /// of adjacent block updates. - static ref BLOCKS_TO_NOTIFY: HashSet<Block> = { - let mut set = HashSet::new(); - // Falling blocks - set.insert(Block::Sand); - set.insert(Block::RedSand); - set.insert(Block::Gravel); - set - }; -} - -/// Event triggered when a block is updated. -/// -/// This event is triggered *after* the block is updated -/// in the chunk map. -#[derive(Debug, Clone)] -pub struct BlockUpdateEvent { - /// The cause of this block update event. - pub cause: BlockUpdateCause, - /// The location of the block which was updated. - pub pos: BlockPosition, - /// The block which was previously at the position. - pub old_block: Block, - /// The new block at the position. - pub new_block: Block, -} - -/// The possible causes of a block update event. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum BlockUpdateCause { - /// Indicates that a player updated the block. - Player(Entity), - /// Indicates that a falling block updated the block. - FallingBlock, - /// A test block update caused, used for unit testing. - Test, -} - -#[derive(Debug, Clone)] -pub struct BlockNotifyEvent { - pub block: Block, - pub pos: BlockPosition, - pub notified_by: BlockPosition, -} - -/// System for propagating block update -/// events to surrounding blocks. -/// -/// This system listens to `BlockUpdateEvent`s. -#[derive(Default)] -pub struct BlockUpdatePropagateSystem { - reader: Option<ReaderId<BlockUpdateEvent>>, -} - -impl<'a> System<'a> for BlockUpdatePropagateSystem { - type SystemData = ( - Read<'a, EventChannel<BlockUpdateEvent>>, - Read<'a, ChunkMap>, - Write<'a, EventChannel<BlockNotifyEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (events, chunk_map, mut notify) = data; - - // Process events - for event in events.read(&mut self.reader.as_mut().unwrap()) { - let mut notify_events: Vec<BlockNotifyEvent> = Vec::new(); - - for x in -1..=1 { - for y in -1..=1 { - for z in -1..=1 { - let mut adjacent = event.pos; - adjacent.x += x; - adjacent.y += y; - adjacent.z += z; - let block = chunk_map.block_at(adjacent); - if let Some(block) = block { - if BLOCKS_TO_NOTIFY.contains(&block) { - notify_events.push(BlockNotifyEvent { - block, - pos: adjacent, - notified_by: event.pos, - }); - } - } - } - } - } - - // Notify all adjacent blocks at once - notify.drain_vec_write(&mut notify_events); - } - } - - setup_impl!(reader); -} - -pub fn init_logic(_dispatcher: &mut DispatcherBuilder) { - // TODO -} - -pub fn init_handlers(dispatcher: &mut DispatcherBuilder) { - dispatcher.add( - BlockUpdatePropagateSystem::default(), - BLOCK_UPDATE_PROPAGATE, - &[], - ); - dispatcher.add( - FallingBlockCreationSystem::default(), - BLOCK_FALLING_CREATION, - &[BLOCK_UPDATE_PROPAGATE], - ); -} diff --git a/server/src/chunk_logic.rs b/server/src/chunk_logic.rs deleted file mode 100644 index 2212903ef..000000000 --- a/server/src/chunk_logic.rs +++ /dev/null @@ -1,522 +0,0 @@ -//! Module for interacting with the chunk worker thread -//! from the server threads. -//! -//! Also handles unloading chunks when unused. -use crossbeam::channel::{Receiver, Sender}; -use shrev::{EventChannel, ReaderId}; -use specs::{ - Component, DispatcherBuilder, Entity, Read, ReadExpect, ReadStorage, System, World, Write, -}; -use std::sync::atomic::{AtomicU32, Ordering}; - -use feather_core::world::{ChunkMap, ChunkPosition}; - -use rayon::prelude::*; - -use crate::config::Config; -use crate::entity::EntityDestroyEvent; -use crate::systems::{CHUNK_HOLD_REMOVE, CHUNK_LOAD, CHUNK_OPTIMIZE, CHUNK_UNLOAD}; -use crate::worldgen::WorldGenerator; -use crate::{chunkworker, current_time_in_millis, TickCount, TPS}; -use feather_core::entity::EntityData; -use feather_core::Chunk; -use hashbrown::HashSet; -use multimap::MultiMap; -use specs::storage::BTreeStorage; -use std::collections::VecDeque; -use std::path::Path; -use std::sync::Arc; - -/// A handle for interacting with the chunk -/// worker thread. -#[derive(Debug, Clone)] -pub struct ChunkWorkerHandle { - pub sender: Sender<chunkworker::Request>, - pub receiver: Receiver<chunkworker::Reply>, -} - -/// Event which is triggered when a chunk is loaded. -#[derive(Debug, Clone)] -pub struct ChunkLoadEvent { - pub pos: ChunkPosition, - pub entities: Vec<EntityData>, -} - -/// Event which is triggered when a chunk fails to load. -#[derive(Debug, Clone, Copy)] -pub struct ChunkLoadFailEvent { - pub pos: ChunkPosition, -} - -/// Event which is triggered when a chunk is unloaded. -#[derive(Clone)] -pub struct ChunkUnloadEvent { - /// The chunk which was unloaded. - pub chunk: Arc<Chunk>, -} - -/// System for receiving loaded chunks from the chunk worker thread. -pub struct ChunkLoadSystem; - -impl<'a> System<'a> for ChunkLoadSystem { - type SystemData = ( - Write<'a, ChunkMap>, - Write<'a, EventChannel<ChunkLoadEvent>>, - Write<'a, EventChannel<ChunkLoadFailEvent>>, - ReadExpect<'a, ChunkWorkerHandle>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (mut chunk_map, mut load_events, mut fail_events, handle) = data; - - while let Ok(reply) = handle.receiver.try_recv() { - if let chunkworker::Reply::LoadedChunk(pos, result) = reply { - match result { - Ok((chunk, entities)) => { - chunk_map.set_chunk_at(pos, chunk); - - // Trigger event - let event = ChunkLoadEvent { pos, entities }; - load_events.single_write(event); - - trace!("Loaded chunk at {:?}", pos); - } - Err(err) => { - warn!("Failed to load chunk at {:?}: {}", pos, err); - let event = ChunkLoadFailEvent { pos }; - fail_events.single_write(event); - } - } - } - } - } - - fn setup(&mut self, world: &mut World) { - use specs::prelude::SystemData; - - let generator = world.fetch_mut::<Arc<dyn WorldGenerator>>().clone(); - let world_name = &world.fetch_mut::<Arc<Config>>().world.name.clone(); - let world_dir = Path::new(world_name); - - info!("Starting chunk worker thread"); - let (sender, receiver) = chunkworker::start(world_dir, generator); - world.insert(ChunkWorkerHandle { sender, receiver }); - - Self::SystemData::setup(world); - } -} - -/// Asynchronously loads the chunk at the given position. -/// At some point in time after this function is called, -/// the chunk will appear in the chunk map. -/// -/// In the event that the requested chunk does not exist -/// in the world save, it will be generated asynchronously. -pub fn load_chunk(handle: &ChunkWorkerHandle, pos: ChunkPosition) { - // Send request to chunk worker thread - handle - .sender - .send(chunkworker::Request::LoadChunk(pos)) - .unwrap(); -} - -/// Asynchronously saves the chunk at the given position. -pub fn save_chunk(handle: &ChunkWorkerHandle, chunk: Arc<Chunk>, entities: Vec<EntityData>) { - handle - .sender - .send(chunkworker::Request::SaveChunk(chunk, entities)) - .unwrap(); -} - -/// The chunk holder map contains a mapping -/// of chunk positions to any number of entities, called "holders." -/// When a chunk position has no holders, it will be queued -/// for unloading. -/// -/// In addition, the chunk holders map can be used to select -/// which players to broadcast an entity movement to: a player -/// who has a chunk hold on the entity's chunk would be able to see -/// the movement, while other players would be outside of the view -/// distance. This technique allows for higher performance and -/// avoids constant nearby entity queries. -#[derive(Default, Clone, Debug)] -pub struct ChunkHolders { - inner: MultiMap<ChunkPosition, Entity>, -} - -impl ChunkHolders { - pub fn holders_for(&self, chunk: ChunkPosition) -> Option<&[Entity]> { - self.inner.get_vec(&chunk).map(|holders| holders.as_slice()) - } - - pub fn chunk_has_holders(&self, chunk: ChunkPosition) -> bool { - let holders = self.holders_for(chunk); - - !(holders.is_none() || holders.unwrap().is_empty()) - } - - pub fn insert_holder(&mut self, chunk: ChunkPosition, holder: Entity) { - self.inner.insert(chunk, holder); - } - - pub fn remove_holder( - &mut self, - chunk: ChunkPosition, - holder: Entity, - events: &mut EventChannel<ChunkHolderReleaseEvent>, - ) { - if let Some(vec) = self.inner.get_vec_mut(&chunk) { - let index = vec.iter().position(|e| *e == holder); - if let Some(index) = index { - vec.remove(index); - - // Trigger event - let event = ChunkHolderReleaseEvent { - entity: holder, - chunk, - }; - events.single_write(event); - } - } - } -} - -/// Event triggered when a chunk holder is released. -#[derive(Clone, Debug)] -pub struct ChunkHolderReleaseEvent { - /// The entity which previously held the chunk. - pub entity: Entity, - /// The chunk which the holder was released from. - pub chunk: ChunkPosition, -} - -/// The queue of chunks to be unloaded. -/// See `ChunkUnloadSystem` for details. -#[derive(Clone, Debug, Default)] -pub struct ChunkUnloadQueue { - /// The internal queue. - queue: VecDeque<ChunkUnload>, -} - -/// A chunk to be unloaded. -#[derive(Clone, Debug, Default)] -struct ChunkUnload { - /// The position of this chunk. - chunk: ChunkPosition, - /// The tick count at which to unload the chunk. - time: u64, -} - -/// The amount of time, in ticks, between the time -/// a chunk is queued for unloading and when it is unloaded. -const CHUNK_UNLOAD_TIME: u64 = TPS * 5; // 5 seconds - TODO make this configurable - -/// System for unloading chunks when they have no holders. -/// This system performs multiple actions: -/// -/// * It listens to `ChunkHolderReleaseEvent` and -/// checks if a chunk has no holders. If so, it queues -/// the chunk to be unloaded after some period of time -/// (defined by a constant). -/// * It goes through chunks which are currently -/// queued to be loaded and unloads them if the -/// period of time has elapsed. -/// -/// Chunks are not unloaded immediately after having -/// no holders because doing so could open up -/// opportunities for exploits. For example, a player -/// could quickly move between chunk boundaries, causing -/// chunks at the edge of their view distance -/// to be loaded and unloaded at an alarming rate. -#[derive(Default)] -pub struct ChunkUnloadSystem { - reader: Option<ReaderId<ChunkHolderReleaseEvent>>, -} - -impl ChunkUnloadSystem { - pub fn new() -> Self { - Self { reader: None } - } -} - -impl<'a> System<'a> for ChunkUnloadSystem { - type SystemData = ( - Write<'a, ChunkMap>, - Write<'a, EventChannel<ChunkUnloadEvent>>, - Read<'a, EventChannel<ChunkHolderReleaseEvent>>, - Write<'a, ChunkUnloadQueue>, - Read<'a, ChunkHolders>, - Read<'a, TickCount>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - mut chunk_map, - mut unload_events, - release_events, - mut unload_queue, - holders, - tick_count, - ) = data; - - // Handle holder release events. - for event in release_events.read(&mut self.reader.as_mut().unwrap()) { - // If the chunk now has zero holders, queue it for unloading. - if !holders.chunk_has_holders(event.chunk) { - let unload = ChunkUnload { - chunk: event.chunk, - time: tick_count.0 + CHUNK_UNLOAD_TIME, - }; - unload_queue.queue.push_back(unload); - } - } - - // Unload chunks which are finished in the queue. - - // Since chunks are queued in the back and taken out - // from the front, the chunks in the front of the vector - // were queued the longest time ago. Because of this, - // we go through the unloads in the front of the queue - // to find which chunks to unload. - while let Some(unload) = unload_queue.queue.front() { - if tick_count.0 >= unload.time { - // Don't unload if new chunk holders have appeared. - if holders.chunk_has_holders(unload.chunk) { - unload_queue.queue.pop_front(); - continue; - } - - // Unload chunk and pop from queue. - if let Some(chunk) = chunk_map.unload_chunk_at(unload.chunk) { - let event = ChunkUnloadEvent { - chunk: Arc::new(chunk), - }; - unload_events.single_write(event); - } - - unload_queue.queue.pop_front(); - } else { - // We're done - all chunks farther up in - // the queue were queued before this one, - // so it isn't time to unload any of those. - break; - } - } - } - - fn setup(&mut self, world: &mut World) { - use specs::SystemData; - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<ChunkHolderReleaseEvent>>() - .register_reader(), - ); - } -} - -/// Component which stores which -/// chunks a given entity has a holder -/// on. -/// -/// Although this information is also -/// stored in the `ChunkHolders` resource, -/// using this component allows for efficiently -/// finding which chunks a given entity has -/// a hold on. -#[derive(Default)] -pub struct ChunkHolderComponent { - pub holds: HashSet<ChunkPosition>, -} - -impl ChunkHolderComponent { - pub fn new() -> Self { - Self { - holds: HashSet::new(), - } - } -} - -impl Component for ChunkHolderComponent { - type Storage = BTreeStorage<Self>; -} - -/// System for removing an entity's chunk holds -/// once it is destroyed. -#[derive(Default)] -pub struct ChunkHoldRemoveSystem { - reader: Option<ReaderId<EntityDestroyEvent>>, -} - -impl ChunkHoldRemoveSystem { - pub fn new() -> Self { - Self { reader: None } - } -} - -impl<'a> System<'a> for ChunkHoldRemoveSystem { - type SystemData = ( - Read<'a, EventChannel<EntityDestroyEvent>>, - Write<'a, ChunkHolders>, - ReadStorage<'a, ChunkHolderComponent>, - Write<'a, EventChannel<ChunkHolderReleaseEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (events, mut holders, holder_comps, mut release_events) = data; - - for event in events.read(&mut self.reader.as_mut().unwrap()) { - // If entity had chunk holds, remove them all - if let Some(holder_comp) = holder_comps.get(event.entity) { - debug!("Removing chunk holds for entity {:?}", event.entity); - holder_comp.holds.iter().for_each(|chunk| { - holders.remove_holder(*chunk, event.entity, &mut release_events); - }); - } - } - } - - fn setup(&mut self, world: &mut World) { - use specs::SystemData; - - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<EntityDestroyEvent>>() - .register_reader(), - ); - } -} - -/// The interval, in ticks, at which -/// chunks will be optimized. -const CHUNK_OPTIMIZE_INTERVAL: u64 = TPS * 60 * 5; // 5 minutes - -/// System which optimizes chunks periodically. -/// This allows for more efficient memory use -/// at the cost of the occasional CPU spike -/// when optimization happens. -/// -/// For optimal performance, this system is fully -/// concurrent - each chunk optimization is split -/// into a separate job and fed into `rayon`. -pub struct ChunkOptimizeSystem; - -impl<'a> System<'a> for ChunkOptimizeSystem { - type SystemData = (Write<'a, ChunkMap>, Read<'a, TickCount>); - - fn run(&mut self, data: Self::SystemData) { - let (mut chunk_map, tick_count) = data; - - // Only run every CHUNK_OPTIMIZE_INTERVAL ticks - if tick_count.0 % CHUNK_OPTIMIZE_INTERVAL != 0 { - return; - } - - let chunks = chunk_map.chunks_mut(); - - // Don't run if there aren't any chunks loaded - if chunks.is_empty() { - return; - } - - debug!("Optimizing chunks"); - - let start_time = current_time_in_millis(); - let count = AtomicU32::new(0); - - chunks.par_iter_mut().for_each(|(_, chunk)| { - count.fetch_add(chunk.optimize(), Ordering::SeqCst); - }); - - let end_time = current_time_in_millis(); - let elapsed = end_time - start_time; - - debug!( - "Optimized {} chunk sections (took {}ms - {:.2}ms/section)", - count.load(Ordering::SeqCst), - elapsed, - elapsed as f64 / f64::from(count.load(Ordering::SeqCst)) - ); - } -} - -pub fn init_logic(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(ChunkLoadSystem, CHUNK_LOAD, &[]); - dispatcher.add(ChunkOptimizeSystem, CHUNK_OPTIMIZE, &[]); -} - -pub fn init_handlers(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(ChunkUnloadSystem::default(), CHUNK_UNLOAD, &[]); - dispatcher.add(ChunkHoldRemoveSystem::default(), CHUNK_HOLD_REMOVE, &[]); -} - -#[cfg(test)] -mod tests { - use specs::{RunNow, World, WorldExt}; - - use feather_core::world::chunk::Chunk; - use feather_core::world::ChunkPosition; - - use super::*; - - #[test] - fn test_chunk_system() { - let (send1, _recv1) = crossbeam::channel::unbounded(); - let (send2, recv2) = crossbeam::channel::unbounded(); - let handle = ChunkWorkerHandle { - sender: send1, - receiver: recv2, - }; - - let chunk_map = ChunkMap::new(); - let pos = ChunkPosition::new(0, 0); - send2 - .send(chunkworker::Reply::LoadedChunk( - pos, - Ok((Chunk::new(pos), vec![])), - )) - .unwrap(); - - let load_event_channel = EventChannel::<ChunkLoadEvent>::new(); - let fail_event_channel = EventChannel::<ChunkLoadFailEvent>::new(); - - let mut system = ChunkLoadSystem; - let mut world = World::new(); - world.insert(chunk_map); - world.insert(handle); - world.insert(load_event_channel); - world.insert(fail_event_channel); - - system.run_now(&world); - - // Confirm that chunk was loaded - let chunk_map = world.read_resource::<ChunkMap>(); - let chunk = chunk_map.chunk_at(pos); - - assert!(chunk.is_some()); - assert!(chunk.unwrap().position() == pos); - } - - #[test] - fn test_load_chunk() { - let (send1, recv1) = crossbeam::channel::unbounded(); - let (_send2, recv2) = crossbeam::channel::unbounded(); - let handle = ChunkWorkerHandle { - sender: send1, - receiver: recv2, - }; - - let pos = ChunkPosition::new(0, 0); - - load_chunk(&handle, pos); - - let recv = recv1.try_recv().unwrap(); - match recv { - chunkworker::Request::LoadChunk(recv_pos) => assert_eq!(recv_pos, pos), - _ => panic!(), - } - } -} diff --git a/server/src/chunkworker.rs b/server/src/chunkworker.rs deleted file mode 100644 index 358a5b799..000000000 --- a/server/src/chunkworker.rs +++ /dev/null @@ -1,241 +0,0 @@ -//! This module handles the asynchronous loading and saving -//! of chunks. It receives load and save requests from the server -//! (over a channel) and executes them. -//! -//! If a chunk cannot be loaded, it is generated on the Rayon thread pool -//! instead. -use crate::worldgen::WorldGenerator; -use crossbeam::channel::{Receiver, Sender}; -use feather_core::entity::EntityData; -use feather_core::region; -use feather_core::region::{RegionHandle, RegionPosition}; -use feather_core::world::chunk::Chunk; -use feather_core::world::ChunkPosition; -use hashbrown::HashMap; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use std::time::{SystemTime, UNIX_EPOCH}; - -#[allow(clippy::large_enum_variant)] -pub enum Reply { - LoadedChunk(ChunkPosition, Result<(Chunk, Vec<EntityData>), Error>), - SavedChunk(ChunkPosition), -} - -#[derive(Clone)] -pub enum Request { - LoadChunk(ChunkPosition), - SaveChunk(Arc<Chunk>, Vec<EntityData>), - ShutDown, -} - -#[derive(Debug)] -pub enum Error { - ChunkNotExist, - LoadError(region::Error), -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - match self { - Error::ChunkNotExist => { - f.write_str("The specified chunk does not exist in the world save")? - } - Error::LoadError(e) => { - f.write_str("Error loading chunk: ")?; - e.fmt(f)?; - } - } - - Ok(()) - } -} - -/// An open region file -struct RegionFile { - /// The handle for the file - handle: RegionHandle, - /// The timestamp of the last time - /// this region file was used. This - /// value is used to close - /// the file after it isn't used for - /// some period of time. - /// - /// TODO actually implement this - _last_used: u64, -} - -struct ChunkWorker { - /// The directory in which the world - /// resides - dir: PathBuf, - - /// Channel used to send chunks and errors - /// back to the server thread - sender: Sender<Reply>, - /// Channel used to receive chunk load requests - /// from the server thread - receiver: Receiver<Request>, - - /// A map of currently open region files - open_regions: HashMap<RegionPosition, RegionFile>, - - /// World generator for new chunks. - world_generator: Arc<dyn WorldGenerator>, -} - -/// Starts a chunk worker on a new thread. -/// The returned channels can be used -/// to communicate with the worker. -pub fn start( - world_dir: &Path, - world_gen: Arc<dyn WorldGenerator>, -) -> (Sender<Request>, Receiver<Reply>) { - let (request_tx, request_rx) = crossbeam::channel::unbounded(); - let (reply_tx, reply_rx) = crossbeam::channel::unbounded(); - - let worker = ChunkWorker { - dir: world_dir.to_path_buf(), - sender: reply_tx, - receiver: request_rx, - open_regions: HashMap::new(), - world_generator: world_gen, - }; - - // Without changing the stack size, - // a stack overflow occurs here. - // This seeks to solve that. - std::thread::Builder::new() - .stack_size(1024 * 1024 * 5) - .name("Chunk Worker Thread".to_string()) - .spawn(move || run(worker)) - .expect("Unable to start chunk worker thread"); - - (request_tx, reply_rx) -} - -/// Runs the chunk worker on the current thread, -/// blocking indefinitely. -fn run(mut worker: ChunkWorker) { - while let Ok(request) = worker.receiver.recv() { - match request { - Request::ShutDown => break, - Request::SaveChunk(chunk, entities) => { - save_chunk(&mut worker, &chunk, entities); - } - Request::LoadChunk(pos) => { - if let Some(reply) = load_chunk(&mut worker, pos) { - worker.sender.send(reply).unwrap(); - } - } - } - } - - info!("Chunk worker terminating"); -} - -/// Attempts to load the chunk at the specified position. -fn load_chunk(worker: &mut ChunkWorker, pos: ChunkPosition) -> Option<Reply> { - let rpos = RegionPosition::from_chunk(pos); - - let file = worker_region(&mut worker.open_regions, &worker.dir, rpos); - // Load from region file - load_chunk_from_handle( - pos, - &mut file.handle, - &Arc::from(worker.sender.clone()), - &worker.world_generator, - ) -} - -fn load_chunk_from_handle( - pos: ChunkPosition, - handle: &mut RegionHandle, - sender: &Arc<Sender<Reply>>, - generator: &Arc<dyn WorldGenerator>, -) -> Option<Reply> { - let result = handle.load_chunk(pos); - - match result { - Ok(chunk) => Some(Reply::LoadedChunk(pos, Ok(chunk))), - Err(e) => match e { - region::Error::ChunkNotExist => { - schedule_generate_new_chunk(sender, pos, generator); - None - } - err => Some(Reply::LoadedChunk(pos, Err(Error::LoadError(err)))), - }, - } -} - -/// Generates a new chunk asynchronously, -/// sending the result to the provided Sender. -fn schedule_generate_new_chunk( - sender: &Arc<Sender<Reply>>, - pos: ChunkPosition, - generator: &Arc<dyn WorldGenerator>, -) { - let sender = sender.clone(); - let generator = Arc::clone(generator); - rayon::spawn(move || { - sender.send(generate_new_chunk(pos, &generator)).unwrap(); - }); -} - -/// Generates a new chunk synchronously, -/// returning a Reply to send to a Sender. -fn generate_new_chunk(pos: ChunkPosition, generator: &Arc<dyn WorldGenerator>) -> Reply { - Reply::LoadedChunk(pos, Ok((generator.generate_chunk(pos), vec![]))) -} - -/// Saves the chunk at the specified position. -fn save_chunk(worker: &mut ChunkWorker, chunk: &Chunk, entities: Vec<EntityData>) { - let rpos = RegionPosition::from_chunk(chunk.position()); - - let file = worker_region(&mut worker.open_regions, &worker.dir, rpos); - - file.handle.save_chunk(chunk, entities).unwrap(); - worker - .sender - .send(Reply::SavedChunk(chunk.position())) - .unwrap(); -} - -/// Returns whether the given chunk's region -/// is already loaded. -fn is_region_loaded( - open_regions: &HashMap<RegionPosition, RegionFile>, - rpos: RegionPosition, -) -> bool { - open_regions.contains_key(&rpos) -} - -fn worker_region<'a>( - open_regions: &'a mut HashMap<RegionPosition, RegionFile>, - dir: &PathBuf, - rpos: RegionPosition, -) -> &'a mut RegionFile { - if !is_region_loaded(open_regions, rpos) { - // Need to load region into memory - let mut handle = region::load_region(&dir, rpos); - if handle.is_err() { - // Create a new region file - handle = region::create_region(&dir, rpos); - } - - let handle = handle.unwrap(); - - let last_used = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - - let file = RegionFile { - handle, - _last_used: last_used, - }; - - open_regions.insert(rpos, file); - } - open_regions.get_mut(&rpos).unwrap() -} diff --git a/server/src/config.rs b/server/src/config.rs deleted file mode 100644 index f8c1e0f00..000000000 --- a/server/src/config.rs +++ /dev/null @@ -1,137 +0,0 @@ -use failure::_core::time::Duration; -use std::fs::read_to_string; - -#[derive(Debug, Fail)] -pub enum ConfigError { - #[fail(display = "Badly formatted configuration file: {}", _0)] - Parse(#[fail(cause)] toml::de::Error), - #[fail(display = "Failed to read configuration file: {}", _0)] - Io(#[fail(cause)] std::io::Error), -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Config { - pub io: IO, - pub proxy: Proxy, - pub server: Server, - pub gameplay: Gameplay, - pub log: Log, - pub resource_pack: ResourcePack, - pub world: World, -} - -pub const DEFAULT_CONFIG_STR: &str = include_str!("../config/feather.toml"); - -impl Default for Config { - fn default() -> Self { - toml::from_str(DEFAULT_CONFIG_STR).unwrap() - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct IO { - pub compression_threshold: i32, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Proxy {} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Server { - pub online_mode: bool, - pub motd: String, - pub max_players: i32, - pub view_distance: u8, - pub address: String, - pub port: u16, - pub default_gamemode: String, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Gameplay { - pub monster_spawning: bool, - pub animal_spawning: bool, - pub pvp: bool, - pub nerf_spawner_mobs: bool, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Log { - pub level: String, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct ResourcePack { - pub url: String, - pub hash: String, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct World { - pub name: String, - pub generator: String, - pub seed: String, - #[serde(with = "humantime_serde")] - pub save_interval: Duration, -} - -/// Loads the configuration from the given file/ -pub fn load_from_file(path: &str) -> Result<Config, ConfigError> { - let input = read_to_string(path).map_err(ConfigError::Io)?; - load(input) -} - -/// Loads the configuration from the given string. -pub fn load(input: String) -> Result<Config, ConfigError> { - let config: Config = toml::from_str(&input).map_err(ConfigError::Parse)?; - - Ok(config) -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum ProxyMode { - None, - Bungee, - Velocity, -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_load_config() { - let input = include_str!("../config/feather.toml"); - - let config = load(input.to_string()).expect("Config load failed"); - let io = &config.io; - assert_eq!(io.compression_threshold, 256); - - let server = &config.server; - assert_eq!(server.online_mode, true); - assert_eq!(server.motd, "A Feather server"); - assert_eq!(server.max_players, 16); - assert_eq!(server.default_gamemode, "creative"); - assert_eq!(server.view_distance, 6); - assert_eq!(server.address, "0.0.0.0"); - assert_eq!(server.port, 25565); - - let gameplay = &config.gameplay; - assert_eq!(gameplay.animal_spawning, true); - assert_eq!(gameplay.monster_spawning, true); - assert_eq!(gameplay.pvp, true); - assert_eq!(gameplay.nerf_spawner_mobs, false); - - let log = &config.log; - assert_eq!(log.level, "debug"); - - let resource_pack = &config.resource_pack; - assert_eq!(resource_pack.url, ""); - assert_eq!(resource_pack.hash, ""); - - let world = &config.world; - assert_eq!(world.name, "world"); - assert_eq!(world.generator, "default"); - assert_eq!(world.seed, ""); - assert_eq!(world.save_interval.as_millis(), 1000 * 60); - } -} diff --git a/server/src/entity/broadcast.rs b/server/src/entity/broadcast.rs deleted file mode 100644 index b2444f92e..000000000 --- a/server/src/entity/broadcast.rs +++ /dev/null @@ -1,201 +0,0 @@ -//! Module for broadcasting when an entity comes within -//! range of a player. Also handles sending the correct -//! packet to spawn entities on the client. -//! -//! Sending entities to a client is handled lazily -//! through `LazyUpdate`, because arbitrary components -//! may need to be accessed. - -use crate::chunk_logic::ChunkHolders; -use crate::entity::{LastKnownPositionComponent, PacketCreatorComponent}; -use crate::entity::{Metadata, PositionComponent}; -use crate::lazy::LazyUpdateExt; -use crate::network::{send_packet_boxed_to_player, send_packet_to_player, NetworkComponent}; -use feather_core::network::packet::implementation::PacketEntityMetadata; -use shrev::EventChannel; -use specs::{Entity, LazyUpdate, Read, ReadStorage, ReaderId, System, WorldExt}; - -/// An entity send request, containing -/// the player to send to and the entity -/// to send. -#[derive(Debug)] -struct SendRequest { - player: Entity, - entity: Entity, -} - -/// Event which is triggered when an entity -/// is sent to a client. This can be used to send -/// associated information, such as entity equipment. -#[derive(Debug, Clone)] -pub struct EntitySendEvent { - /// The player for which this event was triggered. - pub player: Entity, - /// The entity which was sent to the player. - pub entity: Entity, -} - -/// Event triggered when an entity of any -/// type is spawned. -#[derive(Debug, Clone)] -pub struct EntitySpawnEvent { - /// The spawned entity. - pub entity: Entity, -} - -/// System for broadcasting when an entity is spawned. -/// -/// Broadcasts are lazily queued for sending -/// and are sent by `EntitySendSystem`. -/// -/// This system listens to `EntitySpawnEvent`s. -#[derive(Default)] -pub struct EntityBroadcastSystem { - reader: Option<ReaderId<EntitySpawnEvent>>, -} - -impl<'a> System<'a> for EntityBroadcastSystem { - type SystemData = ( - ReadStorage<'a, PositionComponent>, - ReadStorage<'a, NetworkComponent>, - Read<'a, ChunkHolders>, - Read<'a, EventChannel<EntitySpawnEvent>>, - Read<'a, LazyUpdate>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (positions, networks, chunk_holders, spawn_events, lazy) = data; - - for event in spawn_events.read(self.reader.as_mut().unwrap()) { - // Broadcast entity to players who can see it. - let position = match positions.get(event.entity) { - Some(position) => position, - None => continue, - }; - let chunk = position.current.chunk_pos(); - - if let Some(holders) = chunk_holders.holders_for(chunk) { - for holder in holders { - if networks.get(*holder).is_none() { - // Not a player. - continue; - } - - // Don't send player to themself. - if *holder == event.entity { - continue; - } - - lazy.send_entity_to_player(*holder, event.entity); - } - } - } - } - - setup_impl!(reader); -} - -/// Lazily sends an entity to a player. -pub fn send_entity_to_player(lazy: &LazyUpdate, player: Entity, entity: Entity) { - lazy.exec(move |world| { - // Attempt to get the `PacketCreator` for the entity. - // If it doesn't exist, skip sending. - let packet_creators = world.read_component::<PacketCreatorComponent>(); - let packet_creator = match packet_creators.get(entity) { - Some(packet_creator) => packet_creator, - None => return, - }; - - let create_packet = packet_creator.0; - let packet = create_packet(world, entity); - - if let Some(network) = world.read_component::<NetworkComponent>().get(player) { - send_packet_boxed_to_player(network, packet); - - // If the entity has metadata, send it. - let metas = world.read_component::<Metadata>(); - if let Some(meta) = metas.get(entity) { - let packet = PacketEntityMetadata { - entity_id: entity.id() as i32, - metadata: meta.to_full_raw_metadata(), - }; - send_packet_to_player(network, packet); - } - } - - // Insert last known position - let positions = world.read_component::<PositionComponent>(); - let mut last_positions = world.write_component::<LastKnownPositionComponent>(); - if let Some(last_positions) = last_positions.get_mut(player) { - if let Some(pos) = positions.get(entity) { - last_positions.0.insert(entity, pos.current); - } - } - - // Trigger event - let event = EntitySendEvent { entity, player }; - world.fetch_mut::<EventChannel<_>>().single_write(event); - }); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::{item, VelocityComponent}; - use crate::player::ChunkCrossSystem; - use crate::testframework as t; - use feather_core::network::cast_packet; - use feather_core::network::packet::implementation::{SpawnObject, SpawnPlayer}; - use feather_core::network::packet::PacketType; - use feather_core::{Item, ItemStack}; - use specs::{Builder, WorldExt}; - - #[test] - fn test_spawn_player() { - let (mut w, mut d) = t::init_world(); - - let player1 = t::add_player(&mut w); - let player2 = t::add_player(&mut w); - - let event = EntitySpawnEvent { - entity: player1.entity, - }; - - w.fetch_mut::<EventChannel<_>>().single_write(event); - - d.dispatch(&w); - w.maintain(); - - t::assert_packet_not_received(&player1, PacketType::SpawnPlayer); // Player shouldn't have received packet for themselves - - let packet = t::assert_packet_received(&player2, PacketType::SpawnPlayer); - let packet = cast_packet::<SpawnPlayer>(&*packet); - - assert_eq!(packet.entity_id, player1.entity.id() as i32); - } - - #[test] - fn test_spawn_item() { - let (mut w, mut d) = t::builder() - .with(EntityBroadcastSystem::default(), "broadcast") - .with(ChunkCrossSystem::default(), "chunk_cross") - .build(); - - let player = t::add_player(&mut w); - - let item = item::create(&w.fetch(), &w.fetch(), ItemStack::new(Item::Stone, 1), 0) - .with(PositionComponent::default()) - .with(VelocityComponent::default()) - .build(); - - w.maintain(); - d.dispatch(&w); - w.maintain(); - - let spawn_entity = t::assert_packet_received(&player, PacketType::SpawnObject); - let spawn_entity = cast_packet::<SpawnObject>(&*spawn_entity); - - assert_eq!(spawn_entity.entity_id, item.id() as i32); - assert_eq!(spawn_entity.velocity_x, 0); - } -} diff --git a/server/src/entity/chunk.rs b/server/src/entity/chunk.rs deleted file mode 100644 index 22490f8c9..000000000 --- a/server/src/entity/chunk.rs +++ /dev/null @@ -1,446 +0,0 @@ -//! Maintains a list of entities which are in each -//! chunk, which allows for more efficient nearby -//! entity queries and packet broadcasting. - -use crate::chunk_logic::ChunkLoadEvent; -use crate::entity::{ - arrow, chicken, cow, donkey, horse, item, llama, mooshroom, pig, rabbit, sheep, squid, - EntityDestroyEvent, EntitySpawnEvent, PositionComponent, -}; -use crate::TickCount; -use feather_core::entity::EntityData; -use feather_core::world::ChunkPosition; -use hashbrown::{HashMap, HashSet}; -use shrev::EventChannel; -use specs::storage::ComponentEvent; -use specs::{ - BitSet, Entities, Entity, Join, LazyUpdate, Read, ReadStorage, ReaderId, System, World, - WorldExt, Write, -}; -use std::sync::atomic::{AtomicBool, Ordering}; - -/// Keeps track of which entities are in which chunk. -/// Also has a boolean for each chunk which indicates -/// whether its entities have been updated recently. -#[derive(Debug, Deref, DerefMut, Default)] -pub struct ChunkEntities(HashMap<ChunkPosition, (AtomicBool, Vec<Entity>)>); - -lazy_static! { - static ref EMPTY_VEC: Vec<Entity> = Vec::with_capacity(0); -} - -impl ChunkEntities { - /// Returns all entities in a given chunk. - pub fn entities_in_chunk(&self, chunk: ChunkPosition) -> &Vec<Entity> { - if let Some((_, entities)) = self.0.get(&chunk) { - entities - } else { - &EMPTY_VEC - } - } - - /// Returns all entities in the chunk, in addition to - /// a boolean indicating whether the entities have been - /// updated since the last call to this function. - pub fn entities_in_chunk_and_modified(&self, chunk: ChunkPosition) -> (bool, &[Entity]) { - if let Some((dirty, entities)) = self.0.get(&chunk) { - let d = dirty.load(Ordering::SeqCst); - dirty.store(false, Ordering::SeqCst); - (d, entities) - } else { - (false, &[]) - } - } - - /// Adds an entity to a chunk. - pub fn add_to_chunk(&mut self, chunk: ChunkPosition, entity: Entity) { - self.0 - .entry(chunk) - .and_modify(|(dirty, vec)| { - dirty.store(true, Ordering::SeqCst); - vec.push(entity) - }) - .or_insert_with(|| (AtomicBool::new(true), vec![entity])); - } - - /// Removes an entity from a chunk. - /// - /// # Panics - /// May panic in some cases if the entity is not contained - /// within the given chunk. - pub fn remove_from_chunk(&mut self, chunk: ChunkPosition, entity: Entity) { - let (dirty, vec) = match self.0.get_mut(&chunk) { - Some(vec) => vec, - _ => return, - }; - - let (index, _) = match vec.iter().enumerate().find(|x| *x.1 == entity) { - Some(index) => index, - None => return, - }; - vec.swap_remove(index); - - dirty.store(true, Ordering::SeqCst); - - if vec.is_empty() { - self.0.remove(&chunk); - } - } - - /// Returns a vector of all entities in all chunks - /// within the given view distance of another chunk. - pub fn entites_within_view_distance( - &self, - chunk: ChunkPosition, - view_distance: u8, - ) -> HashSet<Entity> { - let mut result = HashSet::new(); - - // 1 is subtracted from the view distance because of some odd - // client-side glitch (or maybe it's our fault?) where the last chunk within the view distance - // is not loaded correctly. - let view_distance = i32::from(view_distance) - 1; - - for x_offset in -view_distance..=view_distance { - for z_offset in -view_distance..=view_distance { - let chunk = ChunkPosition::new(chunk.x + x_offset, chunk.z + z_offset); - - result.extend(self.entities_in_chunk(chunk)); - } - } - - result - } -} - -/// System for updating the `ChunkEntities`. -/// -/// This system listens to `EntityMoveEvent`s, `EntitySpawnEvent`s, -/// and `EntityDestroyEvent`s. -#[derive(Default)] -pub struct ChunkEntityUpdateSystem { - dirty: BitSet, - move_reader: Option<ReaderId<ComponentEvent>>, - spawn_reader: Option<ReaderId<EntitySpawnEvent>>, - destroy_reader: Option<ReaderId<EntityDestroyEvent>>, -} - -impl<'a> System<'a> for ChunkEntityUpdateSystem { - type SystemData = ( - ReadStorage<'a, PositionComponent>, - Write<'a, ChunkEntities>, - Read<'a, EventChannel<EntitySpawnEvent>>, - Read<'a, EventChannel<EntityDestroyEvent>>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (positions, mut entity_chunks, spawn_events, destroy_events, entities) = data; - - self.dirty.clear(); - for event in positions.channel().read(self.move_reader.as_mut().unwrap()) { - if let ComponentEvent::Modified(id) = event { - self.dirty.add(*id); - } - } - - for (position, entity, _) in (&positions, &entities, &self.dirty).join() { - let new_pos = position.current.chunk_pos(); - let old_pos = position.previous.chunk_pos(); - - if new_pos != old_pos { - entity_chunks.remove_from_chunk(old_pos, entity); - entity_chunks.add_to_chunk(new_pos, entity); - } - } - - for event in spawn_events.read(self.spawn_reader.as_mut().unwrap()) { - if let Some(pos) = positions.get(event.entity) { - entity_chunks.add_to_chunk(pos.current.chunk_pos(), event.entity); - } - } - - for event in destroy_events.read(self.destroy_reader.as_mut().unwrap()) { - if let Some(pos) = positions.get(event.entity) { - entity_chunks.remove_from_chunk(pos.current.chunk_pos(), event.entity); - } - } - } - - fn setup(&mut self, world: &mut World) { - use specs::SystemData; - - Self::SystemData::setup(world); - - self.move_reader = Some( - world - .write_component::<PositionComponent>() - .register_reader(), - ); - self.destroy_reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader()); - self.spawn_reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader()); - } -} - -/// System for spawning entities inside newly-loaded chunks. -/// -/// This system listens to `ChunkLoadEvent`s. -#[derive(Default)] -pub struct EntityChunkLoadSystem { - reader: Option<ReaderId<ChunkLoadEvent>>, -} - -impl<'a> System<'a> for EntityChunkLoadSystem { - type SystemData = ( - Read<'a, EventChannel<ChunkLoadEvent>>, - Read<'a, LazyUpdate>, - Entities<'a>, - Read<'a, TickCount>, - ); - - #[allow(clippy::cognitive_complexity)] // Big match statement. Necessary - fn run(&mut self, data: Self::SystemData) { - let (load_events, lazy, entities, tick) = data; - - for event in load_events.read(self.reader.as_mut().unwrap()) { - for entity in &event.entities { - match entity { - EntityData::Item(item_data) => { - if item::create_from_data(&lazy, &entities, item_data, &tick).is_none() { - debug!("Error while loading item entity"); - } - } - EntityData::Arrow(arrow_data) => { - if arrow::create_from_data(&lazy, &entities, arrow_data).is_none() { - debug!("Error while loading arrow entity"); - } - } - EntityData::Cow(data) => { - if cow::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading cow entity") - } - } - EntityData::Pig(data) => { - if pig::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading pig entity") - } - } - EntityData::Chicken(data) => { - if chicken::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading chicken entity") - } - } - EntityData::Sheep(data) => { - if sheep::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading sheep entity") - } - } - EntityData::Horse(data) => { - if horse::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading horse entity") - } - } - EntityData::Llama(data) => { - if llama::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading llama entity") - } - } - EntityData::Mooshroom(data) => { - if mooshroom::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading mooshroom entity") - } - } - EntityData::Rabbit(data) => { - if rabbit::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading rabbit entity") - } - } - EntityData::Squid(data) => { - if squid::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading squid entity") - } - } - EntityData::Donkey(data) => { - if donkey::create_from_data(&lazy, &entities, data).is_none() { - debug!("Error while loading donkey entity") - } - } - // TODO: Spawn remaining entity types here. - EntityData::Unknown => { - trace!("Chunk {:?} contains an unknown entity type", event.pos); - } - } - } - } - } - - setup_impl!(reader); -} - -// Tests here cannot use the `testframework::add_entity` function -// because it automatically adds a ChunkEntities entry for the entity. -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::{test, ArrowComponent, ItemComponent}; - use crate::testframework as t; - use feather_core::entity::{ArrowEntityData, ItemEntityData}; - use specs::{Builder, World, WorldExt}; - - #[test] - fn test_chunk_entities() { - let mut chunks = ChunkEntities::default(); - - let mut world = World::new(); - let entity = world.create_entity().build(); - - let pos = ChunkPosition::new(0, 0); - - chunks.add_to_chunk(pos, entity); - assert_eq!(chunks.entities_in_chunk(pos).as_slice(), &[entity]); - assert!(chunks.entities_in_chunk_and_modified(pos).0); - assert!(!chunks.entities_in_chunk_and_modified(pos).0); - } - - #[test] - fn test_new_entity() { - let (mut w, mut d) = t::builder() - .with(ChunkEntityUpdateSystem::default(), "") - .build(); - - let pos = position!(1.0, 64.0, 1003.5); - let entity = w - .create_entity() - .with(PositionComponent { - current: pos, - previous: pos, - }) - .build(); - - let event = EntitySpawnEvent { entity }; - t::trigger_event(&w, event); - - d.dispatch(&w); - w.maintain(); - - let chunk_entities = w.fetch::<ChunkEntities>(); - assert_eq!( - chunk_entities.entities_in_chunk(pos.chunk_pos()).as_slice(), - &[entity] - ); - } - - #[test] - fn test_moved_entity() { - let (mut w, mut d) = t::builder() - .with(ChunkEntityUpdateSystem::default(), "") - .build(); - - let pos = position!(1.0, 64.0, -14.0); - let old_pos = position!(1.0, 64.0, -18.0); - - let entity = w - .create_entity() - .with(PositionComponent { - current: old_pos, - previous: old_pos, - }) - .build(); - - // Trigger flagged storage event. - w.write_component::<PositionComponent>() - .get_mut(entity) - .unwrap() - .current = pos; - - d.dispatch(&w); - w.maintain(); - - let chunk_entities = w.fetch::<ChunkEntities>(); - assert!(chunk_entities - .entities_in_chunk(old_pos.chunk_pos()) - .is_empty()); - assert_eq!( - chunk_entities.entities_in_chunk(pos.chunk_pos()).as_slice(), - &[entity] - ); - } - - #[test] - fn test_destroyed_entity() { - let (mut w, mut d) = t::builder() - .with(ChunkEntityUpdateSystem::default(), "") - .build(); - - let pos = position!(100.0, -100.0, -100.0); - let entity = test::create(&mut w, pos).build(); - - let event = EntityDestroyEvent { entity }; - t::trigger_event(&w, event); - - d.dispatch(&w); - w.maintain(); - - let chunk_entities = w.fetch::<ChunkEntities>(); - assert!(chunk_entities.entities_in_chunk(pos.chunk_pos()).is_empty()); - } - - #[test] - fn test_entities_within_view_distance() { - let mut chunk_entities = ChunkEntities::default(); - - let mut world = World::new(); - let entity1 = world.create_entity().build(); - let entity2 = world.create_entity().build(); - let entity3 = world.create_entity().build(); - let entity4 = world.create_entity().build(); - - let chunk1 = ChunkPosition::new(0, 0); - let chunk2 = ChunkPosition::new(0, 3); - let chunk3 = ChunkPosition::new(0, 4); - let chunk4 = ChunkPosition::new(-3, -3); - - chunk_entities.add_to_chunk(chunk1, entity1); - chunk_entities.add_to_chunk(chunk2, entity2); - chunk_entities.add_to_chunk(chunk3, entity3); - chunk_entities.add_to_chunk(chunk4, entity4); - - let view_distance = 4; - let entities = chunk_entities.entites_within_view_distance(chunk1, view_distance); - - assert!(entities.contains(&entity1)); - assert!(entities.contains(&entity2)); - assert!(!entities.contains(&entity3)); - assert!(entities.contains(&entity4)); - } - - #[test] - fn test_entities_loaded_in_chunk() { - let (mut w, mut d) = t::builder() - .with(EntityChunkLoadSystem::default(), "") - .build(); - - let entities = vec![ - EntityData::Item(ItemEntityData::default()), - EntityData::Arrow(ArrowEntityData::default()), - ]; - let pos = ChunkPosition::new(1, 2); - - let mut entity_spawn_reader = t::reader(&w); - let load_event = ChunkLoadEvent { pos, entities }; - t::trigger_event(&w, load_event); - - d.dispatch(&w); - w.maintain(); - d.dispatch(&w); - w.maintain(); - - // Confirm two entities were created: one arrow, one item - let mut events = t::triggered_events::<EntitySpawnEvent>(&w, &mut entity_spawn_reader); - - let first = events.remove(0).entity; - let second = events.remove(0).entity; - assert!(w.read_component::<ItemComponent>().contains(first)); - assert!(w.read_component::<ArrowComponent>().contains(second)); - } -} diff --git a/server/src/entity/component.rs b/server/src/entity/component.rs deleted file mode 100644 index 35e2cf1b1..000000000 --- a/server/src/entity/component.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Various Specs components. - -use feather_core::entity::EntityData; -use feather_core::world::Position; -use feather_core::{Gamemode, Packet}; -use glm::DVec3; -use specs::storage::BTreeStorage; -use specs::{Component, Entity, FlaggedStorage, Join, System, VecStorage, World, WriteStorage}; -use uuid::Uuid; - -pub struct PlayerComponent { - pub profile_properties: Vec<mojang_api::ProfileProperty>, - pub gamemode: Gamemode, -} - -impl Component for PlayerComponent { - type Storage = BTreeStorage<Self>; -} - -#[derive(Default, Debug, PartialEq, Clone, Copy)] -pub struct PositionComponent { - /// The current position of this entity. - pub current: Position, - /// The position of this entity on the previous - /// tick. At the end of each tick, `reset` should - /// be called. - pub previous: Position, -} - -impl PositionComponent { - /// Resets the current and previous position. - /// Should be called at the end of every tick. - pub fn reset(&mut self) { - self.previous = self.current; - } -} - -impl Component for PositionComponent { - type Storage = FlaggedStorage<Self, VecStorage<Self>>; -} - -/// An entity's velocity, in blocks per tick. -/// -/// Entities without this component are assumed -/// to have a velocity of 0. -#[derive(Deref, DerefMut, Debug, PartialEq, Clone, Copy)] -pub struct VelocityComponent(pub DVec3); - -impl Component for VelocityComponent { - type Storage = FlaggedStorage<Self, VecStorage<Self>>; -} - -impl Default for VelocityComponent { - fn default() -> Self { - Self(glm::vec3(0.0, 0.0, 0.0)) - } -} - -#[derive(Clone, Debug)] -pub struct NamedComponent { - pub display_name: String, - pub uuid: Uuid, -} - -impl Component for NamedComponent { - type Storage = BTreeStorage<Self>; -} - -pub trait PacketCreator: Fn(&World, Entity) -> Box<dyn Packet> + Send + Sync {} - -impl<F: Fn(&World, Entity) -> Box<dyn Packet> + Send + Sync> PacketCreator for F {} - -/// Component containing a closure which returns the packet -/// needed to spawn an entity. -/// -/// The closure requires world access because it may need to access -/// arbitrary components. -pub struct PacketCreatorComponent(pub &'static dyn PacketCreator); - -impl Component for PacketCreatorComponent { - type Storage = VecStorage<Self>; -} - -pub trait EntitySerializer: Fn(&World, Entity) -> EntityData + Send + Sync {} - -impl<F: Fn(&World, Entity) -> EntityData + Send + Sync> EntitySerializer for F {} - -/// Component containing a closure which returns the `EntityData` -/// for an entity. -/// -/// The closure requires world access because it may need to access -/// arbitrary components. -pub struct SerializerComponent(pub &'static dyn EntitySerializer); - -impl Component for SerializerComponent { - type Storage = VecStorage<Self>; -} - -/// System for resetting an entity's components -/// at the end of the tick. -pub struct ComponentResetSystem; - -impl<'a> System<'a> for ComponentResetSystem { - type SystemData = WriteStorage<'a, PositionComponent>; - - fn run(&mut self, mut positions: Self::SystemData) { - // Ensure that position update events are not triggered - // for this. See #81 - positions.set_event_emission(false); - - for position in (&mut positions).join() { - position.reset(); - } - - positions.set_event_emission(true); - } -} diff --git a/server/src/entity/destroy.rs b/server/src/entity/destroy.rs deleted file mode 100644 index 28aea7e9c..000000000 --- a/server/src/entity/destroy.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! Module for broadcasting and handling entity destroy -//! events. - -use crate::util::Util; -use feather_core::network::packet::implementation::DestroyEntities; -use shrev::{EventChannel, ReaderId}; -use specs::SystemData; -use specs::{Entities, Entity, Read, System, World}; - -/// Event triggered when an entity -/// of any type is destroyed. -#[derive(Debug, Clone)] -pub struct EntityDestroyEvent { - /// Note that when this event is triggered, - /// the entity isn't actually removed from the world - /// yet. This allows systems to access the entity's - /// data before it is destroyed. - /// - /// `EntityDestroySystem` is responsible for removing - /// entities once the `EntityDestroyEvent` has been - /// handled by all readers. - pub entity: Entity, -} - -/// System for removing entities from the world when they -/// are destroyed. -#[derive(Default)] -pub struct EntityDestroySystem { - reader: Option<ReaderId<EntityDestroyEvent>>, -} - -impl<'a> System<'a> for EntityDestroySystem { - type SystemData = (Read<'a, EventChannel<EntityDestroyEvent>>, Entities<'a>); - - fn run(&mut self, data: Self::SystemData) { - let (events, entities) = data; - - for event in events.read(&mut self.reader.as_mut().unwrap()) { - let _ = entities.delete(event.entity); - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<EntityDestroyEvent>>() - .register_reader(), - ); - } -} - -/// System for broadcasting when an entity is destroyed. -#[derive(Default)] -pub struct EntityDestroyBroadcastSystem { - reader: Option<ReaderId<EntityDestroyEvent>>, -} - -impl<'a> System<'a> for EntityDestroyBroadcastSystem { - type SystemData = (Read<'a, Util>, Read<'a, EventChannel<EntityDestroyEvent>>); - - fn run(&mut self, data: Self::SystemData) { - let (util, events) = data; - - for event in events.read(&mut self.reader.as_mut().unwrap()) { - let destroy_entities = DestroyEntities::new(vec![event.entity.id() as i32]); - - util.broadcast_entity_update(event.entity, destroy_entities, None); - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<EntityDestroyEvent>>() - .register_reader(), - ); - } -} diff --git a/server/src/entity/impls/animal/chicken.rs b/server/src/entity/impls/animal/chicken.rs deleted file mode 100644 index a92e4b3d3..000000000 --- a/server/src/entity/impls/animal/chicken.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct ChickenComponent; - -impl Component for ChickenComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(ChickenComponent) - .with(PhysicsBuilder::for_living().bbox(0.4, 0.7, 0.4).build()) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 7) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Chicken(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/cow.rs b/server/src/entity/impls/animal/cow.rs deleted file mode 100644 index e962c8daa..000000000 --- a/server/src/entity/impls/animal/cow.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct CowComponent; - -impl Component for CowComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(CowComponent) - .with(PhysicsBuilder::for_living().bbox(0.9, 1.4, 0.9).build()) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 9) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Cow(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/donkey.rs b/server/src/entity/impls/animal/donkey.rs deleted file mode 100644 index c7918ffcb..000000000 --- a/server/src/entity/impls/animal/donkey.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct DonkeyComponent; - -impl Component for DonkeyComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(DonkeyComponent) - .with( - PhysicsBuilder::for_living() - .bbox(1.396_484_4, 1.6, 1.396_484_4) - .build(), - ) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 11) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Donkey(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/horse.rs b/server/src/entity/impls/animal/horse.rs deleted file mode 100644 index 7b5d6f82f..000000000 --- a/server/src/entity/impls/animal/horse.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct HorseComponent; - -impl Component for HorseComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(HorseComponent) - .with( - PhysicsBuilder::for_living() - .bbox(1.396_484_4, 1.6, 1.396_484_4) - .build(), - ) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 29) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Horse(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/llama.rs b/server/src/entity/impls/animal/llama.rs deleted file mode 100644 index 29f06e68a..000000000 --- a/server/src/entity/impls/animal/llama.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct LlamaComponent; - -impl Component for LlamaComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(LlamaComponent) - .with(PhysicsBuilder::for_living().bbox(0.9, 1.87, 0.9).build()) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 36) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Llama(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/mod.rs b/server/src/entity/impls/animal/mod.rs deleted file mode 100644 index 89ede779b..000000000 --- a/server/src/entity/impls/animal/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! Implementations for animals: cows, pigs, chickens, etc. - -pub mod chicken; -pub mod cow; -pub mod donkey; -pub mod horse; -pub mod llama; -pub mod mooshroom; -pub mod pig; -pub mod rabbit; -pub mod sheep; -pub mod squid; diff --git a/server/src/entity/impls/animal/mooshroom.rs b/server/src/entity/impls/animal/mooshroom.rs deleted file mode 100644 index 830a147bf..000000000 --- a/server/src/entity/impls/animal/mooshroom.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct MooshroomComponent; - -impl Component for MooshroomComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(MooshroomComponent) - .with(PhysicsBuilder::for_living().bbox(0.9, 1.4, 0.9).build()) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 47) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Mooshroom(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/pig.rs b/server/src/entity/impls/animal/pig.rs deleted file mode 100644 index cfa88d29d..000000000 --- a/server/src/entity/impls/animal/pig.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct PigComponent; - -impl Component for PigComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(PigComponent) - .with(PhysicsBuilder::for_living().bbox(0.9, 0.9, 0.9).build()) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 51) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Pig(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/rabbit.rs b/server/src/entity/impls/animal/rabbit.rs deleted file mode 100644 index b247c2f83..000000000 --- a/server/src/entity/impls/animal/rabbit.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct RabbitComponent; - -impl Component for RabbitComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(RabbitComponent) - .with(PhysicsBuilder::for_living().bbox(0.4, 0.5, 0.4).build()) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 56) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Rabbit(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/sheep.rs b/server/src/entity/impls/animal/sheep.rs deleted file mode 100644 index 934456885..000000000 --- a/server/src/entity/impls/animal/sheep.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct SheepComponent; - -impl Component for SheepComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(SheepComponent) - .with(PhysicsBuilder::for_living().bbox(0.9, 1.3, 0.9).build()) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 58) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Sheep(AnimalData { base }) -} diff --git a/server/src/entity/impls/animal/squid.rs b/server/src/entity/impls/animal/squid.rs deleted file mode 100644 index 76bd309d7..000000000 --- a/server/src/entity/impls/animal/squid.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::entity::{ - base_data, create_mob_packet, PacketCreatorComponent, PositionComponent, SerializerComponent, - VelocityComponent, -}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use feather_core::entity::{AnimalData, EntityData}; -use feather_core::Packet; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Builder, Component, Entity, LazyUpdate, NullStorage, World}; - -#[derive(Default)] -pub struct SquidComponent; - -impl Component for SquidComponent { - type Storage = NullStorage<Self>; -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &'a EntitiesRes) -> LazyBuilder<'a> { - lazy.spawn_entity(entities) - .with(SquidComponent) - .with(PhysicsBuilder::for_living().bbox(0.8, 0.8, 0.8).build()) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &AnimalData, -) -> Option<Entity> { - let position = data.base.read_position()?; - let velocity = data.base.read_velocity()?; - - Some( - create(lazy, entities) - .with(PositionComponent { - current: position, - previous: position, - }) - .with(VelocityComponent(velocity)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - create_mob_packet(world, entity, 70) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let base = base_data(world, entity); - EntityData::Squid(AnimalData { base }) -} diff --git a/server/src/entity/impls/arrow.rs b/server/src/entity/impls/arrow.rs deleted file mode 100644 index a9754583f..000000000 --- a/server/src/entity/impls/arrow.rs +++ /dev/null @@ -1,168 +0,0 @@ -use shrev::EventChannel; -use specs::{ - Builder, Component, Entities, Entity, LazyUpdate, NullStorage, Read, ReaderId, System, World, - WorldExt, -}; - -use feather_core::packet::SpawnObject; -use feather_core::{Item, Packet, Position}; - -use crate::entity::component::{PacketCreatorComponent, SerializerComponent}; -use crate::entity::metadata::Metadata; -use crate::entity::movement::degrees_to_stops; -use crate::entity::{PositionComponent, VelocityComponent}; -use crate::lazy::LazyUpdateExt; -use crate::physics::PhysicsBuilder; -use crate::player::PLAYER_EYE_HEIGHT; -use crate::util::protocol_velocity; -use feather_core::entity::{ArrowEntityData, BaseEntityData, EntityData}; -use specs::world::{EntitiesRes, LazyBuilder}; -use uuid::Uuid; - -/// Component for arrow entities. -#[derive(Default)] -pub struct ArrowComponent; - -impl Component for ArrowComponent { - type Storage = NullStorage<Self>; -} - -/// Event triggered when arrow is shot. -#[derive(Debug, Clone)] -pub struct ShootArrowEvent { - pub arrow_type: Item, - pub shooter: Option<Entity>, - pub position: Position, - pub critical: bool, -} - -#[derive(Default)] -pub struct ShootArrowSystem { - reader: Option<ReaderId<ShootArrowEvent>>, -} - -impl<'a> System<'a> for ShootArrowSystem { - type SystemData = ( - Read<'a, LazyUpdate>, - Read<'a, EventChannel<ShootArrowEvent>>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (lazy, shoot_arrow_events, entities) = data; - - for event in shoot_arrow_events.read(self.reader.as_mut().unwrap()) { - let mut pos = event.position - + glm::vec3(0.0, PLAYER_EYE_HEIGHT, 0.0) - + event.position.direction() * 1.5; - pos.on_ground = false; - - // TODO: Scale velocity based on power - let velocity = pos.direction(); - - // TODO: shooter - - create(&lazy, &entities, false) - .with(PositionComponent { - current: pos, - previous: pos, - }) - .with(VelocityComponent(velocity)) - .build(); - } - } - - setup_impl!(reader); -} - -pub fn create<'a>(lazy: &'a LazyUpdate, entities: &EntitiesRes, critical: bool) -> LazyBuilder<'a> { - let meta = { - let mut meta_arrow = crate::entity::metadata::Arrow::default(); - let mask = if critical { - crate::entity::metadata::ArrowBitMask::CRITICAL - } else { - crate::entity::metadata::ArrowBitMask::default() - }; - meta_arrow.set_arrow_bit_mask(mask.bits()); - // meta_arrow.set_shooter(shooter); TODO - Metadata::Arrow(meta_arrow) - }; - - lazy.spawn_entity(entities) - .with(ArrowComponent) - .with( - PhysicsBuilder::new() - .bbox(0.5, 0.5, 0.5) - .gravity(-0.05) - .drag(0.99) - .slip_multiplier(0.0) - .build(), - ) - .with(meta) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &ArrowEntityData, -) -> Option<Entity> { - let pos = data.entity.read_position()?; - let vel = data.entity.read_velocity()?; - - let critical = match data.critical { - 0 => false, - _ => true, - }; - - // TODO: load other attributes - - Some( - create(lazy, entities, critical) - .with(PositionComponent { - current: pos, - previous: pos, - }) - .with(VelocityComponent(vel)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - let positions = world.read_component::<PositionComponent>(); - let velocities = world.read_component::<VelocityComponent>(); - - let position = positions.get(entity).unwrap().current; - let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocities.get(entity).unwrap().0); - - let packet = SpawnObject { - entity_id: entity.id() as i32, - object_uuid: Uuid::new_v4(), // TODO - ty: 60, - x: position.x, - y: position.y, - z: position.z, - pitch: degrees_to_stops(position.pitch), - yaw: degrees_to_stops(position.yaw), - data: 1, // TODO: Shooter entity ID - velocity_x, - velocity_y, - velocity_z, - }; - - Box::new(packet) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let positions = world.read_component::<PositionComponent>(); - let velocities = world.read_component::<VelocityComponent>(); - - EntityData::Arrow(ArrowEntityData { - entity: BaseEntityData::new( - positions.get(entity).unwrap().current, - velocities.get(entity).unwrap().0, - ), - critical: 0, // TODO - }) -} diff --git a/server/src/entity/impls/falling_block.rs b/server/src/entity/impls/falling_block.rs deleted file mode 100644 index 18c59a2cf..000000000 --- a/server/src/entity/impls/falling_block.rs +++ /dev/null @@ -1,142 +0,0 @@ -use shrev::ReaderId; -use specs::shrev::EventChannel; -use specs::{ - Builder, Component, DenseVecStorage, Entity, LazyUpdate, Read, ReadStorage, System, World, - WorldExt, Write, -}; - -use feather_blocks::{Block, BlockExt}; -use feather_core::packet::SpawnObject; -use feather_core::world::ChunkMap; - -use crate::blocks::{BlockUpdateCause, BlockUpdateEvent}; -use crate::entity::component::PacketCreatorComponent; -use crate::entity::metadata::Metadata; -use crate::entity::movement::degrees_to_stops; -use crate::entity::{EntityDestroyEvent, PositionComponent, VelocityComponent}; -use crate::lazy::LazyUpdateExt; -use crate::physics::{EntityPhysicsLandEvent, PhysicsBuilder}; -use crate::util::protocol_velocity; -use feather_core::{Packet, Position}; -use specs::world::{EntitiesRes, LazyBuilder}; -use uuid::Uuid; - -/// Component for falling block entities. -pub struct FallingBlockComponent { - pub block: Block, -} - -impl Default for FallingBlockComponent { - fn default() -> Self { - FallingBlockComponent { - block: Block::Stone, - } - } -} - -impl Component for FallingBlockComponent { - type Storage = DenseVecStorage<Self>; -} - -/// This system listens to `EntityPhysicsLandEvent`s. -#[derive(Default)] -pub struct FallingBlockLandSystem { - reader: Option<ReaderId<EntityPhysicsLandEvent>>, -} - -/// System for handling when a falling block lands -/// on the ground, destroying the entity and setting the block. -impl<'a> System<'a> for FallingBlockLandSystem { - type SystemData = ( - Read<'a, EventChannel<EntityPhysicsLandEvent>>, - ReadStorage<'a, FallingBlockComponent>, - Write<'a, EventChannel<EntityDestroyEvent>>, - Write<'a, EventChannel<BlockUpdateEvent>>, - Write<'a, ChunkMap>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (events, falling_blocks, mut destroy_events, mut block_updates, mut chunk_map) = data; - - // Process events - for event in events.read(&mut self.reader.as_mut().unwrap()) { - let entity = event.entity; - - let falling_block = match falling_blocks.get(entity) { - Some(block) => block, - None => continue, // Not a falling block - }; - - let destroy_event = EntityDestroyEvent { entity }; - destroy_events.single_write(destroy_event); - - let pos = event.pos.block_pos(); - let old_block = chunk_map.block_at(pos).unwrap(); - chunk_map.set_block_at(pos, falling_block.block).unwrap(); - - let update_event = BlockUpdateEvent { - cause: BlockUpdateCause::FallingBlock, - pos, - old_block, - new_block: falling_block.block, - }; - - block_updates.single_write(update_event); - } - } - - setup_impl!(reader); -} - -pub fn create<'a>( - lazy: &'a LazyUpdate, - entities: &EntitiesRes, - block: Block, - position: Position, -) -> LazyBuilder<'a> { - let meta = { - let mut meta_falling_block = crate::entity::metadata::FallingBlock::default(); - meta_falling_block.set_spawn_position(position.block_pos()); - Metadata::FallingBlock(meta_falling_block) - }; - - lazy.spawn_entity(entities) - .with(FallingBlockComponent { block }) - .with( - PhysicsBuilder::new() - .gravity(-0.04) - .drag(0.98) - .bbox(0.98, 0.98, 0.98) - .build(), - ) - .with(meta) - .with(PacketCreatorComponent(&create_packet)) - //.with(SerializerComponent(&serialize)) TODO -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - let blocks = world.read_component::<FallingBlockComponent>(); - let positions = world.read_component::<PositionComponent>(); - let velocities = world.read_component::<VelocityComponent>(); - - let block = blocks.get(entity).unwrap().block.native_state_id(); - let position = positions.get(entity).unwrap().current; - let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocities.get(entity).unwrap().0); - - let packet = SpawnObject { - entity_id: entity.id() as i32, - object_uuid: Uuid::new_v4(), - ty: 70, - x: position.x, - y: position.y, - z: position.z, - pitch: degrees_to_stops(position.pitch), - yaw: degrees_to_stops(position.yaw), - data: i32::from(block), - velocity_x, - velocity_y, - velocity_z, - }; - - Box::new(packet) -} diff --git a/server/src/entity/impls/item.rs b/server/src/entity/impls/item.rs deleted file mode 100644 index edc54b881..000000000 --- a/server/src/entity/impls/item.rs +++ /dev/null @@ -1,582 +0,0 @@ -//! Logic for working with item entities. -use crate::entity::metadata::{self, Metadata}; -use crate::entity::{ - ChunkEntities, EntityDestroyEvent, PlayerComponent, PositionComponent, VelocityComponent, -}; -use crate::physics::{nearby_entities, PhysicsBuilder}; -use crate::player::{ - InventoryComponent, InventoryUpdateEvent, PlayerItemDropEvent, PLAYER_EYE_HEIGHT, -}; -use crate::util::{protocol_velocity, Util}; -use crate::{TickCount, TPS}; -use feather_core::network::packet::implementation::CollectItem; -use feather_core::{Item, ItemStack, Packet}; -use rand::Rng; -use shrev::EventChannel; -use smallvec::SmallVec; -use specs::storage::ComponentEvent; -use specs::{ - BitSet, Builder, Component, DenseVecStorage, Entities, Entity, Join, LazyUpdate, Read, - ReadStorage, ReaderId, System, SystemData, World, WorldExt, Write, WriteStorage, -}; - -use crate::entity::component::{PacketCreatorComponent, SerializerComponent}; -use crate::entity::movement::degrees_to_stops; -use crate::lazy::LazyUpdateExt; -use feather_core::entity::{BaseEntityData, EntityData, ItemData, ItemEntityData}; -use feather_core::packet::SpawnObject; -use specs::world::{EntitiesRes, LazyBuilder}; -use uuid::Uuid; - -/// Component for item entities. -pub struct ItemComponent { - /// The tick at which this item is collectable - /// by a player. - pub collectable_at: u64, - /// This item's stack. - pub stack: ItemStack, -} - -impl Component for ItemComponent { - type Storage = DenseVecStorage<Self>; -} - -/// System for spawning an item entity when -/// an item is dropped. -/// -/// This system listens to `PlayerItemDropEvent`s. -#[derive(Default)] -pub struct ItemSpawnSystem { - reader: Option<ReaderId<PlayerItemDropEvent>>, -} - -impl<'a> System<'a> for ItemSpawnSystem { - type SystemData = ( - ReadStorage<'a, PositionComponent>, - Read<'a, LazyUpdate>, - Entities<'a>, - Read<'a, EventChannel<PlayerItemDropEvent>>, - Read<'a, TickCount>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (positions, lazy, entities, item_drop_events, tick) = data; - - let mut rng = rand::thread_rng(); - - for event in item_drop_events.read(self.reader.as_mut().unwrap()) { - // Spawn item entity. - - // Position is player's eye height minus 0.3 - let mut pos = { - let player_pos = positions.get(event.player).unwrap().current - + glm::vec3(0.0, PLAYER_EYE_HEIGHT, 0.0); - player_pos - glm::vec3(0.0f64, 0.3, 0.0) - }; - - pos.on_ground = false; - - // This velocity calculation was sourced from Glowstone's - // work. See https://github.com/GlowstoneMC/Glowstone/blob/dev/src/main/java/net/glowstone/entity/GlowHumanEntity.java - // (method drop(ItemStack stack)) for their code. - let velocity = { - let mut vel = pos.direction() * 0.3; - let rand_offset = 0.02; - - let x = rng.gen_range(0.0, rand_offset) - rand_offset / 2.0; - let y = rng.gen_range(0.0, 0.12); - let z = rng.gen_range(0.0, rand_offset) - rand_offset / 2.0; - - vel += glm::vec3(x, y, z); - - vel - }; - - create(&lazy, &entities, event.stack.clone(), tick.0 + TPS) - .with(PositionComponent { - current: pos, - previous: pos, - }) - .with(VelocityComponent(velocity)) - .build(); - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader()); - } -} - -/// System for merging item entities of the same -/// type. -#[derive(Default)] -pub struct ItemMergeSystem { - dirty: BitSet, - reader: Option<ReaderId<ComponentEvent>>, -} - -impl<'a> System<'a> for ItemMergeSystem { - type SystemData = ( - ReadStorage<'a, PositionComponent>, - ReadStorage<'a, ItemComponent>, - WriteStorage<'a, Metadata>, - Write<'a, EventChannel<EntityDestroyEvent>>, - Read<'a, ChunkEntities>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (positions, item_markers, mut metadatas, mut destroy_events, chunk_entities, entities) = - data; - - self.dirty.clear(); - - for event in positions.channel().read(self.reader.as_mut().unwrap()) { - match event { - ComponentEvent::Modified(id) | ComponentEvent::Inserted(id) => { - self.dirty.add(*id); - } - _ => (), - } - } - - let mut metadatas_to_update: SmallVec<[(Entity, Metadata); 2]> = smallvec![]; - // Used to not destroy both entities - let mut destroyed: SmallVec<[Entity; 2]> = smallvec![]; - - for (position, entity, _, _) in (&positions, &entities, &item_markers, &self.dirty).join() { - if !entities.is_alive(entity) { - continue; - } - - if destroyed.iter().any(|x| *x == entity) { - continue; - } - - let mut stack = item_stack_from_meta(metadatas.get(entity).unwrap()); - - // Find nearby entities and check if they are of the same item - // type. If so, merge the two item stacks. - let nearby = nearby_entities( - &chunk_entities, - &positions, - position.current, - glm::vec3(1.0, 0.5, 1.0), - ); - - for other in nearby { - // Skip entity if it's dead. - if !entities.is_alive(other) { - continue; - } - - if other == entity { - continue; - } - - // Skip if it's not an item. - if item_markers.get(other).is_none() { - continue; - } - - let other_stack = item_stack_from_meta(metadatas.get(other).unwrap()); - - if other_stack.ty != stack.ty { - continue; - } - - // Merge two stacks. - // This works by deleting `other` and adding - // together the amounts of the two item stacks. - entities.delete(other).unwrap(); - - let event = EntityDestroyEvent { entity: other }; - destroy_events.single_write(event); - - // TODO this could overflow... - stack.amount += other_stack.amount; - - metadatas_to_update.push((entity, item_meta(stack.clone()))); - destroyed.push(other); - } - } - - metadatas_to_update.into_iter().for_each(|(entity, meta)| { - metadatas.insert(entity, meta).unwrap(); - }); - } - - flagged_setup_impl!(PositionComponent, reader); -} - -/// System for collecting items when a player comes -/// near them. -#[derive(Default)] -pub struct ItemCollectSystem { - dirty: BitSet, - reader: Option<ReaderId<ComponentEvent>>, -} - -impl<'a> System<'a> for ItemCollectSystem { - type SystemData = ( - WriteStorage<'a, InventoryComponent>, - ReadStorage<'a, PositionComponent>, - ReadStorage<'a, PlayerComponent>, - ReadStorage<'a, ItemComponent>, - WriteStorage<'a, Metadata>, - Write<'a, EventChannel<InventoryUpdateEvent>>, - Write<'a, EventChannel<EntityDestroyEvent>>, - Read<'a, ChunkEntities>, - Read<'a, Util>, - Read<'a, TickCount>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - mut inventories, - positions, - players, - items, - mut metadatas, - mut inventory_events, - mut destroy_events, - chunk_entities, - util, - tick, - entities, - ) = data; - - self.dirty.clear(); - - read_flagged_events!(positions, self.reader, self.dirty); - - // For each player who has moved this tick, - // look for nearby items. - // We need to keep track of which items - // have already been collected to avoid - // having the same item being collected - // by two players at once; this would - // cause dupe exploits. - let mut collected_items: SmallVec<[Entity; 4]> = smallvec![]; - - for (position, inventory, player, _, _) in ( - &positions, - &mut inventories, - &entities, - &players, - &self.dirty, - ) - .join() - { - let nearby = nearby_entities( - &chunk_entities, - &positions, - position.current, - glm::vec3(1.0, 0.5, 1.0), - ); - - for other in nearby { - // If it's not an item, skip. - let item = continue_if_none!(items.get(other)); - - // Check if the item can be picked up yet. - if item.collectable_at > tick.0 { - continue; - } - - // If the item has already been collected, don't try it. - if collected_items.iter().any(|x| *x == other) { - continue; - } - - // Attempt to collect the item. - let mut stack = item_stack_from_meta(metadatas.get(other).unwrap()); - let (affected_slots, amount_left) = inventory.collect_item(stack.clone()); - - // Broadcast Collect Item packet, which gives an animation. - let packet = CollectItem { - collected: other.id() as i32, - collector: player.id() as i32, - count: i32::from(stack.amount - amount_left), - }; - util.broadcast_entity_update(player, packet, None); - - if amount_left == 0 { - entities.delete(other).unwrap(); - collected_items.push(other); - - let event = EntityDestroyEvent { entity: other }; - destroy_events.single_write(event); - } else { - stack.amount = amount_left; - let meta = item_meta(stack); - metadatas.insert(other, meta).unwrap(); - } - - // Trigger inventory update event. - let event = InventoryUpdateEvent { - slots: affected_slots, - player, - }; - inventory_events.single_write(event); - } - } - } - - flagged_setup_impl!(PositionComponent, reader); -} - -pub fn create<'a>( - lazy: &'a LazyUpdate, - entities: &EntitiesRes, - stack: ItemStack, - collectable_at: u64, -) -> LazyBuilder<'a> { - let meta = { - let mut meta_item = crate::entity::metadata::Item::default(); - meta_item.set_item(Some(stack.clone())); - Metadata::Item(meta_item) - }; - - lazy.spawn_entity(entities) - .with(ItemComponent { - stack, - collectable_at, - }) - .with( - PhysicsBuilder::new() - .bbox(0.25, 0.25, 0.25) - .gravity(-0.04) - .drag(0.98) - .build(), - ) - .with(VelocityComponent::default()) - .with(meta) - .with(PacketCreatorComponent(&create_packet)) - .with(SerializerComponent(&serialize)) -} - -pub fn create_from_data( - lazy: &LazyUpdate, - entities: &EntitiesRes, - data: &ItemEntityData, - tick: &TickCount, -) -> Option<Entity> { - let pos = data.entity.read_position()?; - let vel = data.entity.read_velocity()?; - - let stack = ItemStack::new(Item::from_identifier(&data.item.item)?, data.item.count); - - let collectable_at = data.pickup_delay as u64 + tick.0; - - Some( - create(lazy, entities, stack, collectable_at) - .with(PositionComponent { - current: pos, - previous: pos, - }) - .with(VelocityComponent(vel)) - .build(), - ) -} - -fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - let positions = world.read_component::<PositionComponent>(); - let velocities = world.read_component::<VelocityComponent>(); - - let position = positions.get(entity).unwrap().current; - let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocities.get(entity).unwrap().0); - - let packet = SpawnObject { - entity_id: entity.id() as i32, - object_uuid: Uuid::new_v4(), - ty: 2, // Type 2 for item stack - x: position.x, - y: position.y, - z: position.z, - pitch: degrees_to_stops(position.pitch), - yaw: degrees_to_stops(position.yaw), - data: 1, // Has velocity - velocity_x, - velocity_y, - velocity_z, - }; - - Box::new(packet) -} - -fn serialize(world: &World, entity: Entity) -> EntityData { - let positions = world.read_component::<PositionComponent>(); - let velocities = world.read_component::<VelocityComponent>(); - let items = world.read_component::<ItemComponent>(); - - let item = items.get(entity).unwrap(); - let position = positions.get(entity).unwrap(); - let velocity = velocities.get(entity).unwrap(); - - EntityData::Item(ItemEntityData { - entity: BaseEntityData::new(position.current, velocity.0), - age: 0, // TODO - pickup_delay: 0, // TODO - item: ItemData { - item: item.stack.ty.identifier().to_string(), - count: item.stack.amount, - }, - }) -} - -pub fn item_stack_from_meta(meta: &Metadata) -> ItemStack { - match meta { - Metadata::Item(item) => item.item().unwrap(), - _ => panic!(), - } -} - -pub fn item_meta(stack: ItemStack) -> Metadata { - let mut item = metadata::Item::default(); - item.set_item(Some(stack)); - Metadata::Item(item) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::{ChunkEntityUpdateSystem, EntitySpawnEvent}; - use crate::testframework as t; - use feather_core::inventory::SLOT_HOTBAR_OFFSET; - use feather_core::network::cast_packet; - use feather_core::{Item, ItemStack, PacketType}; - use specs::WorldExt; - - #[test] - fn test_item_spawn_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - t::set_entity_pos(&w, player.entity, position!(0.0, 1.0, 0.0)); - - let stack = ItemStack::new(Item::AcaciaBoat, 4); - - let mut entity_spawn_reader = t::reader(&w); - - let event = PlayerItemDropEvent { - slot: None, - stack, - player: player.entity, - }; - t::trigger_event(&w, event); - - d.dispatch(&w); - w.maintain(); - - // Confirm event was triggered - let events = t::triggered_events::<EntitySpawnEvent>(&w, &mut entity_spawn_reader); - assert_eq!(events.len(), 1); - let first = events.first().unwrap(); - let entity = first.entity; - - // Check position - let pos = t::entity_pos(&w, entity); - assert_float_eq!(pos.x, 0.0); - assert_float_eq!(pos.z, 0.0); - - // Confirm that velocity was created - let _vel = t::entity_vel(&w, entity).unwrap(); - } - - #[test] - fn test_item_merge_system() { - let (mut w, mut d) = t::builder() - .with_dep(ItemMergeSystem::default(), "item_merge", &[]) - .build(); - - let item1 = create( - &w.fetch(), - &w.fetch(), - ItemStack::new(Item::EnderPearl, 4), - 0, - ) - .with(PositionComponent::default()) - .build(); - let item2 = create( - &w.fetch(), - &w.fetch(), - ItemStack::new(Item::EnderPearl, 7), - 0, - ) - .with(PositionComponent::default()) - .build(); - - let mut updater = ChunkEntityUpdateSystem::default(); - updater.setup(&mut w); - - w.maintain(); - - // Update chunk entities so `nearby_entities` works - specs::RunNow::run_now(&mut updater, &w); - - d.dispatch(&w); - w.maintain(); - - assert!(!w.is_alive(item2)); - assert!(w.is_alive(item1)); - - let metadatas = w.read_component::<Metadata>(); - let metadata = metadatas.get(item1).unwrap(); - - let stack = item_stack_from_meta(&metadata); - assert_eq!(stack.ty, Item::EnderPearl); - assert_eq!(stack.amount, 11); - } - - #[test] - fn test_item_collect_system() { - let (mut w, mut d) = t::builder() - .with_dep(ItemCollectSystem::default(), "", &[]) - .build(); - - let player = t::add_player(&mut w); - let stack = ItemStack::new(Item::String, 4); - let item = create(&w.fetch(), &w.fetch(), stack.clone(), 0) - .with(PositionComponent::default()) - .build(); - - let mut destroy_reader = t::reader(&w); - - // Allow item to be collected - w.fetch_mut::<TickCount>().0 = 0; - - let mut updater = ChunkEntityUpdateSystem::default(); - updater.setup(&mut w); - - w.maintain(); - - // Update chunk entities so `nearby_entities` works - - specs::RunNow::run_now(&mut updater, &w); - - d.dispatch(&w); - w.maintain(); - - let destroy_events = t::triggered_events::<EntityDestroyEvent>(&w, &mut destroy_reader); - let first = destroy_events.first().unwrap(); - assert_eq!(first.entity, item); - - assert!(!w.is_alive(item)); - - let inventories = w.read_component::<InventoryComponent>(); - let inventory = inventories.get(player.entity).unwrap(); - - assert_eq!(inventory.item_at(SLOT_HOTBAR_OFFSET), Some(&stack)); - - let packet = t::assert_packet_received(&player, PacketType::CollectItem); - let packet = cast_packet::<CollectItem>(&*packet); - - assert_eq!(packet.collector, player.entity.id() as i32); - assert_eq!(packet.collected, item.id() as i32); - assert_eq!(packet.count, 4); - } -} diff --git a/server/src/entity/impls/mod.rs b/server/src/entity/impls/mod.rs deleted file mode 100644 index f46a2d94d..000000000 --- a/server/src/entity/impls/mod.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! Entity implementations. -//! -//! Every entity implementation is expected to define -//! the following functions: -//! -//! * `create(&LazyUpdate, &EntitiesRes) -> LazyBuilder`. When a system spawns an entity -//! of a known type, it should call this function on the `LazyBuilder` -//! returned by `LazyUpdate::spawn_entity` to apply components, such as markers, metadata, -//! `SerializerComponent`, and `SpawnPacketComponent`. This function may -//! take parameters. This function should not apply generic components, -//! such as position and velocity; the callee is responsible for this. -//! * `create_from_data(&LazyUpdate, &EntitiesRes, &{Entity}Data) -> Option<Entity>`. Spawns an -//! entity loaded from the given entity data. If the entity creation failed, `None` is returned. -//! -//! These functions should be invoked in the form `name::function`, e.g. -//! `arrow::create` or `item::create_from_data`. -//! -//! Entity implementations should also define systems related to the entity: for -//! example, most entities will have an update system which updates an entity -//! on each tick. - -pub mod arrow; -pub mod falling_block; -pub mod item; - -mod animal; -pub use animal::*; - -use crate::entity::{ - degrees_to_stops, metadata::EMPTY_METADATA, Metadata, NamedComponent, PositionComponent, - VelocityComponent, -}; -use crate::util::protocol_velocity; -use feather_core::entity::BaseEntityData; -use feather_core::network::packet::implementation::SpawnMob; -use feather_core::Packet; -use specs::{Entity, World, WorldExt}; -use uuid::Uuid; - -#[cfg(test)] -pub mod test; - -/// Returns a `Spawn Mob` packet with the given entity type ID. -pub fn create_mob_packet(world: &World, entity: Entity, type_id: i32) -> Box<dyn Packet> { - let entity_id = entity.id() as i32; - let entity_uuid = world - .read_component::<NamedComponent>() - .get(entity) - .map(|named| named.uuid) - .unwrap_or_else(Uuid::new_v4); - - let positions = world.read_component::<PositionComponent>(); - let position = positions.get(entity).copied().unwrap_or_default(); - let velocities = world.read_component::<VelocityComponent>(); - let velocity = velocities.get(entity).copied().unwrap_or_default(); - - let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocity.0); - - let metadatas = world.read_component::<Metadata>(); - let metadata = metadatas.get(entity).unwrap_or(&EMPTY_METADATA); - - let packet = SpawnMob { - entity_id, - entity_uuid, - ty: type_id, - x: position.current.x, - y: position.current.y, - z: position.current.z, - yaw: degrees_to_stops(position.current.yaw), - pitch: degrees_to_stops(position.current.pitch), - head_pitch: degrees_to_stops(position.current.pitch), // FIXME: is this correct? - velocity_x, - velocity_y, - velocity_z, - meta: metadata.to_full_raw_metadata(), - }; - - Box::new(packet) -} - -/// Creates a `BaseEntityData` for the given entity. -pub fn base_data(world: &World, entity: Entity) -> BaseEntityData { - let position = world - .read_component::<PositionComponent>() - .get(entity) - .copied() - .unwrap_or_default(); - let velocity = world - .read_component::<VelocityComponent>() - .get(entity) - .copied() - .unwrap_or_default(); - - BaseEntityData::new(position.current, velocity.0) -} diff --git a/server/src/entity/impls/test.rs b/server/src/entity/impls/test.rs deleted file mode 100644 index 21ef64b9f..000000000 --- a/server/src/entity/impls/test.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! A fake entity implementation for unit tests. - -use crate::entity::{EntitySpawnEvent, PositionComponent, VelocityComponent}; -use feather_core::Position; -use shrev::EventChannel; -use specs::{Builder, EntityBuilder, World, WorldExt}; - -pub fn create(world: &mut World, pos: Position) -> EntityBuilder { - let builder = world - .create_entity() - .with(PositionComponent { - current: pos, - previous: pos, - }) - .with(VelocityComponent(glm::vec3(0.0, 0.0, 0.0))); - builder - .world - .fetch_mut::<EventChannel<EntitySpawnEvent>>() - .single_write(EntitySpawnEvent { - entity: builder.entity, - }); - builder -} diff --git a/server/src/entity/metadata.rs b/server/src/entity/metadata.rs deleted file mode 100644 index 82f3d1c3f..000000000 --- a/server/src/entity/metadata.rs +++ /dev/null @@ -1,182 +0,0 @@ -//! Definition for entity metadata enum. - -#![allow(clippy::too_many_arguments)] // TODO: builder patterm - -use crate::util::Util; -use feather_core::packet::PacketEntityMetadata; -use feather_core::{BlockPosition, EntityMetadata, Slot}; -use specs::storage::ComponentEvent; -use specs::{ - BitSet, Component, Entities, FlaggedStorage, Join, Read, ReaderId, System, VecStorage, - WriteStorage, -}; -use uuid::Uuid; - -type OptUuid = Option<Uuid>; - -bitflags! { - pub struct EntityBitMask: u8 { - const ON_FIRE = 0x01; - const CROUCHED = 0x02; - const SPRITING = 0x08; - const SWIMMING = 0x10; - const INVISIBLE = 0x20; - const GLOWING_EFFECT = 0x40; - const FLYING_WITH_ELYTRA = 0x80; - } -} - -bitflags! { - #[derive(Default)] - pub struct ArrowBitMask: u8 { - const CRITICAL = 0x01; - const NO_CLIP = 0x02; - } -} - -lazy_static! { - pub static ref EMPTY_METADATA: Metadata = { Metadata::Entity(Entity::default()) }; -} - -entity_metadata! { - Metadata, - Entity { - bit_mask: u8() = 0, - air: VarInt() = 1, - silent: bool() = 4, - no_gravity: bool() = 5, - }, - Item: Entity { - item: Slot() = 6, - }, - Living: Entity { - hand_states: u8() = 6, - health: f32(1.0) = 7, - potion_effect_color: VarInt() = 8, - potion_effect_ambient: bool() = 9, - arrows: VarInt() = 10, - }, - Player: Living { - additional_hearts: f32() = 11, - score: VarInt() = 12, - displayed_skin_parts: u8() = 13, - main_hand: u8(1) = 14, - }, - Arrow: Entity { - arrow_bit_mask: u8() = 6, - shooter: OptUuid() = 7, - }, - TippedArrow: Arrow { - color: VarInt() = 8, - }, - FallingBlock: Entity { - spawn_position: BlockPosition() = 6, - }, -} - -impl Component for Metadata { - type Storage = FlaggedStorage<Self, VecStorage<Self>>; -} - -/// System for broadcasting entity metadata updates. -#[derive(Default)] -pub struct MetadataBroadcastSystem { - dirty: BitSet, - reader: Option<ReaderId<ComponentEvent>>, -} - -impl<'a> System<'a> for MetadataBroadcastSystem { - type SystemData = (WriteStorage<'a, Metadata>, Read<'a, Util>, Entities<'a>); - - fn run(&mut self, data: Self::SystemData) { - let (mut metadatas, util, entities) = data; - - self.dirty.clear(); - - read_flagged_events!(metadatas, self.reader, self.dirty); - - // Ensure that metadata update events are not - // triggered for this mutation of the storage. - metadatas.set_event_emission(false); - - // Go through updated metadata and broadcast changes. - for (metadata, entity, _) in (&mut metadatas, &entities, &self.dirty).join() { - let packet = PacketEntityMetadata { - entity_id: entity.id() as i32, - metadata: metadata.to_raw_metadata(), - }; - - util.broadcast_entity_update(entity, packet, None); - } - - metadatas.set_event_emission(true); - } - - flagged_setup_impl!(Metadata, reader); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::test; - use crate::testframework as t; - use feather_core::entitymeta::MetaEntry; - use feather_core::network::cast_packet; - use feather_core::PacketType; - use specs::{Builder, WorldExt}; - - #[test] - fn test_basic() { - let mut meta = Metadata::Entity(Entity::new( - (EntityBitMask::ON_FIRE | EntityBitMask::CROUCHED).bits(), - 0, - false, - false, - )); - - let raw = meta.to_raw_metadata(); - - assert_eq!(raw.get(0), Some(MetaEntry::Byte(0b0000_0011))); - assert_eq!(raw.get(5), Some(MetaEntry::Boolean(false))); - assert_eq!(raw.get(6), None); - } - - #[test] - fn test_inheritance() { - let _meta = Metadata::Item(Item::new( - (EntityBitMask::ON_FIRE).bits(), - 0, - false, - false, - None, - )); - } - - #[test] - fn test_metadata_update_system() { - let (mut w, mut d) = t::builder() - .with(MetadataBroadcastSystem::default(), "") - .build(); - - let entity = test::create(&mut w, position!(0.0, 0.0, 0.0)).build(); - - // Insert metadata - { - let mut metadatas = w.write_component::<Metadata>(); - metadatas - .insert(entity, Metadata::Entity(Entity::default())) - .unwrap(); - } - - let player = t::add_player(&mut w); - - d.dispatch(&w); - w.maintain(); - - // Ensure that packet was sent - let packet = t::assert_packet_received(&player, PacketType::EntityMetadata); - let packet = cast_packet::<PacketEntityMetadata>(&*packet); - - assert_eq!(packet.entity_id, entity.id() as i32); - } -} diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs deleted file mode 100644 index 9aa2ee75c..000000000 --- a/server/src/entity/mod.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Provides several useful components, including `EntityComponent` -//! and `PlayerComponent`. In the future, will also -//! provide entity-specific components and systems. - -mod broadcast; -mod chunk; -mod component; -mod destroy; -mod impls; -pub mod metadata; -mod movement; -mod save; - -pub use impls::*; - -use crate::systems::{ - BLOCK_FALLING_LANDING, CHUNK_CROSS, CHUNK_ENTITIES_LOAD, CHUNK_ENTITIES_UPDATE, CHUNK_SAVE, - ENTITY_DESTROY, ENTITY_DESTROY_BROADCAST, ENTITY_METADATA_BROADCAST, ENTITY_MOVE_BROADCAST, - ENTITY_PHYSICS, ENTITY_SPAWN_BROADCAST, ENTITY_VELOCITY_BROADCAST, ITEM_COLLECT, ITEM_MERGE, - ITEM_SPAWN, JOIN_BROADCAST, SHOOT_ARROW, -}; -pub use arrow::{ArrowComponent, ShootArrowEvent}; -pub use broadcast::send_entity_to_player; -pub use broadcast::{EntitySendEvent, EntitySpawnEvent}; -pub use chunk::ChunkEntities; -pub use chunk::ChunkEntityUpdateSystem; -pub use component::{ - NamedComponent, PacketCreatorComponent, PlayerComponent, PositionComponent, - SerializerComponent, VelocityComponent, -}; -pub use destroy::EntityDestroyEvent; -pub use falling_block::FallingBlockComponent; -pub use item::ItemComponent; -pub use metadata::{EntityBitMask, Metadata}; -pub use movement::{degrees_to_stops, LastKnownPositionComponent}; - -pub use save::save_chunks; - -use crate::entity::arrow::ShootArrowSystem; -use crate::entity::chunk::EntityChunkLoadSystem; -use crate::entity::destroy::EntityDestroyBroadcastSystem; -use crate::entity::falling_block::FallingBlockLandSystem; -use crate::entity::item::ItemCollectSystem; -use crate::entity::metadata::MetadataBroadcastSystem; -use crate::entity::save::ChunkSaveSystem; -use broadcast::EntityBroadcastSystem; -use component::ComponentResetSystem; -use destroy::EntityDestroySystem; -use item::{ItemMergeSystem, ItemSpawnSystem}; -use movement::{EntityMoveBroadcastSystem, EntityVelocityBroadcastSystem}; -use specs::DispatcherBuilder; - -pub fn init_logic(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(ItemCollectSystem::default(), ITEM_COLLECT, &[]); -} - -pub fn init_handlers(dispatcher: &mut DispatcherBuilder) { - dispatcher.add( - ChunkEntityUpdateSystem::default(), - CHUNK_ENTITIES_UPDATE, - &[], - ); - dispatcher.add(EntityChunkLoadSystem::default(), CHUNK_ENTITIES_LOAD, &[]); - dispatcher.add(EntityDestroySystem::default(), ENTITY_DESTROY, &[]); - dispatcher.add(ItemSpawnSystem::default(), ITEM_SPAWN, &[]); - dispatcher.add(ItemMergeSystem::default(), ITEM_MERGE, &[]); - dispatcher.add( - MetadataBroadcastSystem::default(), - ENTITY_METADATA_BROADCAST, - &[], - ); - dispatcher.add(ShootArrowSystem::default(), SHOOT_ARROW, &[]); - dispatcher.add(ChunkSaveSystem::default(), CHUNK_SAVE, &[]); -} - -pub fn init_broadcast(dispatcher: &mut DispatcherBuilder) { - dispatcher.add( - EntityMoveBroadcastSystem::default(), - ENTITY_MOVE_BROADCAST, - &[], - ); - dispatcher.add( - EntityBroadcastSystem::default(), - ENTITY_SPAWN_BROADCAST, - &[JOIN_BROADCAST, CHUNK_CROSS], - ); - dispatcher.add( - EntityVelocityBroadcastSystem::default(), - ENTITY_VELOCITY_BROADCAST, - &[], - ); - dispatcher.add( - EntityDestroyBroadcastSystem::default(), - ENTITY_DESTROY_BROADCAST, - &[], - ); - dispatcher.add( - FallingBlockLandSystem::default(), - BLOCK_FALLING_LANDING, - &[ENTITY_PHYSICS], - ); - dispatcher.add_thread_local(ComponentResetSystem); -} diff --git a/server/src/entity/movement.rs b/server/src/entity/movement.rs deleted file mode 100644 index 34a4d25b9..000000000 --- a/server/src/entity/movement.rs +++ /dev/null @@ -1,264 +0,0 @@ -use specs::storage::ComponentEvent; -use specs::{ - BitSet, Component, DenseVecStorage, Entities, Entity, Join, Read, ReadStorage, ReaderId, - System, WriteStorage, -}; - -use feather_core::network::packet::implementation::{ - EntityHeadLook, EntityLook, EntityLookAndRelativeMove, EntityRelativeMove, EntityVelocity, -}; -use feather_core::world::Position; - -use crate::chunk_logic::ChunkHolders; -use crate::entity::{PositionComponent, VelocityComponent}; -use crate::network::{send_packet_boxed_to_player, NetworkComponent}; -use crate::util::{protocol_velocity, Util}; -use feather_core::Packet; -use hashbrown::HashMap; -use smallvec::SmallVec; - -/// Component which stores the last known position for any given entity -/// for a player. -/// -/// This is used to ensure position remains synced across clients, since -/// relative movement packets are used. -#[derive(Default, Debug)] -pub struct LastKnownPositionComponent(pub HashMap<Entity, Position>); - -impl Component for LastKnownPositionComponent { - type Storage = DenseVecStorage<Self>; -} - -/// System for broadcasting when an entity moves. -#[derive(Default)] -pub struct EntityMoveBroadcastSystem { - dirty: BitSet, - reader: Option<ReaderId<ComponentEvent>>, - held: BitSet, -} - -impl<'a> System<'a> for EntityMoveBroadcastSystem { - type SystemData = ( - ReadStorage<'a, PositionComponent>, - WriteStorage<'a, LastKnownPositionComponent>, - ReadStorage<'a, NetworkComponent>, - Read<'a, ChunkHolders>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (positions, mut last_positions, networks, chunk_holders, entities) = data; - - self.dirty.clear(); - - for event in positions.channel().read(&mut self.reader.as_mut().unwrap()) { - match event { - ComponentEvent::Modified(index) | ComponentEvent::Inserted(index) => { - self.dirty.add(*index); - } - _ => (), - } - } - - for (position, entity, _) in (&positions, &entities, &self.dirty).join() { - // Populate `self.held` with chunk holders for this entity's chunk - for entity in chunk_holders - .holders_for(position.current.chunk_pos()) - .unwrap_or(&[]) - { - self.held.add(entity.id()); - } - - // For each player which can see this entity's chunk, send a movement update packet. - for (network, last_positions, _) in (&networks, &mut last_positions, &self.held).join() - { - let last_known_position = match last_positions.0.get(&entity) { - Some(pos) => pos, - None => continue, // Player hasn't yet known this entity - }; - - if let Some(packets) = - packet_for_movement_update(entity, *last_known_position, position.current) - { - packets - .into_iter() - .for_each(|packet| send_packet_boxed_to_player(network, packet)); - } - - last_positions.0.insert(entity, position.current); - } - - self.held.clear(); - } - } - - flagged_setup_impl!(PositionComponent, reader); -} - -/// Returns the packet needed to notify a client -/// of a position update, from the old position to the new one. -#[allow(clippy::float_cmp)] -pub fn packet_for_movement_update( - entity: Entity, - old_pos: Position, - new_pos: Position, -) -> Option<SmallVec<[Box<dyn Packet>; 2]>> { - if old_pos == new_pos { - return None; - } - - let mut packets = smallvec![]; - - let has_moved = old_pos.x != new_pos.x || old_pos.y != new_pos.y || old_pos.z != new_pos.z; - let has_looked = old_pos.pitch != new_pos.pitch || old_pos.yaw != new_pos.yaw; - - if has_moved { - let (rx, ry, rz) = calculate_relative_move(old_pos, new_pos); - - if (rx == 0 && ry == 0 && rz == 0) && !has_looked { - // Because of floating point errors, - // the physics system may trigger an - // event when the distance moved is minuscule, - // which causes jittering on the client. - // Don't send the packet if it has no effect. - return None; - } - - if has_looked { - let packet: Box<dyn Packet> = Box::new(EntityLookAndRelativeMove::new( - entity.id() as i32, - rx, - ry, - rz, - degrees_to_stops(new_pos.yaw), - degrees_to_stops(new_pos.pitch), - new_pos.on_ground, - )); - packets.push(packet); - } else { - let packet: Box<dyn Packet> = Box::new(EntityRelativeMove::new( - entity.id() as i32, - rx, - ry, - rz, - new_pos.on_ground, - )); - packets.push(packet); - } - } else { - let packet: Box<dyn Packet> = Box::new(EntityLook::new( - entity.id() as i32, - degrees_to_stops(new_pos.yaw), - degrees_to_stops(new_pos.pitch), - new_pos.on_ground, - )); - packets.push(packet); - } - - // Entity Head Look also needs to be sent if the entity turned its head - if has_looked { - let packet: Box<dyn Packet> = Box::new(EntityHeadLook::new( - entity.id() as i32, - degrees_to_stops(new_pos.yaw), - )); - packets.push(packet); - } - - Some(packets) -} - -/// System for broadcasting when an entity's velocity -/// is updated. -#[derive(Default)] -pub struct EntityVelocityBroadcastSystem { - dirty: BitSet, - reader: Option<ReaderId<ComponentEvent>>, -} - -impl<'a> System<'a> for EntityVelocityBroadcastSystem { - type SystemData = ( - ReadStorage<'a, VelocityComponent>, - Read<'a, Util>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (velocities, util, entities) = data; - - self.dirty.clear(); - - for event in velocities.channel().read(self.reader.as_mut().unwrap()) { - match event { - ComponentEvent::Modified(index) | ComponentEvent::Inserted(index) => { - self.dirty.add(*index); - } - _ => (), - } - } - - for (velocity, entity, _) in (&velocities, &entities, &self.dirty).join() { - let (velocity_x, velocity_y, velocity_z) = protocol_velocity(velocity.0); - let packet = EntityVelocity { - entity_id: entity.id() as i32, - velocity_x, - velocity_y, - velocity_z, - }; - - util.broadcast_entity_update(entity, packet, Some(entity)); - } - } - - flagged_setup_impl!(VelocityComponent, reader); -} - -/// Calculates the relative move fields -/// as used in the Entity Relative Move packets. -pub fn calculate_relative_move(old: Position, current: Position) -> (i16, i16, i16) { - let x = ((current.x * 32.0 - old.x * 32.0) * 128.0) as i16; - let y = ((current.y * 32.0 - old.y * 32.0) * 128.0) as i16; - let z = ((current.z * 32.0 - old.z * 32.0) * 128.0) as i16; - (x, y, z) -} - -pub fn degrees_to_stops(degs: f32) -> u8 { - ((degs / 360.0) * 256.0) as u8 -} - -#[cfg(test)] -mod tests { - use specs::{Builder, WorldExt}; - - use feather_core::network::cast_packet; - use feather_core::network::packet::PacketType; - - use crate::entity::test; - use crate::testframework as t; - - use super::*; - - #[test] - fn test_velocity_broadcast_system() { - let (mut w, mut d) = t::builder() - .with(EntityVelocityBroadcastSystem::default(), "") - .build(); - - let player = t::add_player(&mut w); - - let entity = test::create(&mut w, position!(0.0, 0.0, 0.0)).build(); - - w.write_component::<VelocityComponent>() - .insert(entity, VelocityComponent(glm::vec3(0.0, 0.0, 0.0))) - .unwrap(); - - d.dispatch(&w); - w.maintain(); - - let packet = t::assert_packet_received(&player, PacketType::EntityVelocity); - let packet = cast_packet::<EntityVelocity>(&*packet); - assert_eq!(packet.entity_id, entity.id() as i32); - assert_eq!(packet.velocity_x, 0); - assert_eq!(packet.velocity_y, 0); - assert_eq!(packet.velocity_z, 0); - } -} diff --git a/server/src/entity/save.rs b/server/src/entity/save.rs deleted file mode 100644 index c1d5cde5a..000000000 --- a/server/src/entity/save.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! Saving of entity data (and chunk data along with it). - -use crate::chunk_logic; -use crate::chunk_logic::{ChunkUnloadEvent, ChunkWorkerHandle}; -use crate::config::Config; -use crate::entity::{ChunkEntities, SerializerComponent}; -use feather_core::world::ChunkMap; -use rayon::prelude::*; -use shrev::{EventChannel, ReaderId}; -use specs::{Entity, LazyUpdate, Read, ReadExpect, System, WorldExt, Write}; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; -use std::time::Instant; - -/// System to save chunk and entity data upon a chunk unload -/// and periodically. -/// -/// This system listens to `ChunkUnloadEvent`s. -#[derive(Default)] -pub struct ChunkSaveSystem { - reader: Option<ReaderId<ChunkUnloadEvent>>, -} - -/// Previous time at which chunks were saved. -pub struct PreviousSaveTime(Instant); - -impl Default for PreviousSaveTime { - fn default() -> Self { - Self(Instant::now()) - } -} - -impl<'a> System<'a> for ChunkSaveSystem { - type SystemData = ( - Write<'a, PreviousSaveTime>, - Write<'a, ChunkMap>, - Read<'a, ChunkEntities>, - Read<'a, EventChannel<ChunkUnloadEvent>>, - Read<'a, Arc<Config>>, - Read<'a, LazyUpdate>, - ReadExpect<'a, ChunkWorkerHandle>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - mut prev_save_time, - mut chunk_map, - chunk_entities, - unload_events, - config, - lazy, - worker_handle, - ) = data; - - for event in unload_events.read(self.reader.as_mut().unwrap()) { - let entities = vec![]; // TODO - chunk_logic::save_chunk(&worker_handle, Arc::clone(&event.chunk), entities); - } - - if prev_save_time.0.elapsed() >= config.world.save_interval { - // Save chunks - save_chunks(&mut chunk_map, &chunk_entities, &lazy); - prev_save_time.0 = Instant::now(); - } - } - - setup_impl!(reader); -} - -/// Saves all modified chunks. -/// -/// The saves themselves are performed lazily and asynchronously. -/// -/// Returns the number of chunks queued for saving. -pub fn save_chunks( - chunk_map: &mut ChunkMap, - chunk_entities: &ChunkEntities, - lazy: &LazyUpdate, -) -> u32 { - let count = AtomicUsize::new(0); - chunk_map - .chunks_mut() - .par_iter_mut() - .map(|(_, chunk)| { - let (dirty, entities) = chunk_entities.entities_in_chunk_and_modified(chunk.position()); - (chunk, entities, dirty) - }) - .for_each(|(chunk, entities, dirty)| { - // If all of the following are true, don't save the chunk: - // * The chunk has not been modified since the last save. - // * The entities in the chunk are empty (if they weren't, it is likely they were modified) - // * The entities in the chunk haven't changed. - if !chunk.check_modified() && (entities.is_empty() && !dirty) { - return; - } - - // World access is required for entity serialization, - // so we perform the saving itself asynchronously. - let chunk = Arc::new(chunk.clone()); - let entities: Vec<Entity> = entities.to_vec(); - lazy.exec(move |world| { - // Compute entity data. - let entity_data = entities - .into_iter() - .filter_map(|entity| { - let serializers = world.read_component::<SerializerComponent>(); - let serializer = match serializers.get(entity) { - Some(serializer) => serializer, - None => return None, // Entity not serialized - }; - - let serialize = serializer.0; - Some(serialize(world, entity)) - }) - .collect(); - - let handle = world.fetch::<ChunkWorkerHandle>(); - chunk_logic::save_chunk(&handle, chunk, entity_data); - }); - - count.fetch_add(1, Ordering::Release); - }); - - let count = count.load(Ordering::Acquire); - debug!("Saving {} chunks", count); - count as u32 -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{chunkworker, testframework as t}; - use failure::_core::time::Duration; - use feather_core::{Chunk, ChunkPosition}; - - #[test] - fn test_chunk_unload() { - let (mut world, mut dispatcher) = t::builder().with(ChunkSaveSystem::default(), "").build(); - - let (tx, rx) = crossbeam::unbounded(); - let (_tx2, rx2) = crossbeam::unbounded(); - world.insert(ChunkWorkerHandle { - sender: tx, - receiver: rx2, - }); - - let event = ChunkUnloadEvent { - chunk: Arc::new(Chunk::default()), - }; - - t::trigger_event(&world, event); - - dispatcher.dispatch(&world); - - let msg = rx.try_recv().unwrap(); - - match msg { - chunkworker::Request::SaveChunk(chunk, entities) => { - assert_eq!(chunk.position(), ChunkPosition::new(0, 0)); - assert!(entities.is_empty()); // TODO - } - _ => panic!(), - } - } - - #[test] - fn test_periodic() { - let (mut world, mut dispatcher) = t::builder().with(ChunkSaveSystem::default(), "").build(); - - let (tx, rx) = crossbeam::unbounded(); - let (_tx2, rx2) = crossbeam::unbounded(); - world.insert(ChunkWorkerHandle { - sender: tx, - receiver: rx2, - }); - - let last_save_time = PreviousSaveTime(Instant::now() - Duration::from_secs(120)); - world.insert(last_save_time); - - let pos = ChunkPosition::new(0, 0); - world - .fetch_mut::<ChunkMap>() - .set_chunk_at(pos, Chunk::new(pos)); - - dispatcher.dispatch(&world); - world.maintain(); - - let msg = rx.try_recv().unwrap(); - - match msg { - chunkworker::Request::SaveChunk(chunk, entities) => { - assert_eq!(chunk.position(), pos); - assert!(entities.is_empty()); // TODO - } - _ => panic!(), - } - } -} diff --git a/server/src/io/initialhandler.rs b/server/src/io/initialhandler.rs deleted file mode 100644 index 6c44f689d..000000000 --- a/server/src/io/initialhandler.rs +++ /dev/null @@ -1,642 +0,0 @@ -//! The initial handler is responsible for -//! handling new connections and getting -//! through the login sequence. After login -//! is completed, control is handed over to the server -//! thread, which is responsible for sending chunks/inventory/ -//! players and then spawning the player. -//! -//! The initial handler is also responsible for handling -//! server list pings. To do this, it shares an `Arc<AtomicInteger>` -//! representing the player count with the server. -//! -//! The initial handler runs on the IO worker thread. -//! This is done to ensure minimal latency in packet handling, -//! speeding up the login process and making the latency calculation in -//! the server list ping as low as possible. - -use std::sync::atomic::Ordering; -use std::sync::Arc; - -use rand_legacy::rngs::OsRng; -use rsa::{PaddingScheme, PublicKey, RSAPrivateKey}; -use rsa_der as der; -use uuid::Uuid; - -use feather_core::network::cast_packet; -use feather_core::network::packet::implementation::{ - DisconnectLogin, EncryptionRequest, EncryptionResponse, Handshake, HandshakeState, LoginStart, - LoginSuccess, Ping, Pong, Request, Response, SetCompression, -}; -use feather_core::network::packet::{Packet, PacketStage, PacketType}; - -use crate::config::Config; -use crate::{PlayerCount, PROTOCOL_VERSION, SERVER_VERSION}; - -/// The key used for symmetric encryption. -pub type Key = [u8; 16]; -/// The verify token used to ensure that encryption -/// is working correctly. -type VerifyToken = [u8; 4]; - -/// The number of bits used for the RSA key. -const RSA_KEY_BITS: usize = 1024; -/// The number of bytes in the shared secret -const SHARED_SECRET_LEN: usize = 128 / 8; - -lazy_static! { - pub static ref RSA_KEY: RSAPrivateKey = { - let mut rng = OsRng::new().unwrap(); - RSAPrivateKey::new(&mut rng, RSA_KEY_BITS).unwrap() - }; -} - -/// An action for the worker thread to execute -/// after `InitialHandler::handle_packet` is called. -pub enum Action { - EnableCompression(i32), - EnableEncryption(Key), - SendPacket(Box<dyn Packet>), - Disconnect, - SetStage(PacketStage), - JoinGame(JoinResult), -} - -/// The type returned for when a player has completed the login process. -#[derive(Clone, Debug)] -pub struct JoinResult { - pub username: String, - pub uuid: Uuid, - pub props: Vec<mojang_api::ProfileProperty>, -} - -/// An initial handler for a connection. -/// -/// When a packet is received from the client this initial -/// handler is registered with, `handle_packet` should be called. -/// This function runs all the necessary code to handle the -/// login sequence or the server list ping. -/// -/// The initial handler is able to communicate with the worker -/// implementation by exposing the `actions_to_execute` method, -/// which returns a vector of actions for the worker to execute. -/// These may include, for example, enabling encryption or sending -/// a packet. -pub struct InitialHandler { - /// A queue of actions to perform. When `actions_to_execute` - /// is called, the queue is flushed. - action_queue: Vec<Action>, - - /// If set to a value, indicates that encryption - /// should be enabled with the given key. - key: Option<Key>, - /// If set to a value, indicates that compression - /// should be enabled with the given threshold. - compression_threshold: Option<i32>, - - /// The verify token generated for this exchange. - verify_token: VerifyToken, - - /// The server's configuration. - config: Arc<Config>, - /// The server's player count. - player_count: Arc<PlayerCount>, - /// The server's icon, if any was loaded. - server_icon: Arc<Option<String>>, - - /// The username of the player, sent - /// in Login Start. - username: Option<String>, - - /// The player info, set to `Some` once - /// the initial handler is finished and - /// the player should join. - info: Option<JoinResult>, - - /// The stage of this initial handler. - stage: Stage, -} - -impl InitialHandler { - pub fn new( - config: Arc<Config>, - player_count: Arc<PlayerCount>, - server_icon: Arc<Option<String>>, - ) -> Self { - Self { - action_queue: vec![], - - key: None, - compression_threshold: None, - - verify_token: rand::random(), - - config, - player_count, - server_icon, - - username: None, - - info: None, - - stage: Stage::AwaitHandshake, - } - } - - /// Notifies this initial handler of a packet - /// received from the client. After calling this - /// function, `action_queue` should be called - /// and the actions should be executed in order. - pub async fn handle_packet(&mut self, packet: Box<dyn Packet>) { - if self.stage == Stage::Finished { - panic!("Called InitialHandler::handle_packet() after completion"); - } - - if let Err(e) = _handle_packet(self, packet).await { - // Disconnect - disconnect_login(self, &format!("{}", e)); - info!( - "Player {} disconnected: {}", - self.username.as_ref().unwrap_or(&"unknown".to_string()), - e - ); - } - } - - /// Returns a vector of actions to perform. - pub fn actions_to_execute(&mut self) -> Vec<Action> { - let mut new_vec = vec![]; - std::mem::swap(&mut new_vec, &mut self.action_queue); - - new_vec - } -} - -/// Handles a packet, returning `Err` if the player -/// should be disconnected. -async fn _handle_packet(ih: &mut InitialHandler, packet: Box<dyn Packet>) -> Result<(), Error> { - // Find packet type and forward to correct function - match packet.ty() { - PacketType::Handshake => handle_handshake(ih, cast_packet::<Handshake>(&*packet))?, - PacketType::Request => handle_request(ih, cast_packet::<Request>(&*packet))?, - PacketType::Ping => handle_ping(ih, cast_packet::<Ping>(&*packet))?, - PacketType::LoginStart => handle_login_start(ih, cast_packet::<LoginStart>(&*packet))?, - PacketType::EncryptionResponse => { - handle_encryption_response(ih, cast_packet::<EncryptionResponse>(&*packet)).await? - } - ty => return Err(Error::InvalidPacket(ty, ih.stage)), - } - - Ok(()) -} - -fn handle_handshake(ih: &mut InitialHandler, packet: &Handshake) -> Result<(), Error> { - check_stage(ih, Stage::AwaitHandshake, packet.ty())?; - - ih.stage = match packet.next_state { - HandshakeState::Status => { - ih.action_queue.push(Action::SetStage(PacketStage::Status)); - Stage::AwaitRequest - } - HandshakeState::Login => { - // While status requests can use differing - // protocol versions, a client - // needs to have a matching protocol version - // to log in. - if packet.protocol_version != PROTOCOL_VERSION { - return Err(Error::InvalidProtocol(packet.protocol_version)); - } - - ih.action_queue.push(Action::SetStage(PacketStage::Login)); - Stage::AwaitLoginStart - } - }; - - Ok(()) -} - -fn handle_request(ih: &mut InitialHandler, packet: &Request) -> Result<(), Error> { - check_stage(ih, Stage::AwaitRequest, packet.ty())?; - let server_icon = (*ih.server_icon).clone().unwrap_or_default(); - - // Send response packet - let json = json!({ - "version": { - "name": SERVER_VERSION, - "protocol": PROTOCOL_VERSION, - }, - "players": { - "max": ih.config.server.max_players, - "online": ih.player_count.0.load(Ordering::SeqCst), - }, - "description": { - "text": ih.config.server.motd, - }, - "favicon": server_icon, - }); - - let response = Response::new(json.to_string()); - send_packet(ih, response); - - ih.stage = Stage::AwaitPing; - - Ok(()) -} - -fn handle_ping(ih: &mut InitialHandler, packet: &Ping) -> Result<(), Error> { - check_stage(ih, Stage::AwaitPing, packet.ty())?; - - let pong = Pong::new(packet.payload); - send_packet(ih, pong); - - // After sending pong, we should disconnect. - ih.action_queue.push(Action::Disconnect); - ih.stage = Stage::Finished; - - Ok(()) -} - -fn handle_login_start(ih: &mut InitialHandler, packet: &LoginStart) -> Result<(), Error> { - check_stage(ih, Stage::AwaitLoginStart, packet.ty())?; - - ih.username = Some(packet.username.clone()); - - // If in online mode, encryption needs to be enabled, - // and authentication needs to be performed. - // If not in online mode, the login sequence is - // already finished, so we can call `finish` after - // setting the player's info. - if ih.config.server.online_mode { - use num_bigint::{BigInt, Sign::Plus}; - // Start enabling encryption - let der = der::public_key_to_der( - &BigInt::from_biguint(Plus, RSA_KEY.n().clone()).to_signed_bytes_be(), - &BigInt::from_biguint(Plus, RSA_KEY.e().clone()).to_signed_bytes_be(), - ); - - let encryption_request = EncryptionRequest::new( - "".to_string(), // Server ID - always empty - der, - ih.verify_token.to_vec(), - ); - send_packet(ih, encryption_request); - - ih.stage = Stage::AwaitEncryptionResponse; - } else { - // Finished - set info and join - ih.info = Some(JoinResult { - username: ih.username.clone().unwrap(), - uuid: Uuid::new_v4(), - props: vec![], - }); - finish(ih); - } - - Ok(()) -} - -async fn handle_encryption_response( - ih: &mut InitialHandler, - packet: &EncryptionResponse, -) -> Result<(), Error> { - check_stage(ih, Stage::AwaitEncryptionResponse, packet.ty())?; - - // Decrypt verify token + shared secret - let shared_secret = decrypt_using_rsa(&packet.secret, &RSA_KEY)?; - if shared_secret.len() != SHARED_SECRET_LEN { - return Err(Error::BadSecretLength); - } - - let verify_token = decrypt_using_rsa(&packet.verify_token, &RSA_KEY)?; - if verify_token.len() != ih.verify_token.len() { - return Err(Error::VerifyTokenMismatch); - } - - // Check that verify token matches - if verify_token.as_slice() != ih.verify_token { - return Err(Error::VerifyTokenMismatch); - } - - // Enable encryption - let mut key = [0u8; SHARED_SECRET_LEN]; - for (i, x) in shared_secret[..SHARED_SECRET_LEN].iter().enumerate() { - key[i] = *x; - } - - ih.key = Some(key); - ih.action_queue - .push(Action::EnableEncryption(ih.key.unwrap())); - - use num_bigint::{BigInt, Sign::Plus}; - let der = der::public_key_to_der( - &BigInt::from_biguint(Plus, RSA_KEY.n().clone()).to_signed_bytes_be(), - &BigInt::from_biguint(Plus, RSA_KEY.e().clone()).to_signed_bytes_be(), - ); - - // Perform authentication - let auth_result = mojang_api::server_auth( - &mojang_api::server_hash("", ih.key.unwrap(), der.as_slice()), - ih.username.as_ref().unwrap(), - ) - .await; - - match auth_result { - Ok(auth) => { - let info = JoinResult { - username: auth.name, - uuid: auth.id, - props: auth.properties, - }; - ih.info = Some(info); - } - Err(e) => return Err(Error::AuthenticationFailed(e)), - } - - finish(ih); - - Ok(()) -} - -fn decrypt_using_rsa(data: &[u8], key: &RSAPrivateKey) -> Result<Vec<u8>, Error> { - let buf = key - .decrypt(PaddingScheme::PKCS1v15, data) - .map_err(|_| Error::BadEncryption)?; - - Ok(buf) -} - -/// Terminates the login process, sending Set Compression (if necessary) -/// and Login Success. -/// -/// Before calling this function, it is expected that: -/// * `info` is set to a valid value -/// * Encryption has been enabled, if necessary -/// * All other login processes have already run -fn finish(ih: &mut InitialHandler) { - assert!(ih.info.is_some()); - - // Enable compression if necessary - let compression_threshold = ih.config.io.compression_threshold; - if compression_threshold > 0 { - enable_compression(ih, compression_threshold); - } - - let info = ih.info.as_ref().unwrap(); - - // Send Login Success - let login_success = LoginSuccess::new( - info.uuid.to_hyphenated_ref().to_string(), - info.username.clone(), - ); - send_packet(ih, login_success); - ih.action_queue.push(Action::SetStage(PacketStage::Play)); - ih.action_queue - .push(Action::JoinGame(ih.info.clone().unwrap())); -} - -/// Enables compression, sending the Set Compression -/// packet. -fn enable_compression(ih: &mut InitialHandler, threshold: i32) { - ih.compression_threshold = Some(threshold); - send_packet(ih, SetCompression::new(threshold)); - ih.action_queue.push(Action::EnableCompression(threshold)); -} - -/// Checks that the initial handler stage matches -/// the expected stage, returning `Err` with a proper -/// error message if not. -fn check_stage(ih: &InitialHandler, expected: Stage, packet_ty: PacketType) -> Result<(), Error> { - if ih.stage != expected { - Err(Error::InvalidPacket(packet_ty, ih.stage)) - } else { - Ok(()) - } -} - -/// Disconnects the initial handler, sending -/// a disconnect packet containing the reason. -fn disconnect_login(ih: &mut InitialHandler, reason: &str) { - let json = json!({ - "text": reason, - }) - .to_string(); - - let packet = DisconnectLogin::new(json); - send_packet(ih, packet); - - ih.action_queue.push(Action::Disconnect); -} - -/// Adds a packet to the internal packet queue. -fn send_packet<P: Packet + 'static>(ih: &mut InitialHandler, packet: P) { - ih.action_queue.push(Action::SendPacket(Box::new(packet))); -} - -#[derive(Fail, Debug)] -enum Error { - #[fail(display = "invalid packet type {:?} sent at stage {:?}", _0, _1)] - InvalidPacket(PacketType, Stage), - #[fail(display = "unsupported protocol version {:?}", _0)] - InvalidProtocol(u32), - #[fail(display = "invalid encryption")] - BadEncryption, - #[fail(display = "verify tokens do not match")] - VerifyTokenMismatch, - #[fail(display = "shared secret length is not correct")] - BadSecretLength, - #[fail(display = "authentication failure: {:?}", _0)] - AuthenticationFailed(mojang_api::Error), -} - -/// The stage of an initial handler. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Stage { - AwaitHandshake, - AwaitRequest, - AwaitPing, - AwaitLoginStart, - AwaitEncryptionResponse, - Finished, -} - -#[cfg(test)] -mod tests { - use std::sync::atomic::AtomicUsize; - - use feather_core::network::cast_packet; - use feather_core::network::packet::implementation::{ - Handshake, HandshakeState, LoginSuccess, Ping, Pong, Request, Response, SetCompression, - }; - use feather_core::network::packet::PacketType; - - use crate::PROTOCOL_VERSION; - - use super::*; - - #[test] - fn test_initial_handler_new() { - let mut ih = ih(); - - assert!(ih.actions_to_execute().is_empty()); - } - - #[tokio::test] - async fn test_status_ping() { - let player_count = 24; - let mut ih = ih_with_player_count(player_count); - - let handshake = Handshake::new( - PROTOCOL_VERSION, - "".to_string(), // Unused - server address - 25565, - HandshakeState::Status, - ); - ih.handle_packet(Box::new(handshake)).await; - - // Confirm that stage was switched and no other actions were performed - let actions = ih.actions_to_execute(); - assert_eq!(actions.len(), 1); - match actions.first().unwrap() { - Action::SetStage(stage) => assert_eq!(*stage, PacketStage::Status), - _ => panic!(), - } - - let request = Request::new(); - ih.handle_packet(Box::new(request)).await; - - let actions = ih.actions_to_execute(); - - // Confirm that correct response was received - assert_eq!(actions.len(), 1); - - let _response = actions.first().unwrap(); - match _response { - Action::SendPacket(_response) => { - assert_eq!(_response.ty(), PacketType::Response); - - let response = cast_packet::<Response>(&**_response); - let _: serde_json::Value = serde_json::from_str(&response.json_response).unwrap(); - } - _ => panic!(), - } - - // Send ping - let payload = 39842; - let ping = Ping::new(payload); - ih.handle_packet(Box::new(ping)).await; - - let mut actions = ih.actions_to_execute(); - - assert_eq!(actions.len(), 2); - let _pong = actions.remove(0); - match _pong { - Action::SendPacket(_pong) => { - assert_eq!(_pong.ty(), PacketType::Pong); - let pong = cast_packet::<Pong>(&*_pong); - assert_eq!(pong.payload, payload); - } - _ => panic!(), - } - - let disconnect = actions.remove(0); - match disconnect { - Action::Disconnect => (), - _ => panic!(), - } - } - - #[tokio::test] - async fn test_login_sequence() { - let mut config = Config::default(); - config.server.online_mode = false; - let mut ih = ih_with_config(config.clone()); - - let handshake = Handshake::new( - PROTOCOL_VERSION, - "".to_string(), // Unused - server address - 25565, - HandshakeState::Login, - ); - ih.handle_packet(Box::new(handshake)).await; - - let actions = ih.actions_to_execute(); - assert_eq!(actions.len(), 1); - match actions.first().unwrap() { - Action::SetStage(stage) => assert_eq!(*stage, PacketStage::Login), - _ => panic!(), - } - - let username = "test"; - let login_start = LoginStart::new(username.to_string()); - ih.handle_packet(Box::new(login_start)).await; - - let mut actions = ih.actions_to_execute(); - assert_eq!(actions.len(), 5); - - let _set_compression = actions.remove(0); - - match _set_compression { - Action::SendPacket(_set_compression) => { - assert_eq!(_set_compression.ty(), PacketType::SetCompression); - - let set_compression = cast_packet::<SetCompression>(&*_set_compression); - assert_eq!(set_compression.threshold, config.io.compression_threshold); - } - _ => panic!(), - } - - let enable_compression = actions.remove(0); - match enable_compression { - Action::EnableCompression(threshold) => { - assert_eq!(threshold, config.io.compression_threshold); - } - _ => panic!(), - } - - let _login_success = actions.remove(0); - - match _login_success { - Action::SendPacket(_login_success) => { - assert_eq!(_login_success.ty(), PacketType::LoginSuccess); - - let login_success = cast_packet::<LoginSuccess>(&*_login_success); - assert_eq!(login_success.username, username.to_string()); - } - _ => panic!(), - } - - match actions.remove(0) { - Action::SetStage(stage) => assert_eq!(stage, PacketStage::Play), - _ => panic!(), - } - - let join = actions.remove(0); - match join { - Action::JoinGame(_) => (), - _ => panic!(), - } - } - - fn ih() -> InitialHandler { - InitialHandler::new( - Arc::new(Config::default()), - Arc::new(PlayerCount(AtomicUsize::new(0))), - Arc::new(Some(String::from("test"))), - ) - } - - fn ih_with_player_count(count: usize) -> InitialHandler { - InitialHandler::new( - Arc::new(Config::default()), - Arc::new(PlayerCount(AtomicUsize::new(count))), - Arc::new(Some(String::from("test"))), - ) - } - - fn ih_with_config(config: Config) -> InitialHandler { - InitialHandler::new( - Arc::new(config), - Arc::new(PlayerCount(AtomicUsize::new(0))), - Arc::new(Some(String::from("test"))), - ) - } -} diff --git a/server/src/io/listener.rs b/server/src/io/listener.rs deleted file mode 100644 index 0090c1052..000000000 --- a/server/src/io/listener.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Listener Tokio task. -//! -//! This task listens on a `TcpListener` and accepts -//! connections, spawning worker tasks to handle them,4. - -use crate::config::Config; -use crate::io::worker::run_worker; -use crate::io::ListenerToServerMessage; -use crate::PlayerCount; -use std::net::SocketAddr; -use std::sync::Arc; -use tokio::io; -use tokio::net::TcpListener; - -pub async fn run_listener( - address: SocketAddr, - sender: crossbeam::Sender<ListenerToServerMessage>, - config: Arc<Config>, - player_count: Arc<PlayerCount>, - server_icon: Arc<Option<String>>, -) -> Result<(), io::Error> { - let mut listener = TcpListener::bind(address).await?; - - loop { - let (stream, ip) = match listener.accept().await { - Ok(res) => res, - Err(e) => { - debug!("Failed to accept connection: {:?}", e); - continue; - } - }; - - debug!("Connection received from {}", ip); - - tokio::spawn(run_worker( - stream, - ip, - sender.clone(), - Arc::clone(&config), - Arc::clone(&player_count), - Arc::clone(&server_icon), - )); - } -} diff --git a/server/src/io/mod.rs b/server/src/io/mod.rs deleted file mode 100644 index 106f04480..000000000 --- a/server/src/io/mod.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::config::Config; -use crate::PlayerCount; -use feather_core::network::packet::Packet; -use std::net::SocketAddr; -use std::sync::Arc; -use uuid::Uuid; - -mod initialhandler; -mod listener; -mod worker; - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub struct Client(usize); - -pub enum ServerToWorkerMessage { - SendPacket(Box<dyn Packet>), - NotifyPacketReceived(Box<dyn Packet>), - NotifyDisconnect(String), - Disconnect, -} - -pub enum ListenerToServerMessage { - NewClient(NewClientInfo), -} - -pub struct NewClientInfo { - pub ip: SocketAddr, - pub username: String, - pub profile: Vec<mojang_api::ProfileProperty>, - pub uuid: Uuid, - - pub sender: futures::channel::mpsc::UnboundedSender<ServerToWorkerMessage>, - pub receiver: crossbeam::Receiver<ServerToWorkerMessage>, -} - -pub struct NetworkIoManager { - pub receiver: crossbeam::Receiver<ListenerToServerMessage>, - /// Used for testing - pub listener_sender: crossbeam::Sender<ListenerToServerMessage>, -} - -impl NetworkIoManager { - /// Starts a new IO listener. - pub fn start( - addr: SocketAddr, - config: Arc<Config>, - player_count: Arc<PlayerCount>, - server_icon: Arc<Option<String>>, - ) -> Self { - info!("Starting IO listener on {}", addr,); - - let (sender, receiver) = crossbeam::unbounded(); - - let future = run_listener(addr, sender.clone(), config, player_count, server_icon); - - if cfg!(test) { - let mut rt = tokio::runtime::current_thread::Runtime::new().unwrap(); - rt.spawn(future); - } else { - tokio::spawn(future); - } - - Self { - receiver, - listener_sender: sender, - } - } -} - -impl Default for NetworkIoManager { - fn default() -> Self { - panic!("Don't try this"); - } -} - -/// Initializes certain static variables. -pub fn init() { - lazy_static::initialize(&initialhandler::RSA_KEY); -} - -async fn run_listener( - addr: SocketAddr, - sender: crossbeam::Sender<ListenerToServerMessage>, - config: Arc<Config>, - player_count: Arc<PlayerCount>, - server_icon: Arc<Option<String>>, -) { - if let Err(e) = listener::run_listener(addr, sender, config, player_count, server_icon).await { - error!("An error occurred while binding to socket: {:?}", e); - std::process::exit(1); - } -} diff --git a/server/src/io/worker.rs b/server/src/io/worker.rs deleted file mode 100644 index a312f6b39..000000000 --- a/server/src/io/worker.rs +++ /dev/null @@ -1,146 +0,0 @@ -//! Worker Tokio task. -//! -//! This is responsible for handling connections by -//! both sending and receiving packets. -//! -//! Packet send requests are sent over a channel from the server threads -//! to the worker for any given client. - -use crate::config::Config; -use crate::io::initialhandler::{Action, InitialHandler}; -use crate::io::{ListenerToServerMessage, NewClientInfo, ServerToWorkerMessage}; -use crate::PlayerCount; -use feather_core::network::codec::MinecraftCodec; -use feather_core::network::packet::PacketDirection; -use futures::{select, StreamExt}; -use futures::{FutureExt, SinkExt}; -use std::net::SocketAddr; -use std::sync::Arc; -use std::time::Duration; -use tokio::codec::Framed; -use tokio::net::TcpStream; -use tokio::timer::Timeout; - -/// Runs a worker task for the given client. -pub async fn run_worker( - stream: TcpStream, - ip: SocketAddr, - global_sender: crossbeam::Sender<ListenerToServerMessage>, - config: Arc<Config>, - player_count: Arc<PlayerCount>, - server_icon: Arc<Option<String>>, -) { - let (tx_worker_to_server, rx_worker_to_server) = crossbeam::unbounded(); - - let msg = match _run_worker( - stream, - ip, - global_sender, - config, - player_count, - server_icon, - tx_worker_to_server.clone(), - rx_worker_to_server.clone(), - ) - .await - { - Ok(()) => "normal disconnect".to_string(), - Err(e) => format!("{}", e), - }; - - let _ = tx_worker_to_server.send(ServerToWorkerMessage::NotifyDisconnect(msg)); -} - -#[allow(clippy::too_many_arguments)] -async fn _run_worker( - stream: TcpStream, - ip: SocketAddr, - global_sender: crossbeam::Sender<ListenerToServerMessage>, - config: Arc<Config>, - player_count: Arc<PlayerCount>, - server_icon: Arc<Option<String>>, - tx_worker_to_server: crossbeam::Sender<ServerToWorkerMessage>, - rx_worker_to_server: crossbeam::Receiver<ServerToWorkerMessage>, -) -> Result<(), failure::Error> { - let codec = MinecraftCodec::new(PacketDirection::Serverbound); - - let mut framed = Framed::new(stream, codec); - - let mut initial_handler = Some(InitialHandler::new(config, player_count, server_icon)); - - let (tx_server_to_worker, mut rx_server_to_worker) = futures::channel::mpsc::unbounded(); - let mut rx_worker_to_server = Some(rx_worker_to_server); - - loop { - let mut server_message = None; - let mut received_packet = None; - - select! { - msg = rx_server_to_worker.next().fuse() => server_message = Some(msg), - packet = Timeout::new(framed.next(), Duration::from_millis(10000)).fuse() => received_packet = Some(packet), - } - - if let Some(msg) = server_message { - if let Some(msg) = msg { - match msg { - ServerToWorkerMessage::SendPacket(packet) => framed.send(packet).await?, - ServerToWorkerMessage::Disconnect => return Ok(()), - _ => unreachable!(), - } - } - } - - if let Some(packet_result) = received_packet { - if let Some(packet_result) = packet_result? { - match packet_result { - Ok(packet) => { - if let Some(ih) = initial_handler.as_mut() { - ih.handle_packet(packet).await; - let actions = ih.actions_to_execute(); - - for action in actions { - match action { - Action::Disconnect => return Ok(()), - Action::SendPacket(packet) => framed.send(packet).await?, - Action::EnableCompression(threshold) => { - if threshold > 0 { - trace!( - "Enabling compression with threshold {}", - threshold - ); - framed - .codec_mut() - .enable_compression(threshold as usize); - } - } - Action::EnableEncryption(key) => { - trace!("Enabling encryption"); - framed.codec_mut().enable_encryption(key) - } - Action::SetStage(stage) => framed.codec_mut().set_stage(stage), - Action::JoinGame(res) => { - let info = NewClientInfo { - ip, - username: res.username, - profile: res.props, - uuid: res.uuid, - sender: tx_server_to_worker.clone(), - receiver: rx_worker_to_server.take().unwrap(), - }; - global_sender - .send(ListenerToServerMessage::NewClient(info))?; - initial_handler = None; - } - } - } - } else { - let _ = tx_worker_to_server - .send(ServerToWorkerMessage::NotifyPacketReceived(packet)); - } - } - Err(e) => return Err(e), - } - } - } - } -} diff --git a/server/src/joinhandler.rs b/server/src/joinhandler.rs deleted file mode 100644 index ad38803cb..000000000 --- a/server/src/joinhandler.rs +++ /dev/null @@ -1,237 +0,0 @@ -//! The join handler, in contrast to the initial handler, -//! takes over after the login sequence has completed. -//! It's responsible for asyncrhonously loading the player's -//! data (inventory, chunks, etc.) and then sending the necessary -//! packets to join the player. After completion, the component is -//! removed. - -use std::sync::atomic::Ordering; -use std::sync::Arc; - -use shrev::EventChannel; -use specs::{ - Component, Entities, Entity, HashMapStorage, Join, LazyUpdate, Read, ReadExpect, ReadStorage, - System, Write, WriteStorage, -}; - -use feather_core::level::LevelData; -use feather_core::network::packet::implementation::{ - JoinGame, PlayerPositionAndLookClientbound, SpawnPosition, -}; -use feather_core::world::{BlockPosition, ChunkMap, ChunkPosition}; -use feather_core::{Difficulty, Dimension}; - -use crate::chunk_logic::{ChunkHolderComponent, ChunkHolders, ChunkWorkerHandle}; -use crate::config::Config; -use crate::entity::{EntitySpawnEvent, PlayerComponent, PositionComponent}; -use crate::network::NetworkComponent; -use crate::player::{ChunkPendingComponent, InventoryUpdateEvent, LoadedChunksComponent}; -use crate::PlayerCount; - -#[derive(Default)] -pub struct JoinHandlerComponent { - stage: Stage, -} - -impl JoinHandlerComponent { - pub fn new() -> Self { - Self { - stage: Stage::Initial, - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum Stage { - Initial, - AwaitChunkSends, -} - -impl Default for Stage { - fn default() -> Self { - Stage::Initial - } -} - -impl Component for JoinHandlerComponent { - type Storage = HashMapStorage<Self>; -} - -/// Event which is triggered when a player -/// completes the join process (i.e. when -/// all chunks have been sent). -pub struct PlayerJoinEvent { - pub player: Entity, -} - -/// System for join handling. -pub struct JoinHandlerSystem; - -impl<'a> System<'a> for JoinHandlerSystem { - type SystemData = ( - WriteStorage<'a, JoinHandlerComponent>, - ReadStorage<'a, NetworkComponent>, - ReadStorage<'a, ChunkPendingComponent>, - Write<'a, EventChannel<PlayerJoinEvent>>, - Write<'a, EventChannel<EntitySpawnEvent>>, - Write<'a, EventChannel<InventoryUpdateEvent>>, - ReadExpect<'a, ChunkWorkerHandle>, - Entities<'a>, - Read<'a, LazyUpdate>, - Read<'a, Arc<Config>>, - Read<'a, Arc<PlayerCount>>, - Read<'a, ChunkMap>, - Write<'a, ChunkHolders>, - Read<'a, LevelData>, - WriteStorage<'a, ChunkHolderComponent>, - WriteStorage<'a, LoadedChunksComponent>, - ReadStorage<'a, PlayerComponent>, - ReadStorage<'a, PositionComponent>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - mut joincomps, - netcomps, - pending_chunks, - mut join_events, - mut spawn_events, - mut inv_events, - worker_handle, - entities, - lazy, - config, - player_count, - chunk_map, - mut holders, - level, - mut holder_comps, - mut loaded_chunks_comps, - playercomps, - positions, - ) = data; - - let mut to_remove = vec![]; - - for (player, net, join_handler, pending_chunks) in - (&entities, &netcomps, &mut joincomps, &pending_chunks).join() - { - match join_handler.stage { - Stage::Initial => { - let playercomp = playercomps.get(player).unwrap(); - - let level_type = &level.generator_name; - - // Send Join Game, then queue chunks for loading + sending. - let join_game = JoinGame::new( - player.id() as i32, - playercomp.gamemode.get_id(), - Dimension::Overwold.get_id(), - Difficulty::Medium.get_id(), - 0, // Max players - not used - level_type.to_string(), - false, // Reduced debug info - ); - crate::network::send_packet_to_player(net, join_game); - - let mut holder_comp = ChunkHolderComponent::new(); - let mut loaded_chunks_comp = LoadedChunksComponent::default(); - - let player_pos = positions.get(player).unwrap().current.chunk_pos(); - - // Offsets from the origin to center view distance on - let chunk_offset_x = player_pos.x; - let chunk_offset_z = player_pos.z; - - // Queue chunks for sending. - let view_distance = i32::from(config.server.view_distance); - let mut chunks = Vec::with_capacity((view_distance * view_distance) as usize); - for x in -view_distance..=view_distance { - for z in -view_distance..=view_distance { - let chunk = ChunkPosition::new(x + chunk_offset_x, z + chunk_offset_z); - chunks.push(chunk); - } - } - - // Sort chunks so that closest chunks are sent first. - chunks.sort_unstable_by(|a, b| { - a.manhattan_distance(player_pos) - .cmp(&b.manhattan_distance(player_pos)) - }); - - // Queue chunks for loading + sending - chunks.into_iter().for_each(|chunk| { - crate::player::send_chunk_to_player( - chunk, - net, - player, - &chunk_map, - &worker_handle, - &mut holders, - &mut holder_comp, - &mut loaded_chunks_comp, - &lazy, - ); - }); - - holder_comps.insert(player, holder_comp).unwrap(); - loaded_chunks_comps - .insert(player, loaded_chunks_comp) - .unwrap(); - - // Increment player count - player_count.0.fetch_add(1, Ordering::SeqCst); - - join_handler.stage = Stage::AwaitChunkSends; - } - Stage::AwaitChunkSends => { - // If 0 chunks have yet to be sent, join the player by sending spawn position. - // See https://wiki.vg/Protocol_FAQ - if pending_chunks.len() != 0 { - continue; - } - - // SpawnPosition packet: world spawn (used for compass) - let level_spawn_block_pos = - BlockPosition::new(level.spawn_x, level.spawn_y, level.spawn_z); - let level_spawn_position = SpawnPosition::new(level_spawn_block_pos); - crate::network::send_packet_to_player(net, level_spawn_position); - - // Initial position/rotation for the player when they spawn - let player_pos = positions.get(player).unwrap().current; - let position_and_look = PlayerPositionAndLookClientbound::new( - player_pos.x, - player_pos.y, - player_pos.z, - player_pos.yaw, - player_pos.pitch, - 0, // Flags - unused by us - 0, // Teleport ID - unused by us - ); - crate::network::send_packet_to_player(net, position_and_look); - - // Trigger events - let event = PlayerJoinEvent { player }; - join_events.single_write(event); - - let event = EntitySpawnEvent { entity: player }; - spawn_events.single_write(event); - - // Trigger inventory update event on the entire inventory - let event = InventoryUpdateEvent { - slots: (0..46).collect(), - player, - }; - inv_events.single_write(event); - - // We're finished here. - to_remove.push(player); - } - } - } - - to_remove.into_iter().for_each(|player| { - joincomps.remove(player); - }); - } -} diff --git a/server/src/lazy.rs b/server/src/lazy.rs deleted file mode 100644 index c446a5f8b..000000000 --- a/server/src/lazy.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Extension methods for `LazyUpdate`. - -use crate::entity::EntitySpawnEvent; -use shrev::EventChannel; -use specs::world::{EntitiesRes, LazyBuilder}; -use specs::{Entity, LazyUpdate}; - -pub trait LazyUpdateExt { - /// Creates an entity and lazily inserts components. - /// - /// This should be used instead of `LazyUpdate::create_entity` - /// because it automatically triggers an `EntitySpawnEvent`. - fn spawn_entity(&self, entities: &EntitiesRes) -> LazyBuilder; - - /// Lazily sends an entity to a player. This simply forwards - /// to `crate::entity::broadcast::send_entity_to_player`. - fn send_entity_to_player(&self, player: Entity, entity: Entity); -} - -impl LazyUpdateExt for LazyUpdate { - fn spawn_entity(&self, entities: &EntitiesRes) -> LazyBuilder { - let entity = entities.create(); - // Trigger event - self.exec(move |world| { - world - .fetch_mut::<EventChannel<EntitySpawnEvent>>() - .single_write(EntitySpawnEvent { entity }); - }); - - LazyBuilder { lazy: self, entity } - } - - fn send_entity_to_player(&self, player: Entity, entity: Entity) { - crate::entity::send_entity_to_player(self, player, entity); - } -} diff --git a/server/src/lib.rs b/server/src/lib.rs deleted file mode 100644 index fa64af739..000000000 --- a/server/src/lib.rs +++ /dev/null @@ -1,554 +0,0 @@ -// Specs systems tend to have very long -// tuples as their SystemData, and Clippy -// doesn't seem to like this. -#![allow(clippy::type_complexity)] - -#[macro_use] -extern crate log; -#[macro_use] -extern crate serde; -#[macro_use] -extern crate serde_json; -#[macro_use] -extern crate failure; -#[macro_use] -extern crate num_derive; -#[macro_use] -extern crate smallvec; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate derive_deref; -#[macro_use] -extern crate feather_codegen; -#[macro_use] -extern crate bitflags; -#[macro_use] -extern crate feather_core; - -extern crate nalgebra_glm as glm; - -use crossbeam::Receiver; -use std::alloc::System; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -use specs::{Builder, Dispatcher, DispatcherBuilder, Entity, LazyUpdate, World, WorldExt}; - -use feather_core::network::packet::implementation::DisconnectPlay; -use prelude::*; - -use crate::chunk_logic::{ChunkHolders, ChunkWorkerHandle}; -use crate::entity::chicken::ChickenComponent; -use crate::entity::cow::CowComponent; -use crate::entity::donkey::DonkeyComponent; -use crate::entity::horse::HorseComponent; -use crate::entity::llama::LlamaComponent; -use crate::entity::mooshroom::MooshroomComponent; -use crate::entity::pig::PigComponent; -use crate::entity::rabbit::RabbitComponent; -use crate::entity::sheep::SheepComponent; -use crate::entity::squid::SquidComponent; -use crate::entity::{ - EntityDestroyEvent, NamedComponent, PacketCreatorComponent, SerializerComponent, -}; -use crate::network::send_packet_to_player; -use crate::player::PlayerDisconnectEvent; -use crate::systems::{BROADCASTER, JOIN_HANDLER, NETWORK, PLAYER_INIT}; -use crate::util::Util; -use crate::worldgen::{ - ComposableGenerator, EmptyWorldGenerator, SuperflatWorldGenerator, WorldGenerator, -}; -use feather_core::level; -use feather_core::level::{deserialize_level_file, save_level_file, LevelData, LevelGeneratorType}; -use rand::Rng; -use shrev::EventChannel; -use std::collections::hash_map::DefaultHasher; -use std::fs::File; -use std::hash::{Hash, Hasher}; -use std::io::{Read, Write}; -use std::path::Path; -use std::process::exit; - -#[global_allocator] -static ALLOC: System = System; - -#[macro_use] -pub mod util; -pub mod blocks; -pub mod chunk_logic; -pub mod chunkworker; -pub mod config; -pub mod entity; -pub mod io; -pub mod joinhandler; -pub mod lazy; -pub mod lighting; -pub mod network; -pub mod physics; -pub mod player; -pub mod prelude; -pub mod shutdown; -pub mod systems; -#[cfg(test)] -pub mod testframework; -pub mod time; -pub mod worldgen; - -pub const TPS: u64 = 20; -pub const PROTOCOL_VERSION: u32 = 404; -pub const SERVER_VERSION: &str = "Feather 1.13.2"; -pub const TICK_TIME: u64 = 1000 / TPS; - -#[derive(Default, Debug)] -pub struct PlayerCount(AtomicUsize); - -#[derive(Default, Debug)] -pub struct TickCount(u64); - -pub fn main() { - let config = Arc::new(load_config()); - init_log(&config); - - info!("Starting Feather; please wait..."); - - let server_icon = Arc::new(load_server_icon()); - - let player_count = Arc::new(PlayerCount(AtomicUsize::new(0))); - - let io_manager = init_io_manager( - Arc::clone(&config), - Arc::clone(&player_count), - Arc::clone(&server_icon), - ); - - let world_name = &config.world.name; - let world_dir = Path::new(world_name.as_str()); - let level_file = &world_dir.join("level.dat"); - if !world_dir.is_dir() { - info!( - "World directory '{}' not found, creating it", - world_dir.display() - ); - // Create directory - std::fs::create_dir(world_dir).unwrap(); - - let level = create_level(&config); - let root = level::Root { data: level }; - let mut level_file = File::create(level_file).unwrap(); - save_level_file(&root, &mut level_file).unwrap(); - } - - info!("Loading {}", level_file.to_str().unwrap()); - let level = load_level(level_file).unwrap_or_else(|e| { - error!("Error occurred while loading level.dat: {}", e); - error!("Please ensure that the world directory exists and is not corrupt."); - exit(1) - }); - - let (mut world, mut dispatcher) = init_world(config, player_count, io_manager, level); - - // Channel used by the shutdown handler to notify the server thread. - let (shutdown_tx, shutdown_rx) = crossbeam::unbounded(); - - shutdown::init(shutdown_tx); - - info!("Initialized world"); - - info!("Generating RSA keypair"); - io::init(); - - info!("Queuing spawn chunks for loading"); - load_spawn_chunks(&mut world); - - info!("Server started"); - run_loop(&mut world, &mut dispatcher, shutdown_rx); - - info!("Shutting down"); - - info!("Saving chunks"); - shutdown::save_chunks(&mut world); - info!("Saving level.dat"); - shutdown::save_level(&world); - info!("Saving player data"); - shutdown::save_player_data(&world); - - info!("Goodbye"); - exit(0); -} - -/// Loads the configuration file, creating a default -/// one if it does not exist. -fn load_config() -> Config { - match config::load_from_file("feather.toml") { - Ok(config) => config, - Err(e) => match e { - config::ConfigError::Io(_) => { - // Use default config - println!("Config not found - creating it"); - let config = Config::default(); - let mut file = File::create("feather.toml").unwrap(); - file.write_all(config::DEFAULT_CONFIG_STR.as_bytes()) - .unwrap(); - config - } - config::ConfigError::Parse(e) => { - panic!("Failed to load configuration file: {}", e); - } - }, - } -} - -fn create_level(config: &Config) -> LevelData { - let seed = get_seed(config); - let world_name = &config.world.name; - debug!("Using seed {} for world '{}'", seed, world_name); - - // TODO: Generate spawn position properly - LevelData { - allow_commands: false, - border_center_x: 0.0, - border_center_z: 0.0, - border_damage_per_block: 0.0, - border_safe_zone: 0.0, - border_size: 0.0, - clear_weather_time: 0, - data_version: 0, - day_time: 0, - difficulty: 0, - difficulty_locked: 0, - game_type: 0, - hardcore: false, - initialized: false, - last_played: 0, - raining: false, - rain_time: 0, - seed, - spawn_x: 0, - spawn_y: 100, - spawn_z: 0, - thundering: false, - thunder_time: 0, - time: 0, - version: Default::default(), - generator_name: config.world.generator.to_string(), - generator_options: None, - } -} - -fn get_seed(config: &Config) -> i64 { - let seed_raw = &config.world.seed; - // Empty seed: random - // Seed is valid i64: parse - // Seed is something else: hash - if seed_raw.is_empty() { - rand::thread_rng().gen() - } else { - match seed_raw.parse::<i64>() { - Ok(seed_int) => seed_int, - Err(_) => hash_seed(seed_raw.as_str()), - } - } -} - -fn hash_seed(seed_raw: &str) -> i64 { - let mut hasher = DefaultHasher::new(); - seed_raw.hash(&mut hasher); - hasher.finish() as i64 -} - -/// Loads the level.dat file for the world. -fn load_level(path: &Path) -> Result<LevelData, failure::Error> { - let file = File::open(path)?; - let data = deserialize_level_file(file)?; - Ok(data) -} - -/// Loads the chunks around the spawn area and creates -/// a chunk hold on those chunks to prevent them from -/// being unloaded. -/// -/// Note that these chunks are loaded asynchronously, -/// and this function will return before loading is complete. -fn load_spawn_chunks(world: &mut World) { - let view_distance = i32::from(world.fetch::<Arc<Config>>().server.view_distance); - - // Create an entity for the server and - // add chunk holders using it. - let server_entity = world.create_entity().build(); - - let mut chunk_holders = world.fetch_mut::<ChunkHolders>(); - let chunk_worker_handle = world.fetch::<ChunkWorkerHandle>(); - - let level = world.fetch::<LevelData>(); - let offset_x = level.spawn_x / 16; - let offset_z = level.spawn_z / 16; - for x in -view_distance..=view_distance { - for z in -view_distance..=view_distance { - let chunk = ChunkPosition::new(x + offset_x, z + offset_z); - - chunk_logic::load_chunk(&chunk_worker_handle, chunk); - chunk_holders.insert_holder(chunk, server_entity); - } - } -} - -/// Runs the server loop, blocking until the server -/// is shut down. -fn run_loop(world: &mut World, dispatcher: &mut Dispatcher, shutdown_rx: Receiver<()>) { - loop { - if shutdown_rx.try_recv().is_ok() { - // Shut down - return; - } - - let start_time = current_time_in_millis(); - - dispatcher.dispatch(&world); - world.maintain(); - - world.fetch_mut::<Util>().reset(); - - // Increment tick count - let mut tick_count = world.write_resource::<TickCount>(); - tick_count.0 += 1; - - // Sleep correct amount - let end_time = current_time_in_millis(); - let elapsed = end_time - start_time; - if elapsed > TICK_TIME { - debug!("Running behind! Starting next tick immediately"); - continue; // Behind - start next tick immediately - } - - // Sleep in 1ms increments until we've slept enough - let mut sleep_time = (TICK_TIME - elapsed) as i64; - let mut last_sleep_time = current_time_in_millis(); - while sleep_time > 0 { - std::thread::sleep(Duration::from_millis(1)); - sleep_time -= (current_time_in_millis() - last_sleep_time) as i64; - last_sleep_time = current_time_in_millis(); - } - } -} - -/// Starts the IO threads. -fn init_io_manager( - config: Arc<Config>, - player_count: Arc<PlayerCount>, - server_icon: Arc<Option<String>>, -) -> io::NetworkIoManager { - io::NetworkIoManager::start( - format!("{}:{}", config.server.address, config.server.port) - .parse() - .unwrap(), - config, - player_count, - server_icon, - ) -} - -/// Initializes the Specs world and dispatchers. -fn init_world<'a, 'b>( - config: Arc<Config>, - player_count: Arc<PlayerCount>, - ioman: io::NetworkIoManager, - level: LevelData, -) -> (World, Dispatcher<'a, 'b>) { - let mut world = World::new(); - time::init_time(&mut world, &level); - world.insert(config); - world.insert(player_count); - world.insert(ioman); - world.insert(TickCount::default()); - - world.register::<PacketCreatorComponent>(); - world.register::<SerializerComponent>(); - - let generator: Arc<dyn WorldGenerator> = match level.generator_type() { - LevelGeneratorType::Flat => Arc::new(SuperflatWorldGenerator { - options: level.clone().generator_options.unwrap_or_default(), - }), - LevelGeneratorType::Default => { - Arc::new(ComposableGenerator::default_with_seed(level.seed as u64)) - } - _ => Arc::new(EmptyWorldGenerator {}), - }; - world.insert(level); - world.insert(generator); - - let mut dispatcher = DispatcherBuilder::new(); - - dispatcher.add(network::NetworkSystem, NETWORK, &[]); - - blocks::init_logic(&mut dispatcher); - physics::init_logic(&mut dispatcher); - entity::init_logic(&mut dispatcher); - player::init_logic(&mut dispatcher); - chunk_logic::init_logic(&mut dispatcher); - time::init_logic(&mut dispatcher); - lighting::init_logic(&mut dispatcher); - - dispatcher.add_barrier(); - - blocks::init_handlers(&mut dispatcher); - physics::init_handlers(&mut dispatcher); - entity::init_handlers(&mut dispatcher); - player::init_handlers(&mut dispatcher); - chunk_logic::init_handlers(&mut dispatcher); - - // Player init dependency is so that player position is loaded - // before the join handle runs. - dispatcher.add( - joinhandler::JoinHandlerSystem, - JOIN_HANDLER, - &[NETWORK, PLAYER_INIT], - ); - - dispatcher.add_barrier(); - - player::init_broadcast(&mut dispatcher); - entity::init_broadcast(&mut dispatcher); - - // Broadcast system needs to run last. - dispatcher.add_barrier(); - dispatcher.add(util::BroadcasterSystem, BROADCASTER, &[]); - - let mut dispatcher = dispatcher.build(); - dispatcher.setup(&mut world); - - register_components(&mut world); - - (world, dispatcher) -} - -fn register_components(world: &mut World) { - world.register::<ChickenComponent>(); - world.register::<CowComponent>(); - world.register::<DonkeyComponent>(); - world.register::<HorseComponent>(); - world.register::<LlamaComponent>(); - world.register::<MooshroomComponent>(); - world.register::<PigComponent>(); - world.register::<RabbitComponent>(); - world.register::<SheepComponent>(); - world.register::<SquidComponent>(); -} - -fn init_log(config: &Config) { - let level = match config.log.level.as_str() { - "trace" => log::Level::Trace, - "debug" => log::Level::Debug, - "info" => log::Level::Info, - "warn" => log::Level::Warn, - "error" => log::Level::Error, - _ => panic!("Unknown log level {}", config.log.level), - }; - - simple_logger::init_with_level(level).unwrap(); -} - -/// Tries to load a server icon from the current directory. -fn load_server_icon() -> Option<String> { - let icon_file: Option<File> = match File::open("server-icon.png") { - Ok(file) => Some(file), - Err(_) => None, - }; - - let mut icon_file = icon_file?; - - let mut data = Vec::new(); - if icon_file.read_to_end(&mut data).is_err() { - warn!("Failed to load server icon."); - return None; - } - - let b64_icon = base64::encode(&data); - Some(format!("data:image/png;base64,{}", b64_icon)) -} - -/// Retrieves the current time in seconds -/// since the UNIX epoch. -pub fn current_time_in_secs() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs() -} - -/// Retrieves the current time in milleseconds -/// since the UNIX epoch. -pub fn current_time_in_millis() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() as u64 -} - -/// Disconnects the given player, removing them from the world. -/// This operation is performed lazily. -pub fn disconnect_player(player: Entity, reason: String, lazy: &LazyUpdate) { - lazy.exec_mut(move |world| { - let json = json!({ - "text": reason, - }); - - let packet = DisconnectPlay::new(json.to_string()); - send_packet_to_player(world.read_component().get(player).unwrap(), packet); - - disconnect_player_without_packet(player, world, reason); - }) -} - -/// Disconnects a player without sending Disconnect Play. -/// This should be used when the client disconnects. -pub fn disconnect_player_without_packet(player: Entity, world: &mut World, reason: String) { - let nameds = world.write_component::<NamedComponent>(); - let named = nameds.get(player).unwrap(); - - info!("Disconnecting player {}: {}", named.display_name, reason); - - // Decrement player count - let player_count = world.fetch_mut::<Arc<PlayerCount>>(); - player_count.0.fetch_sub(1, Ordering::SeqCst); - - // Trigger disconnect event - let event = PlayerDisconnectEvent { - player, - uuid: named.uuid, - reason, - }; - world - .fetch_mut::<EventChannel<PlayerDisconnectEvent>>() - .single_write(event); - - // Trigger entity destroy event - let event = EntityDestroyEvent { entity: player }; - world - .fetch_mut::<EventChannel<EntityDestroyEvent>>() - .single_write(event); - - // The entity is removed from the world by `entity::EntityDestroySystem`. -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_init_world() { - let config = Arc::new(Config::default()); - let player_count = Arc::new(PlayerCount(AtomicUsize::new(0))); - let server_icon = Arc::new(Some(String::from("server_icon"))); - let ioman = init_io_manager( - Arc::clone(&config), - Arc::clone(&player_count), - Arc::clone(&server_icon), - ); - let level = LevelData::default(); - - let (world, mut dispatcher) = init_world(config, player_count, ioman, level); - dispatcher.dispatch(&world); - } -} diff --git a/server/src/lighting.rs b/server/src/lighting.rs deleted file mode 100644 index f862b2fdb..000000000 --- a/server/src/lighting.rs +++ /dev/null @@ -1,514 +0,0 @@ -//! Calculation of block and sky light. -//! -//! # Algorithms: block light -//! For block light calculation, we define four types of block -//! updates for which to perform lighting: -//! -//! * Creation of a light-emitting block. We simply propagate -//! the light update using flood fill. -//! -//! * Removal of a light-emitting block. We first perform flood fill -//! and set any blocks which were previously affected by this block's -//! light to 0. Then, we recalculate lighting for light sources within -//! a range of 30 blocks based on algorithm #1. -//! -//! * Creation of an opaque, non-emitting block. We first set the created -//! block to air temporarily. We then query for nearby lights -//! within a range of 15 (the maximum distance travelled by light) and perform -//! algorithm #2 on them. Finally, we set the created block back to the correct -//! value and perform algorithm #1 on all lights. -//! -//! * Removal of an opaque, non-emitting block. In this case, -//! we set the new air block's light to the highest value of an -//! adjacent block minus 1. We then perform algorithm #1 on this new block. -//! -//! Each algorithm is implemented in a separate function, and `LightingSystem` -//! determines which to use based on the values of the block update event. -//! -//! If we are recalculating light for an entire chunk, e.g. when a chunk is generated, -//! we first zero out light, then find all light sources in the chunk and perform -//! algorithm #1 on them as if they had just been placed. - -use crate::blocks::BlockUpdateEvent; -use crate::chunk_logic::ChunkLoadEvent; -use crate::physics::chunks_within_distance; -use crate::systems::LIGHTING; -use arrayvec::ArrayVec; -use failure::_core::marker::PhantomData; -use feather_blocks::{Block, BlockExt}; -use feather_core::prelude::ChunkMap; -use feather_core::world::chunk_relative_pos; -use feather_core::{BlockPosition, Chunk, ChunkPosition}; -use hashbrown::HashSet; -use multimap::MultiMap; -use shrev::{EventChannel, ReaderId}; -use smallvec::SmallVec; -use specs::{DispatcherBuilder, Read, System, Write}; -use std::collections::VecDeque; - -const MAX_TRAVEL_DISTANCE: u8 = 15; - -/// Lighter context, used to cache things during -/// a lighting iteration. -struct Context<'a> { - /// Reference to the current cached chunk. - /// This is used to avoid repetitive hashmap - /// accesses in the chunk map when groups - /// of clustered blocks are queried for. - current_chunk: *mut Chunk, - /// Chunk map. Raw pointers are used to bypass the borrow - /// checker, since `current_chunk` refers to the chunk map, - /// which isn't allowed. - chunk_map: *mut ChunkMap, - _phantom: PhantomData<&'a ()>, -} - -impl<'a> Context<'a> { - fn new(chunk_map: &'a mut ChunkMap, start_chunk: ChunkPosition) -> Option<Self> { - let chunk_map = chunk_map as *mut ChunkMap; - - // Safety: `chunk_map` is a valid pointer - // made from a mutable reference. - // It has not been modified since. - let current_chunk = unsafe { (*chunk_map).chunk_at_mut(start_chunk)? as *mut Chunk }; - - Some(Self { - current_chunk, - chunk_map, - _phantom: PhantomData, - }) - } - - fn chunk_at_mut(&mut self, pos: ChunkPosition) -> Option<&'a mut Chunk> { - if pos == (unsafe { &*self.current_chunk }).position() { - Some(unsafe { &mut *self.current_chunk }) - } else { - // Safety: While `self.current_chunk` refers to the chunk map, - // it is never accessed between mutations of the chunk - // map itself, since `Context` holds a unique reference to the - // map and never mutates it. - self.current_chunk = unsafe { (*self.chunk_map).chunk_at_mut(pos)? }; - Some(unsafe { &mut *self.current_chunk }) - } - } - - fn block_light_at(&mut self, pos: BlockPosition) -> u8 { - match self.chunk_at_mut(pos.chunk_pos()) { - Some(chunk) => { - let (x, y, z) = chunk_relative_pos(pos); - chunk.block_light_at(x, y, z) - } - None => 0, - } - } - - fn set_block_light_at(&mut self, pos: BlockPosition, value: u8) { - if let Some(chunk) = self.chunk_at_mut(pos.chunk_pos()) { - let (x, y, z) = chunk_relative_pos(pos); - chunk.set_block_light_at(x, y, z, value); - } - } - - fn block_at(&mut self, pos: BlockPosition) -> Block { - match self.chunk_at_mut(pos.chunk_pos()) { - Some(chunk) => { - let (x, y, z) = chunk_relative_pos(pos); - chunk.block_at(x, y, z) - } - None => Block::Air, - } - } - - fn set_block_at(&mut self, pos: BlockPosition, block: Block) { - if let Some(chunk) = self.chunk_at_mut(pos.chunk_pos()) { - let (x, y, z) = chunk_relative_pos(pos); - chunk.set_block_at(x, y, z, block); - } - } -} - -/// Contains a map storing light sources for each chunk. -/// This is used to accelerate light calculation. -#[derive(Default)] -pub struct ChunkLights(MultiMap<ChunkPosition, BlockPosition>); - -impl ChunkLights { - fn lights_within_distance(&self, pos: BlockPosition, dist: u8) -> SmallVec<[BlockPosition; 9]> { - let dist_f64 = f64::from(dist); - let chunks = - chunks_within_distance(pos.world_pos(), glm::vec3(dist_f64, dist_f64, dist_f64)); - - chunks - .into_iter() - .map(|chunk| { - self.0 - .get_vec(&chunk) - .map(|vec| vec.as_slice()) - .unwrap_or(&[]) - .iter() - }) - .flatten() - .copied() - .collect() - } -} - -/// System for handling all lighting tasks. -#[derive(Default)] -pub struct LightingSystem { - update_reader: Option<ReaderId<BlockUpdateEvent>>, - load_reader: Option<ReaderId<ChunkLoadEvent>>, -} - -impl<'a> System<'a> for LightingSystem { - type SystemData = ( - Write<'a, ChunkMap>, - Write<'a, ChunkLights>, - Read<'a, EventChannel<ChunkLoadEvent>>, - Read<'a, EventChannel<BlockUpdateEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (mut chunk_map, mut chunk_lights, load_events, update_events) = data; - - // Update `ChunkLights` with newly loaded chunks - for load in load_events.read(self.load_reader.as_mut().unwrap()) { - // Find all lights within this chunk. - if let Some(chunk) = chunk_map.chunk_at(load.pos) { - let lights = find_lights_in_chunk(chunk); - lights - .into_iter() - .for_each(|light| chunk_lights.0.insert(load.pos, light)); - } - } - - // Perform lighting updates. - for event in update_events.read(self.update_reader.as_mut().unwrap()) { - let mut ctx = match Context::new(&mut chunk_map, event.pos.chunk_pos()) { - Some(ctx) => ctx, - None => continue, // Unloaded chunk - }; - - // Determine which algorithm to use. - if event.old_block.light_emission() < event.new_block.light_emission() { - ctx.set_block_light_at(event.pos, event.new_block.light_emission()); - emitting_creation(&mut ctx, event.pos); - } else if event.new_block.light_emission() == 0 && event.old_block.light_emission() > 0 - { - ctx.set_block_light_at(event.pos, 0); - emitting_removal(&mut ctx, &chunk_lights, event.pos, event.old_block); - } else if event.old_block.is_opaque() && !event.new_block.is_opaque() { - opaque_non_emitting_removal(&mut ctx, event.pos); - } else { - opaque_non_emitting_creation(&mut ctx, &chunk_lights, event.pos, event.new_block); - } - - // Update `ChunkLights`. - if event.old_block.light_emission() != event.new_block.light_emission() { - if event.new_block.light_emission() == 0 { - chunk_lights - .0 - .get_vec_mut(&event.pos.chunk_pos()) - .unwrap() - .retain(|pos| *pos != event.pos); - } else if event.old_block.light_emission() == 0 { - chunk_lights.0.insert(event.pos.chunk_pos(), event.pos); - } - } - } - } - - setup_impl!(update_reader, load_reader); -} - -pub fn init_logic(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(LightingSystem::default(), LIGHTING, &[]); -} - -fn find_lights_in_chunk(chunk: &Chunk) -> Vec<BlockPosition> { - let mut res = vec![]; - - for x in 0..16 { - for y in 0..256 { - for z in 0..16 { - let block = chunk.block_at(x, y, z); - - let emission = block.light_emission(); - if emission > 0 { - res.push(BlockPosition::new(x as i32, y as i32, z as i32)); - } - } - } - } - - res -} - -/// Algorithm #1, as described in the module-level docs. -fn emitting_creation(context: &mut Context, position: BlockPosition) { - let emission = context.block_light_at(position); - // Perform flood fill starting from `position`. - // For each block, set the light value to the maximum light - // value of any adjacent block minus 1. - flood_fill(context, position, emission, |ctx, pos| { - let light = light_value_for_block(ctx, pos); - ctx.set_block_light_at(pos, light); - }); -} - -/// Algorithm #2, as described in the module-level docs. -fn emitting_removal( - context: &mut Context, - chunk_lights: &ChunkLights, - position: BlockPosition, - old_block: Block, -) { - // Perform flood fill and set all blocks affected by the old light to 0 light. - flood_fill(context, position, old_block.light_emission(), |ctx, pos| { - ctx.set_block_light_at(pos, 0); - }); - - // For all lights which could have affected the blocks we just set to 0, - // recalculate lighting using algorithm #1. - let nearby_lights = chunk_lights.lights_within_distance(position, MAX_TRAVEL_DISTANCE * 2); - - nearby_lights.into_iter().for_each(|light| { - if light != position { - emitting_creation(context, light); - } - }); -} - -/// Algorithm #3, as described in the module-level docs. -fn opaque_non_emitting_creation( - context: &mut Context, - chunk_lights: &ChunkLights, - position: BlockPosition, - new_block: Block, -) { - // Re-calculate all lights that could have affected this block. - // We ensure that all areas are correctly set to dark by first - // faking that the block was never created. - context.set_block_at(position, Block::Air); - - let nearby_lights = chunk_lights.lights_within_distance(position, MAX_TRAVEL_DISTANCE); - - nearby_lights.iter().for_each(|light| { - let block = context.block_at(*light); - emitting_removal(context, chunk_lights, *light, block); - }); - - // Set block back to correct value. - context.set_block_at(position, new_block); - - // Recalculate nearby lights. - nearby_lights.iter().for_each(|light| { - emitting_creation(context, *light); - }); -} - -/// Algorithm #4, as described in the module-level docs. -fn opaque_non_emitting_removal(context: &mut Context, position: BlockPosition) { - let value = light_value_for_block(context, position); - - context.set_block_light_at(position, value); - - // Propagate new light value for this block, as if it were a new light source. - if value > 0 { - emitting_creation(context, position); - } -} - -/// Returns the light value for the block at `position`, -/// equivalent to the maximum light value of an adjacent block -/// minus 1. -fn light_value_for_block(context: &mut Context, position: BlockPosition) -> u8 { - // Find highest light value of 6 adjacent blocks. - let adjacent = adjacent_blocks(position); - let mut value = adjacent - .into_iter() - .map(|pos| context.block_light_at(pos)) - .max() - .unwrap(); - - if value > 0 { - value -= 1; - } - - value -} - -/// Performs flood fill starting at `start` and travelling up -/// to `max_dist` blocks. -/// -/// For each block iterated over, the provided closure will be invoked. -/// No block will be iterated more than once. -fn flood_fill<F>(context: &mut Context, start: BlockPosition, max_dist: u8, mut func: F) -where - F: FnMut(&mut Context, BlockPosition), -{ - // Don't iterate over same block more than once - let mut touched = HashSet::with_capacity(64); - touched.insert(start); - - // We use a queue-based algorithm rather than a recursive - // one. - let mut queue = VecDeque::with_capacity(64); - - queue.push_back(start); - - let mut finished = false; - - while let Some(pos) = queue.pop_front() { - if finished { - break; - } - - let blocks = adjacent_blocks(pos); - - blocks.into_iter().for_each(|pos| { - if pos.manhattan_distance(start) > max_dist as i32 { - // Finished - finished = true; - return; - } - - // Skip if we already went over this block - if !touched.insert(pos) { - return; - } - - let block = context.block_at(pos); - if block.is_opaque() { - return; // Stop iterating - } - - // Call closure - func(context, pos); - - // Add block to queue - queue.push_back(pos); - }); - } -} - -/// Returns the up to six adjacent blocks to a given block position. -fn adjacent_blocks(to: BlockPosition) -> ArrayVec<[BlockPosition; 6]> { - let offsets = [ - (-1, 0, 0), - (1, 0, 0), - (0, -1, 0), - (0, 1, 0), - (0, 0, -1), - (0, 0, 1), - ]; - offsets - .iter() - .map(|(x, y, z)| BlockPosition::new(to.x + *x, to.y + *y, to.z + *z)) - .filter(|pos| pos.y >= 0 && pos.y <= 256) - .collect() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_context() { - let mut chunk_map = ChunkMap::new(); - - let pos = ChunkPosition::new(0, 0); - chunk_map.set_chunk_at(pos, Chunk::new(pos)); - let pos2 = ChunkPosition::new(0, 1); - chunk_map.set_chunk_at(pos2, Chunk::new(pos2)); - - let mut ctx = Context::new(&mut chunk_map, pos).unwrap(); - - assert_eq!(ctx.chunk_at_mut(pos).unwrap().position(), pos); - assert_eq!(ctx.chunk_at_mut(pos2).unwrap().position(), pos2); - assert_eq!(ctx.chunk_at_mut(pos).unwrap().position(), pos); - } - - #[test] - fn test_emitting_creation() { - let mut chunk_map = chunk_map(); - let mut ctx = Context::new(&mut chunk_map, ChunkPosition::new(0, 0)).unwrap(); - - let pos = BlockPosition::new(0, 100, 0); - ctx.set_block_at(pos, Block::Glowstone); - ctx.set_block_light_at(pos, Block::Glowstone.light_emission()); - - emitting_creation(&mut ctx, pos); - - assert_eq!(ctx.block_light_at(BlockPosition::new(0, 99, 0)), 14); - assert_eq!(ctx.block_light_at(BlockPosition::new(0, 99, 1)), 13); - } - - #[test] - fn test_opaque_non_emitting_removal() { - let mut chunk_map = chunk_map(); - let mut ctx = Context::new(&mut chunk_map, ChunkPosition::new(0, 0)).unwrap(); - - ctx.set_block_light_at(BlockPosition::new(0, 0, 0), 10); - ctx.set_block_light_at(BlockPosition::new(0, 2, 0), 9); - ctx.set_block_light_at(BlockPosition::new(1, 1, 0), 8); - ctx.set_block_light_at(BlockPosition::new(-1, 1, 0), 11); - ctx.set_block_light_at(BlockPosition::new(0, 1, 1), 0); - ctx.set_block_light_at(BlockPosition::new(0, 1, -1), 12); - ctx.set_block_light_at(BlockPosition::new(0, 1, 0), 15); - - opaque_non_emitting_removal(&mut ctx, BlockPosition::new(0, 1, 0)); - - assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 0)), 11); - assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 1)), 10); - assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 2)), 9); - assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 3)), 8); - assert_eq!(ctx.block_light_at(BlockPosition::new(0, 1, 4)), 7); - // ... - } - - #[test] - fn test_flood_fill() { - let mut chunk_map = chunk_map(); - let mut ctx = Context::new(&mut chunk_map, ChunkPosition::new(0, 0)).unwrap(); - - let mut count = 0; - - flood_fill(&mut ctx, BlockPosition::new(100, 100, 100), 1, |_, _| { - count += 1 - }); - - assert_eq!(count, 6); - } - - #[test] - fn test_chunk_lights() { - let mut chunk_lights = ChunkLights::default(); - chunk_lights - .0 - .insert(ChunkPosition::new(0, 0), BlockPosition::new(0, 0, 0)); - chunk_lights - .0 - .insert(ChunkPosition::new(1, 0), BlockPosition::new(16, 0, 0)); - - assert_eq!( - chunk_lights - .lights_within_distance(BlockPosition::new(0, 0, 0), 16) - .as_slice(), - &[BlockPosition::new(0, 0, 0), BlockPosition::new(16, 0, 0)] - ); - } - - fn chunk_map() -> ChunkMap { - let mut chunk_map = ChunkMap::new(); - - for x in -1..=1 { - for z in -1..=1 { - let pos = ChunkPosition::new(x, z); - chunk_map.set_chunk_at(pos, Chunk::new(pos)); - } - } - - chunk_map - } -} diff --git a/server/src/main.rs b/server/src/main.rs deleted file mode 100644 index f428fe91b..000000000 --- a/server/src/main.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[tokio::main] -async fn main() { - feather_server::main(); -} diff --git a/server/src/network.rs b/server/src/network.rs deleted file mode 100644 index fdf2b13fa..000000000 --- a/server/src/network.rs +++ /dev/null @@ -1,417 +0,0 @@ -use parking_lot::Mutex; - -use crossbeam::Receiver; -use futures::channel::mpsc::UnboundedSender as Sender; -use shrev::EventChannel; -use specs::{ - Component, DenseVecStorage, Entities, Entity, Join, LazyUpdate, Read, ReadStorage, System, - WorldExt, Write, WriteStorage, -}; - -use feather_core::network::packet::{implementation::*, Packet, PacketType}; - -use crate::entity::PlayerComponent; -use crate::io::{ListenerToServerMessage, NetworkIoManager, ServerToWorkerMessage}; -use crate::joinhandler::JoinHandlerComponent; -use crate::prelude::*; -use crate::{disconnect_player_without_packet, TickCount}; -use strum::EnumCount; - -//const MAX_KEEP_ALIVE_TIME: u64 = 30; -//const HEAD_OFFSET: f64 = 1.62; // Offset from feet pos to head pos - -/// A packet received from a player. -pub type QueuedPacket = (Entity, Box<dyn Packet>); - -/// Vector of `QueuedPacket`. -type QueuedPackets = Vec<QueuedPacket>; - -/// A component which contains the received packets -/// for this tick. -pub struct PacketQueue { - /// Vector of packet queues. For any given packet - /// type, the queued packets of that type can - /// be found by indexing into this vector with the ordinal - /// of the packet type. - /// - /// A locked `Vec` is used rather than a `SegQueue` because - /// there is typically no contention when accessing the queue - /// for a single packet type (there is at most one system handling - /// each packet type). As a result, there is no need for a lock-free - /// data structure. - queue: Vec<Mutex<QueuedPackets>>, -} - -impl PacketQueue { - /// Returns the packets queued for handling - /// of the given type, draining the queue of this - /// type of packet. - pub fn for_packet(&self, ty: PacketType) -> Vec<QueuedPacket> { - let ordinal = ty.ordinal(); - - let mut queued_packets = self.queue[ordinal].lock(); - - let mut new_queue = vec![]; - std::mem::swap(&mut new_queue, &mut queued_packets); - - new_queue - } - - /// Adds a packet to the queue. - pub fn add_for_packet(&self, player: Entity, packet: Box<dyn Packet>) { - let ordinal = packet.ty().ordinal(); - - let mut queued_packets = self.queue[ordinal].lock(); - queued_packets.push((player, packet)); - } -} - -impl Default for PacketQueue { - fn default() -> Self { - // Initialize with an empty queue for each packet type. - // Packet type ordinals start at 1 (who decided this? FIXME), - // so we have to use an inclusive range. - Self { - queue: (0..=PacketType::count()) - .map(|_| Mutex::new(vec![])) - .collect(), - } - } -} - -pub struct NetworkComponent { - sender: Sender<ServerToWorkerMessage>, - receiver: Receiver<ServerToWorkerMessage>, - /// A vector of all chunks that are currently - /// being loaded and should be sent to the player - /// once they have been loaded. - pub chunks_to_send: Vec<ChunkPosition>, - //last_keep_alive_time: u64, -} - -impl NetworkComponent { - pub fn new( - sender: Sender<ServerToWorkerMessage>, - receiver: Receiver<ServerToWorkerMessage>, - ) -> Self { - Self { - sender, - receiver, - chunks_to_send: vec![], - } - } -} - -impl Component for NetworkComponent { - type Storage = DenseVecStorage<Self>; -} - -/// The network system, responsible for -/// receiving and buffering packets received -/// from players. Received packets -/// are added to a queue (`PacketQueue`) so that -/// other systems can handle them. -pub struct NetworkSystem; - -/// Event which is triggered when a player joins -/// but before the join handler is completed. -pub struct PlayerPreJoinEvent { - pub player: Entity, - pub username: String, - pub uuid: Uuid, - pub profile_properties: Vec<mojang_api::ProfileProperty>, -} - -impl<'a> System<'a> for NetworkSystem { - type SystemData = ( - WriteStorage<'a, NetworkComponent>, - ReadStorage<'a, PlayerComponent>, - Write<'a, EventChannel<PlayerPreJoinEvent>>, - Write<'a, PacketQueue>, - Read<'a, NetworkIoManager>, - Entities<'a>, - Read<'a, TickCount>, - Read<'a, LazyUpdate>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - mut netcomps, - pcomps, - mut join_events, - packet_queue, - ioman, - entities, - tick_count, - lazy, - ) = data; - // Poll for new connections - while let Ok(msg) = ioman.receiver.try_recv() { - match msg { - ListenerToServerMessage::NewClient(info) => { - // New connection - handle it - info!("Accepting connection from {}", info.ip); - let netcomp = NetworkComponent::new(info.sender, info.receiver); - - // Create entity - let new_entity = entities.create(); - netcomps.insert(new_entity, netcomp).unwrap(); - - // Create join handler - let join_handler = JoinHandlerComponent::new(); - lazy.exec_mut(move |world| { - world - .write_component::<JoinHandlerComponent>() - .insert(new_entity, join_handler) - .unwrap(); - }); - - // Queue event - let event = PlayerPreJoinEvent { - player: new_entity, - username: info.username.clone(), - uuid: info.uuid, - profile_properties: info.profile.clone(), - }; - join_events.single_write(event); - } - } - } - - // Receive packets + disconnects from players - for (player, netcomp) in (&entities, &netcomps).join() { - while let Ok(msg) = netcomp.receiver.try_recv() { - match msg { - ServerToWorkerMessage::NotifyPacketReceived(packet) => { - packet_queue.add_for_packet(player, packet); - } - ServerToWorkerMessage::NotifyDisconnect(reason) => { - lazy.exec_mut(move |world| { - disconnect_player_without_packet(player, world, reason) - }); - break; - } - _ => panic!("Network system received invalid message from IO worker}"), - } - } - } - - // Send keepalives every second. The dependency on the player - // component is required because keepalives should - // only be sent to players who have joined (completed - // the login process). - // TODO check that player hasn't timed out - if tick_count.0 % TPS == 0 { - for (netcomp, _) in (&netcomps, &pcomps).join() { - send_packet_to_player(netcomp, KeepAliveClientbound::new(0)); - } - } - } -} - -/// Sends a packet to all players on the server, excluding -/// `neq`, if it exists. -pub fn send_packet_to_all_players<P: Packet + Clone + 'static>( - net_comps: &ReadStorage<NetworkComponent>, - entities: &Entities, - packet: P, - neq: Option<Entity>, -) { - for (entity, net) in (entities, net_comps).join() { - if let Some(e) = neq.as_ref() { - if *e == entity { - continue; // Exclude this entity - } - } - - send_packet_to_player(net, packet.clone()); - } -} - -/// Sends a packet to the given player. -pub fn send_packet_to_player<P: Packet + 'static>(comp: &NetworkComponent, packet: P) { - send_packet_boxed_to_player(comp, Box::new(packet)); -} - -/// Sends a packet to the given player. -pub fn send_packet_boxed_to_player(comp: &NetworkComponent, packet: Box<dyn Packet>) { - let _ = comp - .sender - .unbounded_send(ServerToWorkerMessage::SendPacket(packet)); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::io::NewClientInfo; - use crate::player::PlayerDisconnectEvent; - use crate::testframework as t; - use std::net::SocketAddr; - - #[test] - fn test_packet_queue() { - let queue = PacketQueue::default(); - - let (mut w, _) = t::init_world(); - let player = t::add_player(&mut w); - - let packet = LoginStart::new("test".to_string()); - queue.add_for_packet(player.entity, Box::new(packet)); - - let packets = queue.for_packet(PacketType::LoginStart); - assert_eq!(packets.len(), 1); - - let (entity, packet) = packets.first().unwrap(); - assert_eq!(*entity, player.entity); - assert_eq!(packet.ty(), PacketType::LoginStart); - } - - #[test] - fn test_new_client() { - let (mut w, mut d) = t::init_world(); - - let ioman = w.fetch_mut::<NetworkIoManager>(); - - let (send1, _recv1) = futures::channel::mpsc::unbounded(); - let (_send2, recv2) = crossbeam::unbounded(); - - let new_client = NewClientInfo { - ip: SocketAddr::new("127.0.0.1".parse().unwrap(), 25565), - username: "".to_string(), - profile: vec![], - uuid: Uuid::new_v4(), - sender: send1, - receiver: recv2, - }; - - let msg = ListenerToServerMessage::NewClient(new_client); - ioman.listener_sender.send(msg).unwrap(); - - let mut event_reader = t::reader(&w); - - drop(ioman); - - // Call the network system - d.dispatch(&w); - - w.maintain(); - - // Confirm that an entity was created - let mut count = 0; - let mut entity = None; - for (e, _, _) in ( - &*w.entities(), - &w.read_component::<NetworkComponent>(), - &w.read_component::<JoinHandlerComponent>(), - ) - .join() - { - entity = Some(e); - count += 1; - } - assert_eq!(count, 1); - - // Confirm that playerprejoinevent was queued - let channel = w.fetch_mut::<EventChannel<PlayerPreJoinEvent>>(); - let join_events: Vec<&PlayerPreJoinEvent> = channel.read(&mut event_reader).collect(); - assert_eq!(join_events.len(), 1); - let event = join_events.first().unwrap(); - - assert_eq!(event.player, entity.unwrap()); - } - - #[test] - fn test_packet_receive() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - // Send a packet - let packet = LoginStart::new("".to_string()); - t::send_packet(&player, packet); - - // Run system - d.dispatch(&w); - - w.maintain(); - - // Confirm that packet was received properly - let queue = w.fetch::<PacketQueue>(); - let packets = queue.for_packet(PacketType::LoginStart); - - assert_eq!(packets.len(), 1); - - let (entity, _packet) = packets.first().unwrap(); - assert_eq!(*entity, player.entity); - } - - #[test] - fn test_disconnect() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let mut event_reader = t::reader(&w); - - player - .network_sender - .send(ServerToWorkerMessage::NotifyDisconnect( - "reason".to_string(), - )) - .unwrap(); - - d.dispatch(&w); - - w.maintain(); - - let channel = w.fetch::<EventChannel<PlayerDisconnectEvent>>(); - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - - assert_eq!(events.len(), 1); - let first = events.first().unwrap(); - assert_eq!(first.player, player.entity); - } - - #[test] - fn test_keep_alives() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - let player2 = t::add_player(&mut w); - - d.dispatch(&w); - - t::assert_packet_received(&player, PacketType::KeepAliveClientbound); - t::assert_packet_received(&player2, PacketType::KeepAliveClientbound); - } - - #[test] - fn test_send_packet_to_all_players() { - let (mut w, _) = t::init_world(); - - let player1 = t::add_player(&mut w); - let player2 = t::add_player(&mut w); - let player3 = t::add_player(&mut w); - - let packet = LoginStart::new("test".to_string()); - - send_packet_to_all_players( - &w.read_component(), - &w.entities(), - packet, - Some(player1.entity), - ); - - dbg!(); - - t::assert_packet_received(&player2, PacketType::LoginStart); - dbg!(); - t::assert_packet_received(&player3, PacketType::LoginStart); - dbg!(); - - // Check that exclusion was not sent - let sent = t::received_packets(&player1, None); - dbg!(); - assert!(sent.is_empty()); - } -} diff --git a/server/src/physics/block_bboxes.rs b/server/src/physics/block_bboxes.rs deleted file mode 100644 index fa6f4e134..000000000 --- a/server/src/physics/block_bboxes.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! Bounding boxes for every non-cubic block. - -use crate::physics::component::bbox; -use feather_blocks::Block; -use ncollide3d::bounding_volume::AABB; - -/// Returns the bounding box for the given block. -/// -/// Non-solid blocks have no bounding box, -/// and the bounding box for a non-solid block -/// is undefined. -pub fn bbox_for_block(block: &Block) -> AABB<f64> { - match block { - Block::WhiteBed(_) - | Block::OrangeBed(_) - | Block::MagentaBed(_) - | Block::LightBlueBed(_) - | Block::YellowBed(_) - | Block::LimeBed(_) - | Block::PinkBed(_) - | Block::GrayBed(_) - | Block::LightGrayBed(_) - | Block::CyanBed(_) - | Block::PurpleBed(_) - | Block::BlueBed(_) - | Block::BrownBed(_) - | Block::GreenBed(_) - | Block::RedBed(_) - | Block::BlackBed(_) - | Block::PrismarineSlab(_) - | Block::PrismarineBrickSlab(_) - | Block::DarkPrismarineSlab(_) - | Block::OakSlab(_) - | Block::SpruceSlab(_) - | Block::BirchSlab(_) - | Block::JungleSlab(_) - | Block::AcaciaSlab(_) - | Block::DarkOakSlab(_) - | Block::StoneSlab(_) - | Block::SandstoneSlab(_) - | Block::PetrifiedOakSlab(_) - | Block::CobblestoneSlab(_) - | Block::BrickSlab(_) - | Block::StoneBrickSlab(_) - | Block::NetherBrickSlab(_) - | Block::QuartzSlab(_) - | Block::RedSandstoneSlab(_) - | Block::PurpurSlab(_) => bbox(1.0, 0.5, 1.0), - _ => bbox(1.0, 1.0, 1.0), - } -} diff --git a/server/src/physics/entity.rs b/server/src/physics/entity.rs deleted file mode 100644 index 4e1b931bd..000000000 --- a/server/src/physics/entity.rs +++ /dev/null @@ -1,216 +0,0 @@ -//! Module for performing entity physics, including velocity, drag -//! and position updates each tick. - -use specs::{Entities, Entity, Join, Read, ReadStorage, System, Write, WriteStorage}; - -use crate::entity::{EntityDestroyEvent, PositionComponent, VelocityComponent}; -use crate::physics::{ - block_impacted_by_ray, blocks_intersecting_bbox, AABBExt, PhysicsComponent, Side, -}; -use feather_core::world::ChunkMap; -use feather_core::Position; -use feather_core::{Block, BlockExt}; -use shrev::EventChannel; - -#[derive(Debug, Clone)] -pub struct EntityPhysicsLandEvent { - pub entity: Entity, - pub pos: Position, -} - -/// System for updating all entities' positions and velocities -/// each tick. -pub struct EntityPhysicsSystem; - -impl<'a> System<'a> for EntityPhysicsSystem { - type SystemData = ( - WriteStorage<'a, PositionComponent>, - WriteStorage<'a, VelocityComponent>, - ReadStorage<'a, PhysicsComponent>, - Write<'a, EventChannel<EntityDestroyEvent>>, - Write<'a, EventChannel<EntityPhysicsLandEvent>>, - Read<'a, ChunkMap>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - mut positions, - mut velocities, - physics, - mut entity_destroy_events, - mut entity_land_events, - chunk_map, - entities, - ) = data; - // Go through entities and update their positions according - // to their velocities. - - // Unfortunately, we are currently not able to parallel - // join over the position storage due to slide-rs/specs#541. - // When this issue is resolved, the join below should be switched to a parallel - // join. - - // A restricted storage is used for `velocity` so as to avoid - // triggering a velocity update event when it is not actually - // modified. - for (position, mut restrict_velocity, physics, entity) in ( - &mut positions, - &mut velocities.restrict_mut(), - &physics, - &entities, - ) - .join() - { - let mut velocity = *restrict_velocity.get_unchecked(); - - let mut pending_position = position.current + velocity.0; - - // Check for blocks along path between old position and pending position. - // This prevents entities from flying through blocks when their - // velocity is sufficiently high. - let origin = position.current.into(); - let direction = (pending_position - position.current).into(); - let distance_squared = pending_position.distance_squared(position.current); - - if let Some(impacted) = - block_impacted_by_ray(&chunk_map, origin, direction, distance_squared) - { - // Set velocities along correct axis to 0 and then set position - // to just before the bbox would have impacted the block. - let face = impacted.face; - let impact = impacted.pos; - - if face.contains(Side::EAST) || face.contains(Side::WEST) { - velocity.x = 0.0; - pending_position.x = impact.x + physics.bbox.size().x * face.as_vector().x; - } - if face.contains(Side::NORTH) || face.contains(Side::SOUTH) { - velocity.z = 0.0; - pending_position.z = impact.z + physics.bbox.size().z * face.as_vector().z; - } - if face.contains(Side::TOP) || face.contains(Side::BOTTOM) { - velocity.y = 0.0; - pending_position.y = impact.y + physics.bbox.size().y * face.as_vector().y; - } - if face.contains(Side::TOP) { - pending_position.on_ground = true; - } - } - - // Check for blocks around the bbox and apply offset - // to position to stop the bbox from intersecting blocks. - let intersect = blocks_intersecting_bbox( - &chunk_map, - position.current, - pending_position, - &physics.bbox, - ); - intersect.apply_to(&mut pending_position); - - if intersect.x_affected() { - velocity.x = 0.0; - } - - if intersect.y_affected() { - velocity.y = 0.0; - } - - if intersect.z_affected() { - velocity.z = 0.0; - } - - // Delete entity if it has gone into unloaded chunks. - let block_at_pos = match chunk_map.block_at(pending_position.block_pos()) { - Some(block) => block, - None => { - // Delete entity. - let event = EntityDestroyEvent { entity }; - entity_destroy_events.single_write(event); - - entities.delete(entity).unwrap(); - continue; - } - }; - - // Set on ground status - pending_position.on_ground = match chunk_map.block_at( - position!( - pending_position.x, - pending_position.y - physics.bbox.size().y / 2.0 - 0.01, - pending_position.z - ) - .block_pos(), - ) { - Some(block) => block.is_solid(), - None => false, - }; - if pending_position.on_ground && !position.current.on_ground { - entity_land_events.single_write(EntityPhysicsLandEvent { - entity, - pos: pending_position, - }); - } - - // Apply drag and gravity. - - // In water and lava, gravity is four times less, and velocity is multiplied by a special drag force. - let liquid_drag = 0.8; - match block_at_pos { - Block::Water(_) => { - velocity.0 *= liquid_drag; - velocity.0.y += physics.gravity / 4.0; - } - Block::Lava(_) => { - velocity.0 *= liquid_drag - 0.3; - velocity.0.y += physics.gravity / 4.0; - } - _ => { - let slip_multiplier = physics.slip_multiplier; - if pending_position.on_ground { - velocity.0.x *= slip_multiplier; - velocity.0.z *= slip_multiplier; - } else { - velocity.0.y = physics.drag * velocity.0.y + physics.gravity; - velocity.0.x *= physics.drag; - velocity.0.z *= physics.drag; - } - } - } - - // Set new position. - // A move event is triggered through FlaggedStorage. - position.current = pending_position; - - // Update velocity, if it changed. - if velocity != *restrict_velocity.get_unchecked() { - *restrict_velocity.get_mut_unchecked() = velocity; - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::test; - use crate::physics::PhysicsBuilder; - use crate::testframework as t; - use specs::{Builder, WorldExt}; - - #[test] - fn test_unloaded_chunk() { - let (mut w, mut d) = t::builder().with(EntityPhysicsSystem, "").build(); - - let entity = test::create(&mut w, position!(1000.0, 100.0, 1000.0)).build(); - - w.write_component::<PhysicsComponent>() - .insert(entity, PhysicsBuilder::new().build()) - .unwrap(); - - d.dispatch(&w); - w.maintain(); - - t::assert_removed(&w, entity); - } -} diff --git a/server/src/physics/mod.rs b/server/src/physics/mod.rs deleted file mode 100644 index c3423d4c7..000000000 --- a/server/src/physics/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Module for calculating physics interactions. - -mod block_bboxes; -mod component; -mod entity; -mod math; - -use crate::systems::ENTITY_PHYSICS; -pub use component::{AABBExt, PhysicsBuilder, PhysicsComponent}; -pub use entity::{EntityPhysicsLandEvent, EntityPhysicsSystem}; -pub use math::*; -use specs::DispatcherBuilder; - -pub fn init_logic(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(EntityPhysicsSystem, ENTITY_PHYSICS, &[]); -} - -pub fn init_handlers(_dispatcher: &mut DispatcherBuilder) { - // nothing -} diff --git a/server/src/player/animation.rs b/server/src/player/animation.rs deleted file mode 100644 index acf600b75..000000000 --- a/server/src/player/animation.rs +++ /dev/null @@ -1,140 +0,0 @@ -use crate::network::PacketQueue; -use crate::util::Util; -use feather_core::network::cast_packet; -use feather_core::network::packet::implementation::{AnimationClientbound, AnimationServerbound}; -use feather_core::network::packet::PacketType; -use feather_core::{ClientboundAnimation, Hand}; -use shrev::EventChannel; -use specs::SystemData; -use specs::{Entity, Read, ReaderId, System, World, Write}; - -/// Event which is triggered when a player causes -/// an animation. -#[derive(Debug, Clone)] -pub struct PlayerAnimationEvent { - pub player: Entity, - pub animation: ClientboundAnimation, -} - -/// System for handling Animation Serverbound packets -/// and then triggering a `PlayerAnimationEvent`. -pub struct PlayerAnimationSystem; - -impl<'a> System<'a> for PlayerAnimationSystem { - type SystemData = ( - Write<'a, EventChannel<PlayerAnimationEvent>>, - Read<'a, PacketQueue>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (mut events, packet_queue) = data; - - // Handle Animation Serverbound packets. - let packets = packet_queue.for_packet(PacketType::AnimationServerbound); - - for (player, packet) in packets { - let packet = cast_packet::<AnimationServerbound>(&*packet); - - let animation = match packet.hand { - Hand::Main => ClientboundAnimation::SwingMainArm, - Hand::Off => ClientboundAnimation::SwingOffhand, - }; - - let event = PlayerAnimationEvent { player, animation }; - events.single_write(event); - } - } -} - -/// System for broadcasting when a player causes an animation. -/// This system listens to `PlayerAnimationEvent`s. -#[derive(Default)] -pub struct AnimationBroadcastSystem { - reader: Option<ReaderId<PlayerAnimationEvent>>, -} - -impl<'a> System<'a> for AnimationBroadcastSystem { - type SystemData = (Read<'a, EventChannel<PlayerAnimationEvent>>, Read<'a, Util>); - - fn run(&mut self, data: Self::SystemData) { - let (events, util) = data; - - for event in events.read(&mut self.reader.as_mut().unwrap()) { - // Broadcast animation - let packet = AnimationClientbound::new(event.player.id() as i32, event.animation); - - util.broadcast_entity_update(event.player, packet, Some(event.player)) - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<PlayerAnimationEvent>>() - .register_reader(), - ); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::testframework as t; - use feather_core::network::packet::implementation::{ - AnimationClientbound, AnimationServerbound, - }; - use specs::WorldExt; - - #[test] - fn test_animation_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let packet = AnimationServerbound::new(Hand::Main); - t::receive_packet(&player, &w, packet); - - let mut event_reader = t::reader::<PlayerAnimationEvent>(&w); - - d.dispatch(&w); - w.maintain(); - - let channel = w.fetch::<EventChannel<PlayerAnimationEvent>>(); - - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - assert_eq!(events.len(), 1); - let first = events.first().unwrap(); - - assert_eq!(first.player, player.entity); - assert_eq!(first.animation, ClientboundAnimation::SwingMainArm); - } - - #[test] - fn test_animation_broadcast_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - let player2 = t::add_player(&mut w); - - let event = PlayerAnimationEvent { - player: player.entity, - animation: ClientboundAnimation::SwingMainArm, - }; - - t::trigger_event(&w, event.clone()); - - d.dispatch(&w); - w.maintain(); - - // Make sure animation wasn't sent to the player itself - t::assert_packet_not_received(&player, PacketType::AnimationClientbound); - - let packet = t::assert_packet_received(&player2, PacketType::AnimationClientbound); - let packet = cast_packet::<AnimationClientbound>(&*packet); - - assert_eq!(packet.entity_id, event.player.id() as i32); - assert_eq!(packet.animation, event.animation); - } -} diff --git a/server/src/player/broadcast.rs b/server/src/player/broadcast.rs deleted file mode 100644 index 40fe02c73..000000000 --- a/server/src/player/broadcast.rs +++ /dev/null @@ -1,203 +0,0 @@ -use crate::config::Config; -use crate::entity::{ChunkEntities, NamedComponent, PlayerComponent, PositionComponent}; -use crate::joinhandler::PlayerJoinEvent; -use crate::lazy::LazyUpdateExt; -use crate::network::{send_packet_to_all_players, send_packet_to_player, NetworkComponent}; -use crate::player::chat::ChatBroadcastEvent; -use feather_core::network::packet::implementation::{PlayerInfo, PlayerInfoAction}; -use feather_core::Gamemode; -use shrev::EventChannel; -use specs::{Entities, Entity, Join, Read, ReadStorage, ReaderId, System, World, Write}; -use specs::{LazyUpdate, SystemData}; -use std::sync::Arc; -use uuid::Uuid; - -/// System for broadcasting when a player joins -/// the game. -/// -/// This system only broadcasts the -/// Player Info packet necessary to view to player -/// in the tablist - the `EntityBroadcastSystem` handles -/// the Spawn Player packet. -#[derive(Default)] -pub struct JoinBroadcastSystem { - reader: Option<ReaderId<PlayerJoinEvent>>, -} - -impl<'a> System<'a> for JoinBroadcastSystem { - type SystemData = ( - Read<'a, EventChannel<PlayerJoinEvent>>, - ReadStorage<'a, PositionComponent>, - ReadStorage<'a, NamedComponent>, - ReadStorage<'a, PlayerComponent>, - ReadStorage<'a, NetworkComponent>, - Write<'a, EventChannel<ChatBroadcastEvent>>, - Read<'a, ChunkEntities>, - Read<'a, LazyUpdate>, - Read<'a, Arc<Config>>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - join_events, - positions, - nameds, - player_comps, - net_comps, - mut chat, - chunk_entities, - lazy, - config, - entities, - ) = data; - - for event in join_events.read(&mut self.reader.as_mut().unwrap()) { - // Broadcast join - let position = positions.get(event.player).unwrap(); - let named = nameds.get(event.player).unwrap(); - let player_comp = player_comps.get(event.player).unwrap(); - - let player_info = get_player_initialization_packet(position, named, player_comp); - - send_packet_to_all_players(&net_comps, &entities, player_info, None); - - let net_comp = net_comps.get(event.player).unwrap(); - - // Send existing players to new player - for (position, named, player_comp, entity) in - (&positions, &nameds, &player_comps, &entities).join() - { - if entity != event.player { - let player_info = - get_player_initialization_packet(position, named, player_comp); - send_packet_to_player(net_comp, player_info); - } - } - - // Send entities within view distance to new player - for entity in chunk_entities.entites_within_view_distance( - position.current.chunk_pos(), - config.server.view_distance, - ) { - if entity != event.player { - lazy.send_entity_to_player(event.player, entity); - } - } - - // Broadcast join message in chat - let message = json!({ - "translate": "multiplayer.player.joined", - "color": "yellow", - "with": [ - {"text": named.display_name}, - ], - }) - .to_string(); - chat.single_write(ChatBroadcastEvent { message }); - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<PlayerJoinEvent>>() - .register_reader(), - ); - } -} - -/// Returns the player info packet -/// for the given player. -fn get_player_initialization_packet( - _position: &PositionComponent, - named: &NamedComponent, - pcomp: &PlayerComponent, -) -> PlayerInfo { - let display_name = json!({ - "text": named.display_name - }) - .to_string(); - - let mut props = vec![]; - for prop in pcomp.profile_properties.iter() { - props.push(( - prop.name.clone(), - prop.value.clone(), - prop.signature.clone(), - )); - } - - let action = PlayerInfoAction::AddPlayer( - named.display_name.clone(), - props, - Gamemode::Creative, - 50, - display_name, - ); - PlayerInfo::new(action, named.uuid) -} - -/// Event which is called when a player disconnected. -pub struct PlayerDisconnectEvent { - pub player: Entity, - pub reason: String, - pub uuid: Uuid, -} - -/// System for broadcasting when a player disconnects. -#[derive(Default)] -pub struct DisconnectBroadcastSystem { - reader: Option<ReaderId<PlayerDisconnectEvent>>, -} - -impl<'a> System<'a> for DisconnectBroadcastSystem { - type SystemData = ( - ReadStorage<'a, NamedComponent>, - ReadStorage<'a, NetworkComponent>, - Write<'a, EventChannel<ChatBroadcastEvent>>, - Read<'a, EventChannel<PlayerDisconnectEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (nameds, networks, mut chat, disconnect_events) = data; - - for event in disconnect_events.read(&mut self.reader.as_mut().unwrap()) { - // Broadcast disconnect. - // Note that the Destroy Entity packet is sent - // in a separate system (crate::entity::EntityDestroyBroadcastSystem). - // This system only updates the tablist for all clients. - let player_info = PlayerInfo::new(PlayerInfoAction::RemovePlayer, event.uuid); - - for net in (&networks).join() { - send_packet_to_player(net, player_info.clone()); - } - - let named = nameds.get(event.player).unwrap(); - - // Broadcast chat message. - let message = json!({ - "translate": "multiplayer.player.left", - "color": "yellow", - "with": [ - {"text": named.display_name}, - ], - }) - .to_string(); - let event = ChatBroadcastEvent { message }; - chat.single_write(event); - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<PlayerDisconnectEvent>>() - .register_reader(), - ); - } -} diff --git a/server/src/player/chat.rs b/server/src/player/chat.rs deleted file mode 100644 index 60e7db460..000000000 --- a/server/src/player/chat.rs +++ /dev/null @@ -1,154 +0,0 @@ -use shrev::EventChannel; -use specs::SystemData; -use specs::{Entities, Read, ReadStorage, ReaderId, System, World, Write}; - -use feather_core::network::cast_packet; -use feather_core::network::packet::implementation::{ - ChatMessageClientbound, ChatMessageServerbound, -}; -use feather_core::network::packet::PacketType; - -use crate::entity::NamedComponent; -use crate::network::{send_packet_to_all_players, NetworkComponent, PacketQueue}; - -/// Event which is triggered when a new chat message is to be broadcasted to the whole server. -#[derive(Debug, Clone)] -pub struct ChatBroadcastEvent { - pub message: String, -} - -/// System for handling Chat Message Serverbound packets -/// and then triggering a `ChatBroadcastEvent`. -pub struct PlayerChatSystem; - -impl<'a> System<'a> for PlayerChatSystem { - type SystemData = ( - Write<'a, EventChannel<ChatBroadcastEvent>>, - ReadStorage<'a, NamedComponent>, - Read<'a, PacketQueue>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (mut events, nameds, packet_queue) = data; - - // Handle Chat Message Serverbound packets. - let packets = packet_queue.for_packet(PacketType::ChatMessageServerbound); - - for (player, packet) in packets { - let packet = cast_packet::<ChatMessageServerbound>(&*packet); - let message = packet.message.clone(); - let player_name = &nameds.get(player).unwrap().display_name; - - // TODO: could use a more robust chat-component library. - let message_json = json!({ - "translate": "chat.type.text", - "with": [ - {"text": player_name}, - {"text": message}, - ], - }) - .to_string(); - - let event = ChatBroadcastEvent { - message: message_json, - }; - events.single_write(event); - - // Log in the console - info!("<{}> {}", player_name, message); - } - } -} - -/// System for broadcasting chat messages. -/// This system listens to `ChatBroadcastEvent`s. -#[derive(Default)] -pub struct ChatBroadcastSystem { - reader: Option<ReaderId<ChatBroadcastEvent>>, -} - -impl<'a> System<'a> for ChatBroadcastSystem { - type SystemData = ( - Read<'a, EventChannel<ChatBroadcastEvent>>, - ReadStorage<'a, NetworkComponent>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (events, networks, entities) = data; - - for event in events.read(&mut self.reader.as_mut().unwrap()) { - let message = event.message.clone(); - - // Broadcast chat message - let packet = ChatMessageClientbound { - json_data: message, - position: 0, - }; - - send_packet_to_all_players(&networks, &entities, packet, None); - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<ChatBroadcastEvent>>() - .register_reader(), - ); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::testframework as t; - use feather_core::network::packet::implementation::ChatMessageServerbound; - use specs::WorldExt; - - #[test] - fn test_chat_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let packet = ChatMessageServerbound { - message: String::from("test"), - }; - t::receive_packet(&player, &w, packet); - - let mut event_reader = t::reader::<ChatBroadcastEvent>(&w); - - d.dispatch(&w); - w.maintain(); - - let channel = w.fetch::<EventChannel<ChatBroadcastEvent>>(); - - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - assert_eq!(events.len(), 1); - } - - #[test] - fn test_chat_broadcast_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - let player2 = t::add_player(&mut w); - - let event = ChatBroadcastEvent { - message: String::from("test"), - }; - - t::trigger_event(&w, event); - - d.dispatch(&w); - w.maintain(); - - t::assert_packet_received(&player, PacketType::ChatMessageClientbound); - let packet = t::assert_packet_received(&player2, PacketType::ChatMessageClientbound); - let packet = cast_packet::<ChatMessageClientbound>(&*packet); - assert_eq!(packet.json_data, String::from("test")); - } -} diff --git a/server/src/player/digging.rs b/server/src/player/digging.rs deleted file mode 100644 index 6b1d51466..000000000 --- a/server/src/player/digging.rs +++ /dev/null @@ -1,817 +0,0 @@ -//! This module handles the monolithic Player Digging packet. -//! -//! The packet's name is rather misleading, as it is also sent -//! for completely unrelated actions, including eating, shooting bows, -//! swapping items out the the offhand, and dropping items. - -use specs::{Entity, LazyUpdate, Read, ReadStorage, ReaderId, System, World, Write, WriteStorage}; - -use feather_core::network::cast_packet; -use feather_core::network::packet::implementation::{ - BlockChange, PlayerDigging, PlayerDiggingStatus, -}; -use feather_core::network::packet::PacketType; -use feather_core::world::block::{Block, BlockExt}; -use feather_core::world::ChunkMap; -use feather_core::{Gamemode, Item, Position}; - -use crate::blocks::{BlockUpdateCause, BlockUpdateEvent}; -use crate::disconnect_player; -use crate::entity::{PlayerComponent, PositionComponent, ShootArrowEvent}; -use crate::network::PacketQueue; -use crate::player::{InventoryComponent, InventoryUpdateEvent}; -use crate::util::Util; -use feather_core::inventory::{ItemStack, SlotIndex, SLOT_HOTBAR_OFFSET, SLOT_OFFHAND}; -use shrev::EventChannel; -use specs::SystemData; - -/// Event triggered when a player drops an item. -/// -/// Before this event is triggered, the item -/// is removed from the player's inventory. -#[derive(Debug, Clone)] -pub struct PlayerItemDropEvent { - /// The slot from which the item was dropped, - /// if known. - pub slot: Option<SlotIndex>, - /// The item stack which was dropped. - pub stack: ItemStack, - /// The player who dropped the item. - pub player: Entity, -} - -/// System responsible for polling for PlayerDigging -/// packets and writing the corresponding events. -pub struct PlayerDiggingSystem; - -impl<'a> System<'a> for PlayerDiggingSystem { - type SystemData = ( - WriteStorage<'a, InventoryComponent>, - ReadStorage<'a, PlayerComponent>, // For gamemodes - ReadStorage<'a, PositionComponent>, - Write<'a, EventChannel<BlockUpdateEvent>>, - Write<'a, EventChannel<PlayerItemDropEvent>>, - Write<'a, EventChannel<InventoryUpdateEvent>>, - Write<'a, EventChannel<ShootArrowEvent>>, - Write<'a, ChunkMap>, - Read<'a, PacketQueue>, - Read<'a, LazyUpdate>, - ); - - fn run(&mut self, data: Self::SystemData) { - use PlayerDiggingStatus::*; - - let ( - mut inventories, - players, - positions, - mut block_breaks, - mut item_drops, - mut inventory_updates, - mut shoot_arrow_events, - mut chunk_map, - packet_queue, - lazy, - ) = data; - - let packets = packet_queue.for_packet(PacketType::PlayerDigging); - - for (player, packet) in packets { - let packet = cast_packet::<PlayerDigging>(&*packet); - - match packet.status { - StartedDigging | FinishedDigging | CancelledDigging => handle_digging( - packet, - players.get(player).unwrap(), - inventories.get(player).unwrap().item_in_main_hand(), - player, - &mut block_breaks, - &mut chunk_map, - &lazy, - ), - DropItem | DropItemStack => handle_drop_item_stack( - packet, - player, - &mut inventory_updates, - &mut item_drops, - inventories.get_mut(player).unwrap(), - ), - ConsumeItem => handle_consume_item( - packet, - players.get(player).unwrap(), - player, - inventories.get_mut(player).unwrap(), - &mut inventory_updates, - positions.get(player).unwrap().current, - &mut shoot_arrow_events, - ), - status => warn!("Unhandled Player Digging status {:?}", status), - } - } - } -} - -fn handle_digging( - packet: &PlayerDigging, - player: &PlayerComponent, - item_in_main_hand: Option<&ItemStack>, - entity: Entity, - events: &mut EventChannel<BlockUpdateEvent>, - chunk_map: &mut ChunkMap, - lazy: &LazyUpdate, -) { - // Return early if needed - match packet.status { - PlayerDiggingStatus::StartedDigging => { - if player.gamemode != Gamemode::Creative { - return; - } - } - PlayerDiggingStatus::CancelledDigging => return, - _ => (), - } - - // Don't break block if player is holding a sword in creative mode. - if player.gamemode == Gamemode::Creative { - if let Some(item_in_main_hand) = item_in_main_hand { - match item_in_main_hand.ty { - Item::WoodenSword - | Item::StoneSword - | Item::GoldenSword - | Item::IronSword - | Item::DiamondSword => return, - _ => (), - } - } - } - - let old = chunk_map.block_at(packet.location); - - if chunk_map.set_block_at(packet.location, Block::Air).is_err() { - disconnect_player( - entity, - "Attempted to break block in unloaded chunk".to_string(), - lazy, - ); - return; - } - - let event = BlockUpdateEvent { - cause: BlockUpdateCause::Player(entity), - pos: packet.location, - old_block: old.unwrap(), // We checked that the location was valid above - new_block: Block::Air, - }; - - events.single_write(event); -} - -fn handle_drop_item_stack( - packet: &PlayerDigging, - entity: Entity, - inventory_updates: &mut EventChannel<InventoryUpdateEvent>, - item_drops: &mut EventChannel<PlayerItemDropEvent>, - inventory: &mut InventoryComponent, -) { - assert!( - packet.status == PlayerDiggingStatus::DropItem - || packet.status == PlayerDiggingStatus::DropItemStack - ); - - let slot = inventory.held_item + SLOT_HOTBAR_OFFSET; - - let stack = { - if let Some(item) = inventory.item_at(slot) { - item.clone() - } else { - // Silently fail - no item stack to drop - return; - } - }; - - let amnt = match packet.status { - PlayerDiggingStatus::DropItem => { - if stack.amount == 0 { - inventory.clear_item_at(slot); - 0 - } else if stack.amount == 1 { - inventory.clear_item_at(slot); - 1 - } else { - inventory.set_item_at(slot, ItemStack::new(stack.ty, stack.amount - 1)); - 1 - } - } - PlayerDiggingStatus::DropItemStack => { - inventory.clear_item_at(slot); - stack.amount - } - _ => unreachable!(), // Assertion above - }; - - let inv_update = InventoryUpdateEvent { - slots: smallvec![slot], - player: entity, - }; - inventory_updates.single_write(inv_update); - - if amnt != 0 { - let item_drop = PlayerItemDropEvent { - slot: Some(slot), - stack: ItemStack::new(stack.ty, amnt), - player: entity, - }; - item_drops.single_write(item_drop); - } -} - -/// Handles food consumption and shooting arrows. -fn handle_consume_item( - packet: &PlayerDigging, - player: &PlayerComponent, - entity: Entity, - inventory: &mut InventoryComponent, - inventory_updates: &mut EventChannel<InventoryUpdateEvent>, - position: Position, - shoot_arrow_events: &mut EventChannel<ShootArrowEvent>, -) { - assert_eq!(packet.status, PlayerDiggingStatus::ConsumeItem); - - // TODO: Fallback to off-hand if main-hand is not a consumable - let used_item = inventory.item_in_main_hand(); - - if let Some(item) = used_item { - if item.ty == Item::Bow { - handle_shoot_bow( - player, - entity, - inventory, - inventory_updates, - position, - shoot_arrow_events, - ); - } - // TODO: Food, potions - } -} - -fn handle_shoot_bow( - player: &PlayerComponent, - entity: Entity, - inventory: &mut InventoryComponent, - inventory_updates: &mut EventChannel<InventoryUpdateEvent>, - position: Position, - shoot_arrow_events: &mut EventChannel<ShootArrowEvent>, -) { - let arrow_to_consume: Option<(SlotIndex, ItemStack)> = find_arrow(&inventory); - if player.gamemode == Gamemode::Survival || player.gamemode == Gamemode::Adventure { - // If no arrow was found, don't shoot - let arrow_to_consume = arrow_to_consume.clone(); - if arrow_to_consume.is_none() { - debug!("Tried to shoot bow with no arrows."); - return; - } - - // Consume arrow - let (arrow_slot, arrow_stack) = arrow_to_consume.unwrap(); - let mut arrow_stack: ItemStack = arrow_stack; - arrow_stack.amount -= 1; - - inventory.set_item_at(arrow_slot, arrow_stack); - inventory_updates.single_write(InventoryUpdateEvent { - slots: smallvec![arrow_slot], - player: entity, - }); - } - - let arrow_type: Item = match arrow_to_consume { - None => Item::Arrow, // Default to generic arrow in creative mode with none in inventory - Some((_, arrow_stack)) => arrow_stack.ty, - }; - - shoot_arrow_events.single_write(ShootArrowEvent { - shooter: Some(entity), - position, - arrow_type, - critical: false, // TODO: Determine critical based on how long bow was pulled back - }); -} - -fn find_arrow(inventory: &InventoryComponent) -> Option<(SlotIndex, ItemStack)> { - // Order of priority is: off-hand, hotbar (0 to 8), rest of inventory - - if let Some(offhand) = inventory.item_at(SLOT_OFFHAND) { - if is_arrow_item(offhand.ty) { - return Some((SLOT_OFFHAND, offhand.clone())); - } - } - - for hotbar_slot in 0..9 { - if let Some(hotbar_stack) = inventory.item_at(SLOT_HOTBAR_OFFSET + hotbar_slot) { - if is_arrow_item(hotbar_stack.ty) { - return Some((SLOT_HOTBAR_OFFSET + hotbar_slot, hotbar_stack.clone())); - } - } - } - - for inv_slot in 9..=35 { - if let Some(inv_stack) = inventory.item_at(inv_slot) { - if is_arrow_item(inv_stack.ty) { - return Some((inv_slot, inv_stack.clone())); - } - } - } - None -} - -fn is_arrow_item(item: Item) -> bool { - match item { - Item::Arrow | Item::SpectralArrow | Item::TippedArrow => true, - _ => false, - } -} - -/// System for broadcasting block update -/// events to all clients. -/// -/// This system listens to `BlockUpdateEvent`s. -#[derive(Default)] -pub struct BlockUpdateBroadcastSystem { - reader: Option<ReaderId<BlockUpdateEvent>>, -} - -impl<'a> System<'a> for BlockUpdateBroadcastSystem { - type SystemData = (Read<'a, EventChannel<BlockUpdateEvent>>, Read<'a, Util>); - - fn run(&mut self, data: Self::SystemData) { - let (events, util) = data; - - // Process events - for event in events.read(&mut self.reader.as_mut().unwrap()) { - // Send Block Change packet to every player, - // except for the one that performed the update - // (if any) - let neq = if let BlockUpdateCause::Player(player) = event.cause { - Some(player) - } else { - None - }; - - let packet = BlockChange::new(event.pos, i32::from(event.new_block.native_state_id())); - util.broadcast_chunk_update(event.pos.chunk_pos(), packet, neq); - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader()); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::blocks::BlockUpdateEvent; - use crate::testframework as t; - use feather_core::item::Item; - use feather_core::world::chunk::Chunk; - use feather_core::world::{BlockPosition, ChunkPosition}; - use specs::WorldExt; - - #[test] - fn test_started_digging() { - let (mut w, mut d) = t::init_world(); - - let cpos = ChunkPosition::new(0, 0); - let bpos = BlockPosition::new(0, 0, 0); - let mut chunk = Chunk::new(cpos); - chunk.set_block_at(0, 0, 0, Block::Stone); - w.fetch_mut::<ChunkMap>().set_chunk_at(cpos, chunk); - - let mut event_reader = t::reader(&w); - - // Creative mode - - let player = t::add_player(&mut w); - - let packet = PlayerDigging::new(PlayerDiggingStatus::StartedDigging, bpos, 0); - - t::receive_packet(&player, &w, packet.clone()); - - d.dispatch(&w); - w.maintain(); - - t::assert_not_disconnected(&player); - - { - let mut chunk_map = w.fetch_mut::<ChunkMap>(); - - assert_eq!(chunk_map.block_at(bpos).unwrap(), Block::Air); - - chunk_map.set_block_at(bpos, Block::Stone).unwrap(); - - let channel = w.fetch_mut::<EventChannel<BlockUpdateEvent>>(); - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - assert_eq!(events.len(), 1); - - let first = events.first().unwrap(); - assert_eq!(first.old_block, Block::Stone); - assert_eq!(first.new_block, Block::Air); - assert_eq!(first.cause, BlockUpdateCause::Player(player.entity)); - assert_eq!(first.pos, bpos); - } - - // Survival mode - let player = t::add_player(&mut w); - w.write_component::<PlayerComponent>() - .get_mut(player.entity) - .unwrap() - .gamemode = Gamemode::Survival; - - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_not_disconnected(&player); - - let chunk_map = w.fetch::<ChunkMap>(); - assert_eq!(chunk_map.block_at(bpos).unwrap(), Block::Stone); - - let channel = w.fetch_mut::<EventChannel<BlockUpdateEvent>>(); - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - assert_eq!(events.len(), 0); - } - - // This should be a no-op. - #[test] - fn test_cancelled_digging() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let mut event_reader = t::reader(&w); - - let packet = PlayerDigging::new( - PlayerDiggingStatus::CancelledDigging, - BlockPosition::default(), - 0, - ); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_not_disconnected(&player); - - let channel = w.fetch::<EventChannel<BlockUpdateEvent>>(); - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - assert!(events.is_empty()); - } - - #[test] - fn test_finished_digging() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - w.write_component::<PlayerComponent>() - .get_mut(player.entity) - .unwrap() - .gamemode = Gamemode::Survival; - - let mut event_reader = t::reader(&w); - - let bpos = BlockPosition::new(0, 0, 0); - let cpos = bpos.chunk_pos(); - - let mut chunk = Chunk::new(cpos); - chunk.set_block_at(0, 0, 0, Block::Stone); - - w.fetch_mut::<ChunkMap>().set_chunk_at(cpos, chunk); - - let packet = PlayerDigging::new(PlayerDiggingStatus::FinishedDigging, bpos, 0); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_not_disconnected(&player); - - let chunk_map = w.fetch::<ChunkMap>(); - - assert_eq!(chunk_map.block_at(bpos).unwrap(), Block::Air); - - let channel = w.fetch_mut::<EventChannel<BlockUpdateEvent>>(); - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - assert_eq!(events.len(), 1); - - let first = events.first().unwrap(); - assert_eq!(first.old_block, Block::Stone); - assert_eq!(first.new_block, Block::Air); - assert_eq!(first.cause, BlockUpdateCause::Player(player.entity)); - assert_eq!(first.pos, bpos); - } - - #[test] - fn test_block_break_in_unloaded_chunk() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let mut event_reader = t::reader(&w); - - let bpos = BlockPosition::new(1000, 25, 1000); - - let packet = PlayerDigging::new(PlayerDiggingStatus::FinishedDigging, bpos, 0); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_disconnected(&player); - - let channel = w.fetch::<EventChannel<BlockUpdateEvent>>(); - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - assert!(events.is_empty()); - } - - #[test] - fn test_drop_item() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let slot = SLOT_HOTBAR_OFFSET; - { - let mut invs = w.write_component::<InventoryComponent>(); - let inv = invs.get_mut(player.entity).unwrap(); - inv.held_item = 0; - inv.set_item_at(slot, ItemStack::new(Item::CookedBeef, 4)); - } - - let mut drop_reader = t::reader(&w); - let mut update_reader = t::reader(&w); - - let packet = PlayerDigging::new(PlayerDiggingStatus::DropItem, BlockPosition::default(), 0); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - let drop_channel = w.fetch::<EventChannel<PlayerItemDropEvent>>(); - let update_channel = w.fetch::<EventChannel<InventoryUpdateEvent>>(); - - // Check that events are correct - let drop_events = drop_channel.read(&mut drop_reader).collect::<Vec<_>>(); - assert_eq!(drop_events.len(), 1); - let first = drop_events.first().unwrap(); - assert_eq!(first.player, player.entity); - assert_eq!(first.slot, Some(slot)); - assert_eq!(first.stack, ItemStack::new(Item::CookedBeef, 1)); // 1 beef was dropped - - let update_events = update_channel.read(&mut update_reader).collect::<Vec<_>>(); - assert_eq!(update_events.len(), 1); - let first = update_events.first().unwrap(); - assert_eq!(first.player, player.entity); - assert_eq!(first.slots.as_slice(), &[slot]); - - // Check that inventory was updated correctly - let invs = w.read_component::<InventoryComponent>(); - let inv = invs.get(player.entity).unwrap(); - assert_eq!( - inv.item_at(slot).unwrap(), - &ItemStack::new(Item::CookedBeef, 3) - ); // 1 was removed - } - - #[test] - fn test_drop_item_no_stack() { - // This should be a no-op. - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let mut drop_reader = t::reader(&w); - let mut update_reader = t::reader(&w); - - let packet = PlayerDigging::new(PlayerDiggingStatus::DropItem, BlockPosition::default(), 0); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_not_disconnected(&player); - - let drop_channel = w.fetch::<EventChannel<PlayerItemDropEvent>>(); - let update_channel = w.fetch::<EventChannel<InventoryUpdateEvent>>(); - - let drop_events = drop_channel.read(&mut drop_reader).collect::<Vec<_>>(); - assert!(drop_events.is_empty()); - let update_events = update_channel.read(&mut update_reader).collect::<Vec<_>>(); - assert!(update_events.is_empty()); - } - - #[test] - fn test_drop_item_stack() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let mut drop_reader = t::reader(&w); - let mut update_reader = t::reader(&w); - - let slot = SLOT_HOTBAR_OFFSET; - let amnt = 32; - { - let mut invs = w.write_component::<InventoryComponent>(); - let inv = invs.get_mut(player.entity).unwrap(); - inv.set_item_at(slot, ItemStack::new(Item::CookedBeef, amnt)); - } - - let packet = PlayerDigging::new( - PlayerDiggingStatus::DropItemStack, - BlockPosition::default(), - 0, - ); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - let drop_channel = w.fetch::<EventChannel<PlayerItemDropEvent>>(); - let update_channel = w.fetch::<EventChannel<InventoryUpdateEvent>>(); - - let update_events = update_channel.read(&mut update_reader).collect::<Vec<_>>(); - assert_eq!(update_events.len(), 1); - let first = update_events.first().unwrap(); - assert_eq!(first.player, player.entity); - assert_eq!(first.slots.as_slice(), &[slot]); - - let drop_events = drop_channel.read(&mut drop_reader).collect::<Vec<_>>(); - assert_eq!(drop_events.len(), 1); - let first = drop_events.first().unwrap(); - assert_eq!(first.player, player.entity); - assert_eq!(first.slot, Some(slot)); - assert_eq!(first.stack, ItemStack::new(Item::CookedBeef, amnt)); - - let invs = w.read_component::<InventoryComponent>(); - let inv = invs.get(player.entity).unwrap(); - assert_eq!(inv.item_at(slot), None); - } - - #[test] - fn test_block_update_broadcast_system() { - let (mut w, mut d) = t::init_world(); - - let player1 = t::add_player(&mut w); - let player2 = t::add_player(&mut w); - - let pos = BlockPosition::default(); - let block = Block::Sand; - - let event = BlockUpdateEvent { - cause: BlockUpdateCause::Player(player1.entity), - pos, - old_block: block, - new_block: Block::Air, - }; - w.fetch_mut::<EventChannel<_>>().single_write(event); - - d.dispatch(&w); - w.maintain(); - - let block_change = t::assert_packet_received(&player2, PacketType::BlockChange); - let block_change = cast_packet::<BlockChange>(&*block_change); - assert_eq!(block_change.location, pos); - assert_eq!( - block_change.block_id, - i32::from(Block::Air.native_state_id()) - ); - - t::assert_packet_not_received(&player1, PacketType::BlockChange); // Don't send update to own player - - // Now handle an event not caused by a player - let event = BlockUpdateEvent { - cause: BlockUpdateCause::Test, - pos, - old_block: block, - new_block: Block::Air, - }; - w.fetch_mut::<EventChannel<_>>().single_write(event); - - d.dispatch(&w); - w.maintain(); - - // Packet should be sent to both players - t::assert_packet_received(&player1, PacketType::BlockChange); - t::assert_packet_received(&player2, PacketType::BlockChange); - } - - #[test] - pub fn test_find_arrow() { - let mut inv = InventoryComponent::new(); - inv.set_item_at( - SLOT_OFFHAND, - ItemStack { - ty: Item::Arrow, - amount: 1, - }, - ); - inv.set_item_at( - SLOT_HOTBAR_OFFSET, - ItemStack { - ty: Item::Arrow, - amount: 1, - }, - ); - inv.set_item_at( - 9, - ItemStack { - ty: Item::Arrow, - amount: 1, - }, - ); - - // 1. Off-hand - let (slot, stack) = find_arrow(&inv).unwrap(); - assert_eq!(slot, SLOT_OFFHAND); - assert_eq!(stack.ty, Item::Arrow); - inv.clear_item_at(SLOT_OFFHAND); - - // 2. Hot-bar - let (slot, stack) = find_arrow(&inv).unwrap(); - assert_eq!(slot, SLOT_HOTBAR_OFFSET); - assert_eq!(stack.ty, Item::Arrow); - inv.clear_item_at(SLOT_HOTBAR_OFFSET); - - // 3. Rest of inventory - let (slot, stack) = find_arrow(&inv).unwrap(); - assert_eq!(slot, 9); - assert_eq!(stack.ty, Item::Arrow); - inv.clear_item_at(9); - - // 4. No arrow found - assert!(find_arrow(&inv).is_none()); - } - - #[test] - pub fn test_shoot_arrow() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let mut shoot_reader = t::reader(&w); - let mut update_reader = t::reader(&w); - - let slot = SLOT_HOTBAR_OFFSET; - let amnt = 32; - { - let mut invs = w.write_component::<InventoryComponent>(); - let inv = invs.get_mut(player.entity).unwrap(); - inv.set_item_at(slot, ItemStack::new(Item::Bow, 1)); - inv.set_item_at(slot + 1, ItemStack::new(Item::Arrow, amnt)); - } - - // Change to survival - w.write_component::<PlayerComponent>() - .insert( - player.entity, - PlayerComponent { - gamemode: Gamemode::Survival, - profile_properties: vec![], - }, - ) - .unwrap(); - - let packet = PlayerDigging::new( - PlayerDiggingStatus::ConsumeItem, - BlockPosition::default(), - 0, - ); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - let shoot_channel = w.fetch::<EventChannel<ShootArrowEvent>>(); - let update_channel = w.fetch::<EventChannel<InventoryUpdateEvent>>(); - - let update_events = update_channel.read(&mut update_reader).collect::<Vec<_>>(); - assert_eq!(update_events.len(), 1); - let first = update_events.first().unwrap(); - assert_eq!(first.player, player.entity); - assert_eq!(first.slots.as_slice(), &[slot + 1]); - - let shoot_events = shoot_channel.read(&mut shoot_reader).collect::<Vec<_>>(); - assert_eq!(shoot_events.len(), 1); - let first = shoot_events.first().unwrap(); - assert_eq!(first.shooter.unwrap(), player.entity); - assert_eq!(first.arrow_type, Item::Arrow); - - // In survival, check if amount of arrow stack decreased. - let invs = w.read_component::<InventoryComponent>(); - let inv = invs.get(player.entity).unwrap(); - assert_eq!(inv.item_at(slot + 1).unwrap().amount, amnt - 1); - } -} diff --git a/server/src/player/init.rs b/server/src/player/init.rs deleted file mode 100644 index a0c4d83aa..000000000 --- a/server/src/player/init.rs +++ /dev/null @@ -1,177 +0,0 @@ -use crate::entity::{ - degrees_to_stops, LastKnownPositionComponent, PacketCreatorComponent, PlayerComponent, - VelocityComponent, -}; -use crate::entity::{Metadata, NamedComponent, PositionComponent}; -use crate::network::PlayerPreJoinEvent; -use crate::player::{ChunkPendingComponent, InventoryComponent, LoadedChunksComponent}; -use crate::prelude::*; -use feather_core::level::LevelData; -use feather_core::packet::SpawnPlayer; -use feather_core::{Gamemode, Packet}; -use hashbrown::HashSet; -use shrev::{EventChannel, ReaderId}; -use specs::{Entity, SystemData, WorldExt}; -use specs::{Read, System, World, WriteStorage}; -use std::path::Path; -use std::sync::Arc; - -/// System for initializing the necessary components -/// when a player joins. -#[derive(Default)] -pub struct PlayerInitSystem { - join_event_reader: Option<ReaderId<PlayerPreJoinEvent>>, -} - -impl<'a> System<'a> for PlayerInitSystem { - type SystemData = ( - Read<'a, EventChannel<PlayerPreJoinEvent>>, - WriteStorage<'a, PlayerComponent>, - WriteStorage<'a, PositionComponent>, - WriteStorage<'a, VelocityComponent>, - WriteStorage<'a, NamedComponent>, - WriteStorage<'a, ChunkPendingComponent>, - WriteStorage<'a, LoadedChunksComponent>, - WriteStorage<'a, InventoryComponent>, - WriteStorage<'a, Metadata>, - WriteStorage<'a, LastKnownPositionComponent>, - WriteStorage<'a, PacketCreatorComponent>, - Read<'a, LevelData>, - Read<'a, Arc<Config>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - join_events, - mut player_comps, - mut positions, - mut velocities, - mut nameds, - mut chunk_pending_comps, - mut loaded_chunk_comps, - mut inventory_comps, - mut metadata, - mut last_positions, - mut packet_creators, - level, - config, - ) = data; - - // Run through events - for event in join_events.read(&mut self.join_event_reader.as_mut().unwrap()) { - // Load player data - let uuid = event.uuid; - // If this is a new player, set gamemode to server's default (config) - let default_gamemode = &config.server.default_gamemode.clone(); - let world_dir = Path::new(&config.world.name); - - debug!("Loading player data for UUID {}", uuid); - let (gamemode, pos, velocity, inventory_slots) = - match feather_core::player_data::load_player_data(world_dir, uuid) { - Ok(data) => ( - Gamemode::from_id(data.gamemode as u8), - data.entity.read_position(), - data.entity.read_velocity(), - data.inventory, - ), - Err(_) => ( - Gamemode::from_string(default_gamemode.as_str()), - None, // Invalid position will default to world spawn - None, - vec![], // Empty inventory - ), - }; - - let player_comp = PlayerComponent { - profile_properties: event.profile_properties.clone(), - gamemode, - }; - player_comps.insert(event.player, player_comp).unwrap(); - - let spawn_pos = pos.unwrap_or(position!( - f64::from(level.spawn_x), - f64::from(level.spawn_y), - f64::from(level.spawn_z) - )); - let position = PositionComponent { - current: spawn_pos, - previous: spawn_pos, - }; - positions.insert(event.player, position).unwrap(); - - let velocity = VelocityComponent(velocity.unwrap_or_else(|| glm::vec3(0.0, 0.0, 0.0))); - velocities.insert(event.player, velocity).unwrap(); - - let named = NamedComponent { - display_name: event.username.clone(), - uuid: event.uuid, - }; - nameds.insert(event.player, named).unwrap(); - - let chunk_pending_comp = ChunkPendingComponent { - pending: HashSet::new(), - }; - chunk_pending_comps - .insert(event.player, chunk_pending_comp) - .unwrap(); - - let loaded_chunk_comp = LoadedChunksComponent::default(); - loaded_chunk_comps - .insert(event.player, loaded_chunk_comp) - .unwrap(); - - let mut inventory_comp = InventoryComponent::new(); - for slot in inventory_slots { - let slot_index = slot.convert_index(); - if let Some(slot_index) = slot_index { - inventory_comp.set_item_at(slot_index, slot.to_stack()); - } - } - inventory_comps - .insert(event.player, inventory_comp) - .unwrap(); - - let last_position = LastKnownPositionComponent::default(); - last_positions.insert(event.player, last_position).unwrap(); - - let meta = Metadata::Player(crate::entity::metadata::Player::default()); - metadata.insert(event.player, meta).unwrap(); - - let packet_creator = PacketCreatorComponent(&create_packet); - packet_creators - .insert(event.player, packet_creator) - .unwrap(); - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.join_event_reader = Some( - world - .fetch_mut::<EventChannel<PlayerPreJoinEvent>>() - .register_reader(), - ); - } -} - -pub fn create_packet(world: &World, entity: Entity) -> Box<dyn Packet> { - let positions = world.read_component::<PositionComponent>(); - let nameds = world.read_component::<NamedComponent>(); - let metas = world.read_component::<Metadata>(); - - let position = positions.get(entity).unwrap(); - - let packet = SpawnPlayer { - entity_id: entity.id() as i32, - player_uuid: nameds.get(entity).unwrap().uuid, - x: position.current.x, - y: position.current.y, - z: position.current.z, - yaw: degrees_to_stops(position.current.yaw), - pitch: degrees_to_stops(position.current.pitch), - metadata: metas.get(entity).unwrap().to_full_raw_metadata(), - }; - - Box::new(packet) -} diff --git a/server/src/player/inventory.rs b/server/src/player/inventory.rs deleted file mode 100644 index cfed37950..000000000 --- a/server/src/player/inventory.rs +++ /dev/null @@ -1,759 +0,0 @@ -use crate::disconnect_player; -use crate::entity::{EntitySendEvent, PlayerComponent}; -use crate::network::{send_packet_to_player, NetworkComponent, PacketQueue}; -use crate::player::digging::PlayerItemDropEvent; -use crate::util::Util; -use feather_core::inventory::{ - Inventory, InventoryType, SlotIndex, HOTBAR_SIZE, SLOT_ARMOR_CHEST, SLOT_ARMOR_FEET, - SLOT_ARMOR_HEAD, SLOT_ARMOR_LEGS, SLOT_HOTBAR_OFFSET, SLOT_OFFHAND, -}; -use feather_core::network::cast_packet; -use feather_core::network::packet::implementation::{ - CreativeInventoryAction, EntityEquipment, HeldItemChangeServerbound, SetSlot, -}; -use feather_core::network::packet::PacketType; -use feather_core::{Gamemode, ItemStack}; -use num_traits::ToPrimitive; -use shrev::EventChannel; -use smallvec::SmallVec; -use specs::{Component, LazyUpdate, Read, ReadStorage, ReaderId, World, WriteStorage}; -use specs::{DenseVecStorage, SystemData}; -use specs::{Entity, System, Write}; -use std::ops::{Deref, DerefMut}; - -/// Component for storing a player's inventory. -#[derive(Clone, Debug)] -pub struct InventoryComponent { - pub inventory: Inventory, - /// The player's held item. - /// This is stored as an index in the range 0..9. - pub held_item: SlotIndex, -} - -impl InventoryComponent { - pub fn new() -> Self { - Self { - inventory: Inventory::new(InventoryType::Player, 46), - held_item: 0, - } - } - - /// Returns the item in this inventory's - /// main hand. - pub fn item_in_main_hand(&self) -> Option<&ItemStack> { - self.inventory.item_at(SLOT_HOTBAR_OFFSET + self.held_item) - } - - /// Sets the item in this inventory's main hand. - pub fn set_item_in_main_hand(&mut self, item: ItemStack) { - self.inventory - .set_item_at(SLOT_HOTBAR_OFFSET + self.held_item, item); - } -} - -impl Default for InventoryComponent { - fn default() -> Self { - Self::new() - } -} - -impl Deref for InventoryComponent { - type Target = Inventory; - - fn deref(&self) -> &Self::Target { - &self.inventory - } -} - -impl DerefMut for InventoryComponent { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inventory - } -} - -impl Component for InventoryComponent { - type Storage = DenseVecStorage<Self>; -} - -/// An equipment slot, with variants -/// listed in the order of the Entity Equipment -/// IDs to allow for easy conversion using `ToPrimitive`/`FromPrimitive`. -#[derive(Debug, Clone, Copy, ToPrimitive, FromPrimitive, PartialEq, Eq, Hash)] -pub enum Equipment { - MainHand, - OffHand, - Boots, - Leggings, - Chestplate, - Helmet, -} - -impl Equipment { - pub fn from_slot_index(index: SlotIndex) -> Option<Self> { - match index { - SLOT_OFFHAND => Some(Equipment::OffHand), - SLOT_ARMOR_FEET => Some(Equipment::Boots), - SLOT_ARMOR_LEGS => Some(Equipment::Leggings), - SLOT_ARMOR_CHEST => Some(Equipment::Chestplate), - SLOT_ARMOR_HEAD => Some(Equipment::Helmet), - _ => None, - } - } - - pub fn slot_index(self, held_item: SlotIndex) -> SlotIndex { - match self { - Equipment::MainHand => held_item + SLOT_HOTBAR_OFFSET, - Equipment::OffHand => SLOT_OFFHAND, - Equipment::Boots => SLOT_ARMOR_FEET, - Equipment::Leggings => SLOT_ARMOR_LEGS, - Equipment::Chestplate => SLOT_ARMOR_CHEST, - Equipment::Helmet => SLOT_ARMOR_HEAD, - } - } -} - -/// Event which is triggered when a player -/// updates their inventory. -/// -/// This event could also be triggered when the player -/// changes their held item. -#[derive(Debug, Clone)] -pub struct InventoryUpdateEvent { - /// The slot(s) affected by the update. - /// - /// Multiple slots could be affected when, for - /// example, a player uses the "drag" inventory interaction. - pub slots: SmallVec<[SlotIndex; 2]>, - /// The player owning the updated inventory. - pub player: Entity, -} - -/// System for handling Creative Inventory Action packets. -pub struct CreativeInventorySystem; - -impl<'a> System<'a> for CreativeInventorySystem { - type SystemData = ( - WriteStorage<'a, InventoryComponent>, - ReadStorage<'a, PlayerComponent>, - Write<'a, EventChannel<InventoryUpdateEvent>>, - Write<'a, EventChannel<PlayerItemDropEvent>>, - Read<'a, PacketQueue>, - Read<'a, LazyUpdate>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (mut inventories, players, mut update_events, mut drop_events, packet_queue, lazy) = - data; - - let packets = packet_queue.for_packet(PacketType::CreativeInventoryAction); - - for (player, packet) in packets { - // Creative Inventory Action can only be used in creative - // mode. - let player_comp = players.get(player).unwrap(); - if player_comp.gamemode != Gamemode::Creative { - disconnect_player( - player, - "Attempted to use Creative Inventory Action while not in creative mode" - .to_string(), - &lazy, - ); - continue; - } - - let packet = cast_packet::<CreativeInventoryAction>(&*packet); - - let inventory = inventories.get_mut(player).unwrap(); - - // Slot -1 means that the user clicked outside the window, - // dropping the item. - if packet.slot == -1 { - match &packet.clicked_item { - Some(stack) => { - let event = PlayerItemDropEvent { - slot: None, - stack: stack.clone(), - player, - }; - drop_events.single_write(event); - - // No need to update inventory - continue; - } - None => (), - } - } - - if packet.slot >= inventory.slot_count() as i16 || packet.slot < -1 { - disconnect_player(player, "Slot index out of bounds".to_string(), &lazy); - continue; - } - - match packet.clicked_item.as_ref() { - Some(item) => { - inventory.set_item_at(packet.slot as usize, item.clone()); - } - None => { - inventory.clear_item_at(packet.slot as usize); - } - } - - // Trigger inventory update event - let event = InventoryUpdateEvent { - slots: smallvec![packet.slot as usize], - player, - }; - update_events.single_write(event); - } - } -} - -/// System for handling Held Item Change packets. -pub struct HeldItemChangeSystem; - -impl<'a> System<'a> for HeldItemChangeSystem { - type SystemData = ( - WriteStorage<'a, InventoryComponent>, - Write<'a, EventChannel<InventoryUpdateEvent>>, - Read<'a, PacketQueue>, - Read<'a, LazyUpdate>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (mut inventories, mut events, packet_queue, lazy) = data; - - let packets = packet_queue.for_packet(PacketType::HeldItemChangeServerbound); - - for (player, packet) in packets { - let packet = cast_packet::<HeldItemChangeServerbound>(&*packet); - - if packet.slot as usize >= HOTBAR_SIZE { - disconnect_player(player, "Hotbar index out of bounds".to_string(), &lazy); - continue; - } - - let inventory = inventories.get_mut(player).unwrap(); - inventory.held_item = packet.slot as usize; - - // Trigger event - let event = InventoryUpdateEvent { - slots: smallvec![inventory.held_item as usize + SLOT_HOTBAR_OFFSET], - player, - }; - events.single_write(event); - } - } -} - -/// System for broadcasting equipment updates. -#[derive(Default)] -pub struct HeldItemBroadcastSystem { - reader: Option<ReaderId<InventoryUpdateEvent>>, -} - -impl<'a> System<'a> for HeldItemBroadcastSystem { - type SystemData = ( - ReadStorage<'a, InventoryComponent>, - Read<'a, EventChannel<InventoryUpdateEvent>>, - Read<'a, Util>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (inventories, events, util) = data; - - for event in events.read(&mut self.reader.as_mut().unwrap()) { - let inv = inventories.get(event.player).unwrap(); - - for slot in &event.slots { - // Skip this slot if it is not an equipment update. - if let Ok(equipment) = is_equipment_update(&inv, *slot) { - let slot = equipment.slot_index(inv.held_item); - let item = inv.item_at(slot).cloned(); - - let packet = EntityEquipment::new( - event.player.id() as i32, - equipment.to_i32().unwrap(), - item, - ); - - util.broadcast_entity_update(event.player, packet, Some(event.player)); - } - } - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some( - world - .fetch_mut::<EventChannel<InventoryUpdateEvent>>() - .register_reader(), - ); - } -} - -/// System which listens to `EntitySendEvent`s and -/// sends entity equipment alongside. -#[derive(Default)] -pub struct EquipmentSendSystem { - reader: Option<ReaderId<EntitySendEvent>>, -} - -impl<'a> System<'a> for EquipmentSendSystem { - type SystemData = ( - ReadStorage<'a, InventoryComponent>, - ReadStorage<'a, NetworkComponent>, - Read<'a, EventChannel<EntitySendEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (inventories, networks, send_events) = data; - - for event in send_events.read(&mut self.reader.as_mut().unwrap()) { - let network = networks.get(event.player).unwrap(); - let inventory = match inventories.get(event.entity) { - Some(inv) => inv, - None => continue, - }; - - let equipments = [ - Equipment::MainHand, - Equipment::Boots, - Equipment::Leggings, - Equipment::Chestplate, - Equipment::Helmet, - Equipment::OffHand, - ]; - - for equipment in equipments.iter() { - let item = { - let slot = equipment.slot_index(inventory.held_item); - inventory.item_at(slot).cloned() - }; - - let equipment_slot = equipment.to_i32().unwrap(); - - let packet = EntityEquipment::new(event.entity.id() as i32, equipment_slot, item); - send_packet_to_player(network, packet); - } - } - } - - fn setup(&mut self, world: &mut World) { - Self::SystemData::setup(world); - - self.reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader()); - } -} - -/// System for sending the Set Slot packet -/// when a player's inventory is updated. -#[derive(Default)] -pub struct SetSlotSystem { - reader: Option<ReaderId<InventoryUpdateEvent>>, -} - -impl<'a> System<'a> for SetSlotSystem { - type SystemData = ( - ReadStorage<'a, InventoryComponent>, - ReadStorage<'a, NetworkComponent>, - Read<'a, EventChannel<InventoryUpdateEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (inventories, networks, events) = data; - - for event in events.read(self.reader.as_mut().unwrap()) { - let inv = inventories.get(event.player).unwrap(); - let network = networks.get(event.player).unwrap(); - - for slot in &event.slots { - let packet = SetSlot { - window_id: 0, - slot: *slot as i16, - slot_data: inv.item_at(*slot as usize).cloned(), - }; - - send_packet_to_player(&network, packet); - } - } - } - - setup_impl!(reader); -} - -/// Returns whether the given update to an inventory -/// is an equipment update. -fn is_equipment_update(inv: &InventoryComponent, slot: SlotIndex) -> Result<Equipment, ()> { - if slot >= SLOT_HOTBAR_OFFSET && slot - SLOT_HOTBAR_OFFSET == inv.held_item { - Ok(Equipment::MainHand) - } else if let Some(equipment) = Equipment::from_slot_index(slot) { - Ok(equipment) - } else { - Err(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::testframework as t; - use feather_core::inventory::{ItemStack, SLOT_ENTITY_EQUIPMENT_MAIN_HAND}; - use feather_core::item::Item; - use specs::WorldExt; - - #[test] - fn test_creative_inventory_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let packet = CreativeInventoryAction::new( - SLOT_HOTBAR_OFFSET as i16, - Some(ItemStack::new(Item::IronSword, 1)), - ); - - t::receive_packet(&player, &w, packet); - - let mut update_reader = t::reader(&w); - let mut drop_reader = t::reader(&w); - - d.dispatch(&w); - w.maintain(); - - t::assert_not_disconnected(&player); - - let inv_storage = w.read_component::<InventoryComponent>(); - let inv = inv_storage.get(player.entity).unwrap(); - assert_eq!( - inv.item_at(SLOT_HOTBAR_OFFSET).unwrap(), - &ItemStack::new(Item::IronSword, 1) - ); - - // Confirm that event was triggered - { - let channel = w.fetch::<EventChannel<InventoryUpdateEvent>>(); - let events = channel.read(&mut update_reader).collect::<Vec<_>>(); - assert_eq!(events.len(), 1); - let first = events.first().unwrap(); - assert_eq!(first.player, player.entity); - assert_eq!(first.slots.as_slice(), &[SLOT_HOTBAR_OFFSET]); - - assert!(w - .fetch::<EventChannel<PlayerItemDropEvent>>() - .read(&mut drop_reader) - .next() - .is_none()); - } - - drop(inv_storage); - - let packet = CreativeInventoryAction::new(0, None); - - t::receive_packet(&player, &w, packet.clone()); - - d.dispatch(&w); - w.maintain(); - - t::assert_not_disconnected(&player); - - let inv_storage = w.read_component::<InventoryComponent>(); - let inv = inv_storage.get(player.entity).unwrap(); - assert_eq!(inv.item_at(0), None); - - drop(inv_storage); - - // Now with a survival mode player... - w.write_component::<PlayerComponent>() - .get_mut(player.entity) - .unwrap() - .gamemode = Gamemode::Survival; - - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_disconnected(&player); - } - - #[test] - fn test_creative_inventory_slot_out_of_bounds() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let packet = CreativeInventoryAction::new(46, Some(ItemStack::new(Item::IronSword, 1))); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_disconnected(&player); - } - - #[test] - fn test_creative_inventory_armor() { - let equipments = [ - Equipment::OffHand, - Equipment::Boots, - Equipment::Leggings, - Equipment::Chestplate, - Equipment::Helmet, - ]; - - for equipment in equipments.iter() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let mut event_reader = t::reader(&w); - - let packet = CreativeInventoryAction::new( - equipment.slot_index(0) as i16, - Some(ItemStack::new(Item::IronSword, 1)), - ); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - let ch = w.fetch::<EventChannel<InventoryUpdateEvent>>(); - let events = ch.read(&mut event_reader).collect::<Vec<_>>(); - - assert_eq!(events.len(), 1); - let first = events.first().unwrap(); - - assert_eq!(first.slots.as_slice(), &[equipment.slot_index(0)]); - assert_eq!(first.player, player.entity); - } - } - - #[test] - fn test_creative_inventory_system_drop_item() { - // Drop item - slot index -1 - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let stack = ItemStack::new(Item::CookedBeef, 1); - - let mut drop_reader = t::reader(&w); - let mut update_reader = t::reader(&w); - - let packet = CreativeInventoryAction { - slot: -1, - clicked_item: Some(stack.clone()), - }; - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_not_disconnected(&player); - - let channel = w.fetch::<EventChannel<InventoryUpdateEvent>>(); - let events = channel.read(&mut update_reader).collect::<Vec<_>>(); - assert!(events.is_empty()); - - let channel = w.fetch::<EventChannel<PlayerItemDropEvent>>(); - let events = channel.read(&mut drop_reader).collect::<Vec<_>>(); - - assert_eq!(events.len(), 1); - let first = events.first().unwrap(); - assert_eq!(first.stack, stack); - assert_eq!(first.player, player.entity); - assert_eq!(first.slot, None); - } - - #[test] - fn test_held_item_change_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let slot = 4; - - let mut event_reader = t::reader(&w); - - let packet = HeldItemChangeServerbound::new(slot); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - let channel = w.fetch::<EventChannel<InventoryUpdateEvent>>(); - let events = channel.read(&mut event_reader).collect::<Vec<_>>(); - - assert_eq!(events.len(), 1); - - let first = events.first().unwrap(); - assert_eq!(first.player, player.entity); - assert_eq!( - first.slots.as_slice(), - &[slot as usize + SLOT_HOTBAR_OFFSET] - ); - - let inventories = w.read_component::<InventoryComponent>(); - let inv = inventories.get(player.entity).unwrap(); - - assert_eq!(inv.held_item, slot as usize); - } - - #[test] - fn test_held_item_change_system_out_of_bounds() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let slot = 9; - - let packet = HeldItemChangeServerbound::new(slot); - t::receive_packet(&player, &w, packet); - - d.dispatch(&w); - w.maintain(); - - t::assert_disconnected(&player); // Slot out of bounds - } - - #[test] - fn test_held_item_broadcast_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - let player2 = t::add_player(&mut w); - - { - let mut invs = w.write_component::<InventoryComponent>(); - let inv = invs.get_mut(player.entity).unwrap(); - inv.held_item = 0; - inv.set_item_at(SLOT_HOTBAR_OFFSET, ItemStack::new(Item::IronSword, 1)); - } - - let event = InventoryUpdateEvent { - player: player.entity, - slots: smallvec![SLOT_HOTBAR_OFFSET], - }; - - w.fetch_mut::<EventChannel<InventoryUpdateEvent>>() - .single_write(event); - - d.dispatch(&w); - w.maintain(); - - let packet = t::assert_packet_received(&player2, PacketType::EntityEquipment); - - let packet = cast_packet::<EntityEquipment>(&*packet); - assert_eq!(packet.slot, SLOT_ENTITY_EQUIPMENT_MAIN_HAND as i32); - assert_eq!(packet.entity_id, player.entity.id() as i32); - assert_eq!(packet.item, Some(ItemStack::new(Item::IronSword, 1))); - - t::assert_packet_not_received(&player, PacketType::EntityEquipment); - } - - #[test] - fn test_equipment_send_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - let player2 = t::add_player(&mut w); - - let event = EntitySendEvent { - player: player.entity, - entity: player2.entity, - }; - - w.fetch_mut::<EventChannel<_>>().single_write(event); - - { - let mut invs = w.write_component::<InventoryComponent>(); - let inv = invs.get_mut(player2.entity).unwrap(); - - inv.held_item = 1; - inv.set_item_at(SLOT_HOTBAR_OFFSET + 1, ItemStack::new(Item::IronSword, 1)); - inv.set_item_at(SLOT_ARMOR_HEAD, ItemStack::new(Item::DiamondHelmet, 1)); - } - - d.dispatch(&w); - w.maintain(); - - let packets = t::received_packets(&player, None); - - let packets = packets - .into_iter() - .filter(|packet| packet.ty() == PacketType::EntityEquipment) - .collect::<Vec<_>>(); - - assert_eq!(packets.len(), 6); - - for packet in packets { - let packet = cast_packet::<EntityEquipment>(&*packet); - assert_eq!(packet.entity_id, player2.entity.id() as i32); - } - } - - #[test] - fn test_set_slot_system() { - let (mut w, mut d) = t::builder().with(SetSlotSystem::default(), "").build(); - - let player = t::add_player(&mut w); - let stack = ItemStack::new(Item::EnderPearl, 8); - { - let mut inventories = w.write_component::<InventoryComponent>(); - inventories - .get_mut(player.entity) - .unwrap() - .set_item_at(0, stack.clone()); - - let event = InventoryUpdateEvent { - slots: smallvec![0], - player: player.entity, - }; - t::trigger_event(&w, event); - } - - d.dispatch(&w); - w.maintain(); - - let packet = t::assert_packet_received(&player, PacketType::SetSlot); - let packet = cast_packet::<SetSlot>(&*packet); - - assert_eq!(packet.window_id, 0); - assert_eq!(packet.slot_data, Some(stack)); - assert_eq!(packet.slot, 0); - } - - #[test] - fn test_is_equipment_update() { - let mut inv = InventoryComponent::default(); - inv.held_item = 0; - - assert!(is_equipment_update(&inv, 21).is_err()); - assert_eq!( - is_equipment_update(&inv, SLOT_HOTBAR_OFFSET), - Ok(Equipment::MainHand) - ); - assert_eq!( - is_equipment_update(&inv, SLOT_ARMOR_HEAD), - Ok(Equipment::Helmet) - ); - assert_eq!( - is_equipment_update(&inv, SLOT_ARMOR_CHEST), - Ok(Equipment::Chestplate) - ); - assert_eq!( - is_equipment_update(&inv, SLOT_ARMOR_LEGS), - Ok(Equipment::Leggings) - ); - assert_eq!( - is_equipment_update(&inv, SLOT_ARMOR_FEET), - Ok(Equipment::Boots) - ); - assert_eq!( - is_equipment_update(&inv, SLOT_OFFHAND), - Ok(Equipment::OffHand) - ); - } -} diff --git a/server/src/player/mod.rs b/server/src/player/mod.rs deleted file mode 100644 index 2cdeeaee6..000000000 --- a/server/src/player/mod.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! This module provides systems and components -//! relating to players, including player movement -//! and inventory handling. - -/// Module for handling player animation broadcasting -/// (e.g. when a player swings their arm). -mod animation; -/// Module for broadcasting when a player joins and leaves. -mod broadcast; -/// Module for handling and broadcasting chat messages. -mod chat; -/// Module for handling the Player Digging packet. -mod digging; -/// Module for initializing the necessary components -/// when a player joins. -mod init; -/// Module for handling player inventory. -mod inventory; -/// Module for handling player movement packets. -/// Also handles loading/unloading chunks when necessary. -mod movement; -/// Module for handling player block placements. -mod placement; -mod resource_pack; -mod save; -mod view; - -pub use broadcast::PlayerDisconnectEvent; -pub use init::create_packet; - -pub use movement::{ - send_chunk_to_player, ChunkCrossSystem, ChunkPendingComponent, LoadedChunksComponent, -}; - -pub use animation::PlayerAnimationEvent; - -pub use digging::PlayerItemDropEvent; -pub use inventory::{InventoryComponent, InventoryUpdateEvent}; -pub use save::save_player_data; - -use crate::player::inventory::SetSlotSystem; -use crate::player::placement::BlockPlacementSystem; -use crate::player::save::PlayerDataSaveSystem; -use crate::player::view::ViewUpdateSystem; -use crate::systems::{ - ANIMATION_BROADCAST, BLOCK_BREAK_BROADCAST, BLOCK_PLACEMENT, CHAT_BROADCAST, CHUNK_CROSS, - CHUNK_SEND, CLIENT_CHUNK_UNLOAD, CREATIVE_INVENTORY, DISCONNECT_BROADCAST, EQUIPMENT_SEND, - HELD_ITEM_BROADCAST, HELD_ITEM_CHANGE, JOIN_BROADCAST, NETWORK, PLAYER_ANIMATION, PLAYER_CHAT, - PLAYER_DATA_SAVE, PLAYER_DIGGING, PLAYER_INIT, PLAYER_MOVEMENT, RESOURCE_PACK_SEND, SET_SLOT, - VIEW_UPDATE, -}; -use animation::{AnimationBroadcastSystem, PlayerAnimationSystem}; -use broadcast::{DisconnectBroadcastSystem, JoinBroadcastSystem}; -use chat::{ChatBroadcastSystem, PlayerChatSystem}; -use digging::BlockUpdateBroadcastSystem; -use digging::PlayerDiggingSystem; -use init::PlayerInitSystem; -use inventory::{ - CreativeInventorySystem, EquipmentSendSystem, HeldItemBroadcastSystem, HeldItemChangeSystem, -}; -use movement::{ChunkSendSystem, ClientChunkUnloadSystem, PlayerMovementSystem}; -use resource_pack::ResourcePackSendSystem; -use specs::DispatcherBuilder; - -pub const PLAYER_EYE_HEIGHT: f64 = 1.62; -pub const PLAYER_EYE_HEIGHT_WHILE_SNEAKING: f64 = 1.54; - -pub fn init_logic(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(PlayerDiggingSystem, PLAYER_DIGGING, &[NETWORK]); - dispatcher.add(PlayerAnimationSystem, PLAYER_ANIMATION, &[NETWORK]); - dispatcher.add(CreativeInventorySystem, CREATIVE_INVENTORY, &[NETWORK]); - dispatcher.add(HeldItemChangeSystem, HELD_ITEM_CHANGE, &[NETWORK]); - dispatcher.add(PlayerMovementSystem, PLAYER_MOVEMENT, &[NETWORK]); - dispatcher.add(PlayerChatSystem, PLAYER_CHAT, &[NETWORK]); - dispatcher.add(BlockPlacementSystem, BLOCK_PLACEMENT, &[NETWORK]); - dispatcher.add( - PlayerDataSaveSystem::default(), - PLAYER_DATA_SAVE, - &[NETWORK], - ); -} - -pub fn init_handlers(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(ViewUpdateSystem::default(), VIEW_UPDATE, &[]); - dispatcher.add(ChunkCrossSystem::default(), CHUNK_CROSS, &[]); - dispatcher.add(ClientChunkUnloadSystem, CLIENT_CHUNK_UNLOAD, &[]); - dispatcher.add(PlayerInitSystem::default(), PLAYER_INIT, &[]); -} - -pub fn init_broadcast(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(HeldItemBroadcastSystem::default(), HELD_ITEM_BROADCAST, &[]); - dispatcher.add(JoinBroadcastSystem::default(), JOIN_BROADCAST, &[]); - dispatcher.add( - DisconnectBroadcastSystem::default(), - DISCONNECT_BROADCAST, - &[], - ); - dispatcher.add( - AnimationBroadcastSystem::default(), - ANIMATION_BROADCAST, - &[], - ); - dispatcher.add(EquipmentSendSystem::default(), EQUIPMENT_SEND, &[]); - dispatcher.add(ResourcePackSendSystem::default(), RESOURCE_PACK_SEND, &[]); - dispatcher.add(ChunkSendSystem::default(), CHUNK_SEND, &[]); - dispatcher.add( - BlockUpdateBroadcastSystem::default(), - BLOCK_BREAK_BROADCAST, - &[], - ); - dispatcher.add(SetSlotSystem::default(), SET_SLOT, &[]); - dispatcher.add(ChatBroadcastSystem::default(), CHAT_BROADCAST, &[]); -} diff --git a/server/src/player/movement.rs b/server/src/player/movement.rs deleted file mode 100644 index 919847c85..000000000 --- a/server/src/player/movement.rs +++ /dev/null @@ -1,469 +0,0 @@ -use std::collections::VecDeque; -use std::ops::{Deref, DerefMut}; -use std::sync::Arc; - -use hashbrown::HashSet; -use rayon::prelude::*; -use shrev::{EventChannel, ReaderId}; -use specs::storage::{BTreeStorage, ComponentEvent}; -use specs::{ - BitSet, Component, Entities, Entity, Join, LazyUpdate, ParJoin, Read, ReadExpect, ReadStorage, - System, WorldExt, Write, WriteStorage, -}; - -use feather_core::network::cast_packet; -use feather_core::network::packet::implementation::{ - ChunkData, PlayerLook, PlayerPosition, PlayerPositionAndLookServerbound, UnloadChunk, -}; -use feather_core::network::packet::{Packet, PacketType}; -use feather_core::world::chunk::Chunk; -use feather_core::world::{ChunkMap, ChunkPosition, Position}; - -use crate::chunk_logic::{ - load_chunk, ChunkHolderComponent, ChunkHolderReleaseEvent, ChunkHolders, ChunkLoadEvent, - ChunkLoadFailEvent, ChunkWorkerHandle, -}; -use crate::config::Config; -use crate::entity::PositionComponent; -use crate::network::{send_packet_to_player, NetworkComponent, PacketQueue}; -use crate::{TickCount, TPS}; - -// MOVEMENT HANDLING - -/// System for handling player movement -/// packets. -pub struct PlayerMovementSystem; - -impl<'a> System<'a> for PlayerMovementSystem { - type SystemData = (WriteStorage<'a, PositionComponent>, Read<'a, PacketQueue>); - - fn run(&mut self, data: Self::SystemData) { - let (mut positions, packet_queue) = data; - - // Take movement packets - let mut packets = vec![]; - packets.append(&mut packet_queue.for_packet(PacketType::PlayerPosition)); - packets.append(&mut packet_queue.for_packet(PacketType::PlayerPositionAndLookServerbound)); - packets.append(&mut packet_queue.for_packet(PacketType::PlayerLook)); - - // Handle movement packets - for (player, packet) in packets { - let position = positions.get(player).unwrap(); - - // Get position using packet and old position - let new_pos = new_pos_from_packet(position.previous, packet); - - // Set new position - positions.get_mut(player).unwrap().current = new_pos; - } - } -} - -fn new_pos_from_packet(old_pos: Position, packet: Box<dyn Packet>) -> Position { - match packet.ty() { - PacketType::PlayerPosition => { - let packet = cast_packet::<PlayerPosition>(&*packet); - - position!( - packet.x, - packet.feet_y, - packet.z, - old_pos.pitch, - old_pos.yaw, - packet.on_ground - ) - } - PacketType::PlayerLook => { - let packet = cast_packet::<PlayerLook>(&*packet); - - position!( - old_pos.x, - old_pos.y, - old_pos.z, - packet.pitch, - packet.yaw, - packet.on_ground - ) - } - PacketType::PlayerPositionAndLookServerbound => { - let packet = cast_packet::<PlayerPositionAndLookServerbound>(&*packet); - - position!( - packet.x, - packet.feet_y, - packet.z, - packet.pitch, - packet.yaw, - packet.on_ground - ) - } - _ => panic!(), - } -} - -// CHUNK LOAD/UNLOAD HANDLING - -/// Component for storing which chunks a client -/// has loaded and which are queued to be unloaded -/// on the client. -#[derive(Clone, Default, Debug)] -pub struct LoadedChunksComponent { - /// All chunks which are loaded on the client, i.e. - /// which have had a Chunk Data packet sent. - loaded_chunks: HashSet<ChunkPosition>, - /// Chunks queued for unloading on the client. - /// - /// Note that that these chunks will not be unloaded - /// on the server - all that will happen is that an Unload - /// Chunk packet will be sent to the client. This avoids client-side - /// memory leaks. - unload_queue: VecDeque<(ChunkPosition, u64)>, -} - -impl Component for LoadedChunksComponent { - type Storage = BTreeStorage<Self>; -} - -/// Component storing what chunks are pending -/// to send to a player. -#[derive(Clone, Debug)] -pub struct ChunkPendingComponent { - pub pending: HashSet<ChunkPosition>, -} - -impl Deref for ChunkPendingComponent { - type Target = HashSet<ChunkPosition>; - - fn deref(&self) -> &Self::Target { - &self.pending - } -} - -impl DerefMut for ChunkPendingComponent { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pending - } -} - -impl Component for ChunkPendingComponent { - type Storage = BTreeStorage<Self>; -} - -/// Time after a player can no longer see a chunk -/// that it is unloaded. -const CHUNK_UNLOAD_TIME: u64 = TPS * 5; // 5 seconds - -/// Event which is triggered when a player crosses -/// chunk boundaries, causing their position's chunk -/// to change. -#[derive(Debug, Clone)] -pub struct ChunkCrossEvent { - /// The player affected by this event. - pub player: Entity, - /// The old chunk position. - pub old: ChunkPosition, - /// The new chunk position. - pub new: ChunkPosition, -} - -/// System that checks when a player crosses chunk boundaries. -/// When the player does so, the system sends Chunk Data packets -/// for chunks within the view distance and also unloads -/// chunks no longer within the player's view distance. -#[derive(Default)] -pub struct ChunkCrossSystem { - dirty: BitSet, - reader: Option<ReaderId<ComponentEvent>>, -} - -impl<'a> System<'a> for ChunkCrossSystem { - type SystemData = ( - ReadStorage<'a, PositionComponent>, - Read<'a, ChunkMap>, - Read<'a, TickCount>, - Read<'a, Arc<Config>>, - WriteStorage<'a, LoadedChunksComponent>, - WriteStorage<'a, ChunkHolderComponent>, - ReadStorage<'a, NetworkComponent>, - Write<'a, ChunkHolders>, - Write<'a, EventChannel<ChunkCrossEvent>>, - ReadExpect<'a, ChunkWorkerHandle>, - Read<'a, LazyUpdate>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - positions, - chunk_map, - tick_count, - config, - mut loaded_chunks_comps, - mut chunk_holder_comps, - net_comps, - mut holders, - mut cross_events, - chunk_handle, - lazy, - entities, - ) = data; - - self.dirty.clear(); - - for event in positions.channel().read(self.reader.as_mut().unwrap()) { - match event { - ComponentEvent::Modified(id) | ComponentEvent::Inserted(id) => { - self.dirty.add(*id); - } - _ => (), - } - } - - // Go through events and handle them accordingly - for (position, net, chunk_holder, loaded_chunks, player, _) in ( - &positions, - &net_comps, - &mut chunk_holder_comps, - &mut loaded_chunks_comps, - &entities, - &self.dirty, - ) - .join() - { - let old_chunk_pos = position.previous.chunk_pos(); - let new_chunk_pos = position.current.chunk_pos(); - - if old_chunk_pos != new_chunk_pos { - // Player has moved across chunk boundaries. Handle accordingly. - let chunks = chunks_within_view_distance(&config, new_chunk_pos); - - for chunk in &chunks { - if loaded_chunks.loaded_chunks.contains(chunk) { - // Already sent - nothing to do. - continue; - } - - send_chunk_to_player( - *chunk, - net, - player, - &chunk_map, - &chunk_handle, - &mut holders, - chunk_holder, - loaded_chunks, - &lazy, - ); - } - - // Now, queue all chunks which need to be unloaded for unloading. - let old_chunks = chunks_within_view_distance(&config, old_chunk_pos); - - for chunk in old_chunks { - if chunks.contains(&chunk) { - // Chunk should remain loaded. Nothing to do - continue; - } - - // Queue chunk for unloading. - let time = tick_count.0 + CHUNK_UNLOAD_TIME; - loaded_chunks.unload_queue.push_back((chunk, time)); - } - - // Trigger chunk cross event. - let event = ChunkCrossEvent { - player, - old: old_chunk_pos, - new: new_chunk_pos, - }; - cross_events.single_write(event); - } - } - } - - flagged_setup_impl!(PositionComponent, reader); -} - -/// System for sending chunks to players once they're loaded. -/// -/// This system listens to `ChunkLoadEvent`s. -#[derive(Default)] -pub struct ChunkSendSystem { - load_event_reader: Option<ReaderId<ChunkLoadEvent>>, - fail_event_reader: Option<ReaderId<ChunkLoadFailEvent>>, -} - -impl<'a> System<'a> for ChunkSendSystem { - type SystemData = ( - WriteStorage<'a, ChunkPendingComponent>, - ReadStorage<'a, NetworkComponent>, - Read<'a, ChunkMap>, - Read<'a, EventChannel<ChunkLoadEvent>>, - Read<'a, EventChannel<ChunkLoadFailEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (mut pendings, netcomps, chunk_map, load_events, fail_events) = data; - - for event in load_events.read(&mut self.load_event_reader.as_mut().unwrap()) { - // TODO perhaps this is slightly inefficient? - (&netcomps, &mut pendings) - .par_join() - .for_each(|(net, pending)| { - if pending.contains(&event.pos) { - // It's safe to unwrap the chunk value now, - // because we know it's been loaded. - let chunk = chunk_map.chunk_at(event.pos).unwrap(); - send_chunk_data(chunk, net); - - pending.remove(&event.pos); - } - }); - } - - for event in fail_events.read(self.fail_event_reader.as_mut().unwrap()) { - (&mut pendings).par_join().for_each(|pending| { - if pending.contains(&event.pos) { - // The chunk failed to load - skip sending it. - // See issue #71 - pending.remove(&event.pos); - } - }); - } - } - - setup_impl!(load_event_reader, fail_event_reader); -} - -/// System for sending the Unload Chunk packet when the time comes. -pub struct ClientChunkUnloadSystem; - -impl<'a> System<'a> for ClientChunkUnloadSystem { - type SystemData = ( - WriteStorage<'a, LoadedChunksComponent>, - ReadStorage<'a, NetworkComponent>, - ReadStorage<'a, PositionComponent>, - WriteStorage<'a, ChunkHolderComponent>, - Entities<'a>, - Write<'a, ChunkHolders>, - Read<'a, TickCount>, - Read<'a, Arc<Config>>, - Write<'a, EventChannel<ChunkHolderReleaseEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - mut loaded_chunks_comps, - net_comps, - positions, - mut chunk_holder_comps, - entities, - mut chunk_holders, - tick_count, - config, - mut holder_release_events, - ) = data; - - ( - &mut loaded_chunks_comps, - &net_comps, - &positions, - &mut chunk_holder_comps, - &entities, - ) - .join() - .for_each( - |(loaded_chunks_comp, net_comp, position, chunk_holder_comp, player)| { - // Go through queue and see if it's time to unload any chunks. - while let Some((chunk, time)) = loaded_chunks_comp.unload_queue.front() { - let chunk = *chunk; - if tick_count.0 >= *time { - // Unload if needed. - - let chunks_within_view_distance = - chunks_within_view_distance(&config, position.current.chunk_pos()); - - if chunks_within_view_distance.contains(&chunk) { - // Chunk is within view distance again - don't unload it. - loaded_chunks_comp.unload_queue.pop_front(); - continue; - } - - let unload_chunk = UnloadChunk::new(chunk.x, chunk.z); - send_packet_to_player(net_comp, unload_chunk); - - // Remove chunk from queue. - loaded_chunks_comp.unload_queue.pop_front(); - // Remove from loaded chunk list. - loaded_chunks_comp.loaded_chunks.remove(&chunk); - // Remove hold on chunk so it can be unloaded. - chunk_holders.remove_holder(chunk, player, &mut holder_release_events); - // Remove hold from chunk holder component. - chunk_holder_comp.holds.remove(&chunk); - } else { - // No more chunks in queue that should - // be unloaded - finished. - break; - } - } - }, - ); - } -} - -/// Returns the set of all chunk positions -/// within the server view distance of a given -/// chunk. -fn chunks_within_view_distance(config: &Config, chunk: ChunkPosition) -> HashSet<ChunkPosition> { - let view_distance = i32::from(config.server.view_distance); - let mut results = HashSet::with_capacity((view_distance * view_distance) as usize); - - for x in -view_distance..=view_distance { - for z in -view_distance..=view_distance { - results.insert(ChunkPosition::new(chunk.x + x, chunk.z + z)); - } - } - - results -} - -/// Attempts to send the chunk at the given position to -/// the given player. If the chunk is not loaded, it will -/// be loaded and sent at a later time as soon as it is -/// loaded. -#[allow(clippy::too_many_arguments)] // TODO: get rid of LoadedChunksComponent -pub fn send_chunk_to_player( - chunk_pos: ChunkPosition, - net: &NetworkComponent, - player: Entity, - chunk_map: &ChunkMap, - chunk_handle: &ChunkWorkerHandle, - holders: &mut ChunkHolders, - holder: &mut ChunkHolderComponent, - loaded_chunks: &mut LoadedChunksComponent, - lazy: &LazyUpdate, -) { - holders.insert_holder(chunk_pos, player); - holder.holds.insert(chunk_pos); - loaded_chunks.loaded_chunks.insert(chunk_pos); - - if let Some(chunk) = chunk_map.chunk_at(chunk_pos) { - send_chunk_data(chunk, net); - } else { - // Queue for loading - load_chunk(chunk_handle, chunk_pos); - lazy.exec_mut(move |world| { - world - .write_component::<ChunkPendingComponent>() - .get_mut(player) - .unwrap() - .pending - .insert(chunk_pos); - }); - } -} - -fn send_chunk_data(chunk: &Chunk, net: &NetworkComponent) { - let packet = ChunkData::new(chunk.clone()); - send_packet_to_player(net, packet); -} diff --git a/server/src/player/placement.rs b/server/src/player/placement.rs deleted file mode 100644 index 4974554f2..000000000 --- a/server/src/player/placement.rs +++ /dev/null @@ -1,215 +0,0 @@ -use crate::blocks::{BlockUpdateCause, BlockUpdateEvent}; -use crate::disconnect_player; -use crate::entity::PlayerComponent; -use crate::network::PacketQueue; -use crate::player::{InventoryComponent, InventoryUpdateEvent}; -use crate::prelude::Gamemode; -use feather_core::inventory::SLOT_HOTBAR_OFFSET; -use feather_core::network::cast_packet; -use feather_core::network::packet::implementation::PlayerBlockPlacement; -use feather_core::world::ChunkMap; -use feather_core::{Block, ItemStack, PacketType}; -use feather_item_block::ItemToBlock; -use shrev::EventChannel; -use specs::{LazyUpdate, Read, ReadStorage, System, Write, WriteStorage}; - -/// System for handling Player Block Placement packets -/// and updating the world accordingly. -pub struct BlockPlacementSystem; - -impl<'a> System<'a> for BlockPlacementSystem { - type SystemData = ( - WriteStorage<'a, InventoryComponent>, - ReadStorage<'a, PlayerComponent>, - Write<'a, ChunkMap>, - Write<'a, EventChannel<BlockUpdateEvent>>, - Write<'a, EventChannel<InventoryUpdateEvent>>, - Read<'a, PacketQueue>, - Read<'a, LazyUpdate>, - ); - - fn run(&mut self, data: Self::SystemData) { - let ( - mut inventories, - players, - mut chunk_map, - mut block_update_events, - mut inventory_update_events, - packet_queue, - lazy, - ) = data; - - let packets = packet_queue.for_packet(PacketType::PlayerBlockPlacement); - - for (player, packet) in packets { - let packet = cast_packet::<PlayerBlockPlacement>(&*packet); - - // TODO: handle slabs, blocks with directions, etc. - let inventory = inventories.get_mut(player).unwrap(); - - let item = continue_if_none!(inventory.item_in_main_hand()); - - let block = continue_if_none!(item.ty.to_block()); - - let placed_on = match chunk_map.block_at(packet.location) { - Some(block) => block, - None => { - disconnect_player( - player, - String::from("Attempted to place block in unloaded chunk"), - &lazy, - ); - continue; - } - }; - - // TODO: waterlogged blocks, more - let pos = match placed_on { - Block::Grass | Block::TallGrass(_) | Block::Water(_) | Block::Lava(_) => { - packet.location - } - _ => packet.location + packet.face.placement_offset(), - }; - - let old = match chunk_map.block_at(pos) { - Some(block) => block, - None => { - disconnect_player( - player, - String::from("Attempted to place block in unloaded chunk"), - &lazy, - ); - continue; - } - }; - - chunk_map.set_block_at(pos, block).unwrap(); - - let event = BlockUpdateEvent { - cause: BlockUpdateCause::Player(player), - pos, - old_block: old, - new_block: block, - }; - - block_update_events.single_write(event); - - let gamemode = players.get(player).unwrap().gamemode; - - // Update player's inventory if in survival - if gamemode == Gamemode::Survival { - let item = ItemStack::new(item.ty, item.amount - 1); - inventory.set_item_in_main_hand(item); - - let event = InventoryUpdateEvent { - slots: smallvec![SLOT_HOTBAR_OFFSET + inventory.held_item], - player, - }; - inventory_update_events.single_write(event); - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::testframework as t; - use feather_core::inventory::SLOT_HOTBAR_OFFSET; - use feather_core::network::packet::implementation::Face; - use feather_core::{Block, BlockPosition, Item, ItemStack}; - use specs::WorldExt; - - #[test] - fn test_block_placement_system() { - let (mut w, mut d) = t::builder().with(BlockPlacementSystem, "").build(); - - t::populate_with_air(&mut w); - - let player = t::add_player(&mut w); - - { - let mut inventories = w.write_component::<InventoryComponent>(); - inventories - .get_mut(player.entity) - .unwrap() - .set_item_at(SLOT_HOTBAR_OFFSET, ItemStack::new(Item::Cobblestone, 1)); - - let mut players = w.write_component::<PlayerComponent>(); - players.get_mut(player.entity).unwrap().gamemode = Gamemode::Survival; - } - - let pos = BlockPosition::new(10, 20, 30); - - let packet = PlayerBlockPlacement { - location: pos, - face: Face::Top, - hand: 0, - cursor_position_x: 0.0, - cursor_position_y: 0.0, - cursor_position_z: 0.0, - }; - t::receive_packet(&player, &w, packet); - - let mut reader = t::reader(&w); - - d.dispatch(&w); - w.maintain(); - - let events = t::triggered_events::<BlockUpdateEvent>(&w, &mut reader); - let first = events.first().unwrap(); - - assert_eq!(first.cause, BlockUpdateCause::Player(player.entity)); - assert_eq!(first.old_block, Block::Air); - assert_eq!(first.new_block, Block::Cobblestone); - assert_eq!(first.pos, pos + BlockPosition::new(0, 1, 0)); - - let inventory = w - .read_component::<InventoryComponent>() - .get(player.entity) - .unwrap() - .clone(); - assert_eq!(inventory.item_in_main_hand(), None); - } - - #[test] - fn test_block_placement_system_unloaded_chunk() { - let (mut w, mut d) = t::builder().with(BlockPlacementSystem, "").build(); - - t::populate_with_air(&mut w); - - let player = t::add_player(&mut w); - - { - let mut inventories = w.write_component::<InventoryComponent>(); - inventories - .get_mut(player.entity) - .unwrap() - .set_item_at(SLOT_HOTBAR_OFFSET, ItemStack::new(Item::Cobblestone, 1)); - - let mut players = w.write_component::<PlayerComponent>(); - players.get_mut(player.entity).unwrap().gamemode = Gamemode::Survival; - } - - let pos = BlockPosition::new(1000, 100, 2000); - - let packet = PlayerBlockPlacement { - location: pos, - face: Face::Top, - hand: 0, - cursor_position_x: 0.0, - cursor_position_y: 0.0, - cursor_position_z: 0.0, - }; - t::receive_packet(&player, &w, packet); - - let mut reader = t::reader(&w); - - d.dispatch(&w); - w.maintain(); - - t::assert_disconnected(&player); - - assert!(t::triggered_events::<BlockUpdateEvent>(&w, &mut reader).is_empty()); - } -} diff --git a/server/src/player/resource_pack.rs b/server/src/player/resource_pack.rs deleted file mode 100644 index 917536250..000000000 --- a/server/src/player/resource_pack.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! System for sending resource pack to new players. - -use crate::config::Config; -use crate::joinhandler::PlayerJoinEvent; -use crate::network::{send_packet_to_player, NetworkComponent}; -use feather_core::network::packet::implementation::ResourcePackSend; -use shrev::{EventChannel, ReaderId}; -use specs::{Read, ReadStorage, System}; -use std::sync::Arc; - -/// System for sending resource pack to new players, -/// if enabled. -/// -/// This system listens to `PlayerJoinEvent`s. -#[derive(Default)] -pub struct ResourcePackSendSystem { - reader: Option<ReaderId<PlayerJoinEvent>>, -} - -impl<'a> System<'a> for ResourcePackSendSystem { - type SystemData = ( - ReadStorage<'a, NetworkComponent>, - Read<'a, Arc<Config>>, - Read<'a, EventChannel<PlayerJoinEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (networks, config, join_events) = data; - if config.resource_pack.url.is_empty() { - return; // Resource pack not enabled - } - - for event in join_events.read(self.reader.as_mut().unwrap()) { - let network = networks.get(event.player).unwrap(); - - let packet = ResourcePackSend { - url: config.resource_pack.url.clone(), - hash: config.resource_pack.hash.to_lowercase(), - }; - - send_packet_to_player(&network, packet); - } - } - - setup_impl!(reader); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::testframework as t; - use feather_core::network::cast_packet; - use feather_core::network::packet::PacketType; - use specs::WorldExt; - - #[test] - fn test_resource_pack_send_system() { - let (mut w, mut d) = t::init_world(); - - let player = t::add_player(&mut w); - - let event = PlayerJoinEvent { - player: player.entity, - }; - t::trigger_event(&w, event); - - let url = "https://rust-lang.org/".to_string(); - let hash = "bLa".to_string(); - - { - let mut config = Config::clone(&w.fetch::<Arc<Config>>()); - config.resource_pack.url = url.clone(); - config.resource_pack.hash = hash.clone(); - w.insert(Arc::new(config)); - } - - d.dispatch(&w); - w.maintain(); - - let packet = t::assert_packet_received(&player, PacketType::ResourcePackSend); - let packet = cast_packet::<ResourcePackSend>(&*packet); - - assert_eq!(packet.url, url); - assert_eq!(packet.hash, hash.to_lowercase()); - } -} diff --git a/server/src/player/save.rs b/server/src/player/save.rs deleted file mode 100644 index df1ac1140..000000000 --- a/server/src/player/save.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Saving of player data files and a system to save -//! player data on disconnect. - -use crate::entity::{NamedComponent, PlayerComponent, PositionComponent}; -use crate::player::{InventoryComponent, PlayerDisconnectEvent}; -use crate::prelude::Config; -use crossbeam::Receiver; -use feather_core::entity::BaseEntityData; -use feather_core::inventory::Inventory; -use feather_core::player_data::{InventorySlot, PlayerData}; -use feather_core::{player_data, Gamemode, Position}; -use shrev::{EventChannel, ReaderId}; -use specs::{Read, ReadStorage, System}; -use std::path::Path; -use std::sync::Arc; -use uuid::Uuid; - -/// System to save player data upon disconnect. -/// -/// This system listens to `PlayerDisconnectEvent`s. -#[derive(Default)] -pub struct PlayerDataSaveSystem { - reader: Option<ReaderId<PlayerDisconnectEvent>>, -} - -impl<'a> System<'a> for PlayerDataSaveSystem { - type SystemData = ( - Read<'a, Arc<Config>>, - ReadStorage<'a, PositionComponent>, - ReadStorage<'a, PlayerComponent>, - ReadStorage<'a, NamedComponent>, - ReadStorage<'a, InventoryComponent>, - Read<'a, EventChannel<PlayerDisconnectEvent>>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (config, positions, players, nameds, inventories, disconnect_events) = data; - - for event in disconnect_events.read(self.reader.as_mut().unwrap()) { - let player = players.get(event.player).unwrap(); - save_player_data( - &config, - positions.get(event.player).unwrap().current, - player.gamemode, - &inventories.get(event.player).unwrap().inventory, - nameds.get(event.player).unwrap().uuid, - ); - } - } - - setup_impl!(reader); -} - -/// Saves a player's data. -/// -/// This operation is performed asynchronously, -/// and a channel is returned which will receive -/// a message upon completion. -pub fn save_player_data( - config: &Config, - position: Position, - gamemode: Gamemode, - inventory: &Inventory, - uuid: Uuid, -) -> Receiver<()> { - let data = PlayerData { - entity: BaseEntityData { - velocity: vec![0.0; 3], // Player velocity has no effect - position: vec![position.x, position.y, position.z], - rotation: vec![position.yaw, position.pitch], - }, - gamemode: gamemode.get_id() as i32, - inventory: inventory - .items() - .iter() - .enumerate() - .filter_map(|(index, item)| match item.clone() { - Some(item) => Some((index, item)), - None => None, - }) - .map(|(index, item)| InventorySlot::from_network_index(index, item)) - .collect(), - }; - - // Channel used to communicate with Tokio task - let (tx, rx) = crossbeam::bounded(1); - - let world_dir = Path::new(&config.world.name).to_owned(); - - tokio_executor::blocking::run(move || { - if let Err(e) = player_data::save_player_data(world_dir.as_path(), uuid, data) { - error!("Failed to save player data for UUID {}: {:?}", uuid, e); - } else { - debug!("Saved player data for UUID {}", uuid); - } - - let _ = tx.send(()); // Channel could have been dropped, so ignore result - }); - - rx -} diff --git a/server/src/player/view.rs b/server/src/player/view.rs deleted file mode 100644 index d0cf7504c..000000000 --- a/server/src/player/view.rs +++ /dev/null @@ -1,221 +0,0 @@ -//! This module implements creating and destroying -//! entities on the client when a player moves. -//! -//! When a player crosses chunk boundaries, the following -//! takes place: -//! * We send a `Destroy Entities` packet containing all -//! entities which are no longer within the view distance. -//! * We spawn an entity on the client for every entity -//! which is now within the view distance. -//! -//! This is handled by `ViewUpdateSystem`, which listens -//! to `ChunkCrossEvent`s. - -use crate::config::Config; -use crate::entity::ChunkEntities; -use crate::lazy::LazyUpdateExt; -use crate::network::{send_packet_to_player, NetworkComponent}; -use crate::player::movement::ChunkCrossEvent; -use feather_core::network::packet::implementation::DestroyEntities; -use shrev::EventChannel; -use specs::{LazyUpdate, Read, ReadStorage, ReaderId, System}; -use std::sync::Arc; - -/// System for updating entities visible -/// by the client. -#[derive(Default)] -pub struct ViewUpdateSystem { - reader: Option<ReaderId<ChunkCrossEvent>>, -} - -impl<'a> System<'a> for ViewUpdateSystem { - type SystemData = ( - ReadStorage<'a, NetworkComponent>, - Read<'a, EventChannel<ChunkCrossEvent>>, - Read<'a, ChunkEntities>, - Read<'a, Arc<Config>>, - Read<'a, LazyUpdate>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (networks, cross_events, chunk_entities, config, lazy) = data; - - for event in cross_events.read(self.reader.as_mut().unwrap()) { - // Find new and old entities. - let old_entities = - chunk_entities.entites_within_view_distance(event.old, config.server.view_distance); - let new_entities = - chunk_entities.entites_within_view_distance(event.new, config.server.view_distance); - - let mut to_destroy = vec![]; - - // Compute entities which are only present in one of the sets. - // If an entity is only present in `old_entities` and not `new_entities`, - // it should be destroyed on the client. - // If an entity is only present in `new_entities`, it should be spawned. - for entity in old_entities.symmetric_difference(&new_entities) { - if *entity == event.player { - continue; - } - - if old_entities.contains(entity) { - // Entity is in `old_entities` but not in `new_entities`. - // Destroy it. If the entity is a player, also destroy this player - // on the client. - to_destroy.push(entity.id() as i32); - - if let Some(network) = networks.get(*entity) { - let packet = DestroyEntities { - entity_ids: vec![event.player.id() as i32], - }; - send_packet_to_player(network, packet); - } - } else { - // Entity is in `new_entities` but not in `old_entities`. - // Spawn it. If the entity is a player, also send this player - // to that entity. - lazy.send_entity_to_player(event.player, *entity); - - if networks.get(*entity).is_some() { - lazy.send_entity_to_player(*entity, event.player); - } - } - } - - if !to_destroy.is_empty() { - let packet = DestroyEntities { - entity_ids: to_destroy, - }; - send_packet_to_player(&networks.get(event.player).unwrap(), packet); - } - } - } - - setup_impl!(reader); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::{item, PositionComponent}; - use crate::testframework as t; - use feather_core::network::cast_packet; - use feather_core::network::packet::implementation::{SpawnObject, SpawnPlayer}; - use feather_core::{ChunkPosition, Item, ItemStack, PacketType}; - use hashbrown::HashSet; - use specs::{Builder, WorldExt}; - - #[test] - fn test_view_update_system() { - let (mut world, mut dispatcher) = t::builder() - .with(ViewUpdateSystem::default(), "view") - .build(); - - let player_chunk = ChunkPosition::new(0, 0); - - let player1 = t::add_player_without_holder(&mut world); - let player2 = t::add_player_without_holder(&mut world); - - let entity1 = item::create( - &world.fetch(), - &world.fetch(), - ItemStack::new(Item::Stone, 0), - 0, - ) - .with(PositionComponent::default()) - .build(); - let entity2 = item::create( - &world.fetch(), - &world.fetch(), - ItemStack::new(Item::Stone, 0), - 0, - ) - .with(PositionComponent::default()) - .build(); - let entity3 = item::create( - &world.fetch(), - &world.fetch(), - ItemStack::new(Item::Stone, 0), - 0, - ) - .with(PositionComponent::default()) - .build(); - let entity4 = item::create( - &world.fetch(), - &world.fetch(), - ItemStack::new(Item::Stone, 0), - 0, - ) - .with(PositionComponent::default()) - .build(); - - let mut config = Config::default(); - config.server.view_distance = 4; - world.insert(Arc::new(config)); - - { - let mut chunk_entities = world.fetch_mut::<ChunkEntities>(); - chunk_entities.add_to_chunk(player_chunk, player1.entity); - chunk_entities.add_to_chunk(player_chunk, player2.entity); - chunk_entities.add_to_chunk(ChunkPosition::new(3, -3), entity1); - chunk_entities.add_to_chunk(player_chunk, entity2); - chunk_entities.add_to_chunk(ChunkPosition::new(4, -3), entity3); - chunk_entities.add_to_chunk(ChunkPosition::new(100, 103), entity4); - } - - let event = ChunkCrossEvent { - player: player1.entity, - old: ChunkPosition::new(100, 103), - new: player_chunk, - }; - t::trigger_event(&world, event); - - world.maintain(); - dispatcher.dispatch(&world); - world.maintain(); - dispatcher.dispatch(&world); - world.maintain(); - - let packets = t::received_packets(&player1, None); - - let mut received_spawns = HashSet::new(); - - for packet in packets { - dbg!(packet.ty()); - match packet.ty() { - PacketType::DestroyEntities => { - let packet = cast_packet::<DestroyEntities>(&*packet); - let destroyed = packet.entity_ids.iter().cloned().collect::<HashSet<_>>(); - assert_eq!(destroyed.len(), 1); - assert!(destroyed.contains(&(entity4.id() as i32))); - } - PacketType::SpawnObject => { - let packet = cast_packet::<SpawnObject>(&*packet); - received_spawns.insert(packet.entity_id); - } - PacketType::SpawnPlayer => { - let packet = cast_packet::<SpawnPlayer>(&*packet); - received_spawns.insert(packet.entity_id); - } - _ => (), - } - } - - println!("{:?}", received_spawns); - assert_eq!(received_spawns.len(), 3); - assert!(received_spawns.contains(&(entity1.id() as i32))); - assert!(received_spawns.contains(&(entity2.id() as i32))); - assert!(received_spawns.contains(&(player2.entity.id() as i32))); - - // Confirm that `player1` was sent to `player2`. - let packets = t::received_packets(&player2, None); - assert_eq!(packets.len(), 2); // One for Spawn Player, one for metadata - - let packet = packets - .into_iter() - .find(|packet| packet.ty() == PacketType::SpawnPlayer) - .unwrap(); - let packet = cast_packet::<SpawnPlayer>(&*packet); - assert_eq!(packet.entity_id, player1.entity.id() as i32); - } -} diff --git a/server/src/prelude.rs b/server/src/prelude.rs deleted file mode 100644 index b656211e1..000000000 --- a/server/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use super::TPS; -pub use crate::config::Config; -pub use feather_core::prelude::*; -pub use std::cell::RefCell; -pub use std::rc::Rc; diff --git a/server/src/shutdown.rs b/server/src/shutdown.rs deleted file mode 100644 index 5bcb42a43..000000000 --- a/server/src/shutdown.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Shutdown behavior. - -use crate::chunk_logic::ChunkWorkerHandle; -use crate::config::Config; -use crate::entity::{NamedComponent, PlayerComponent, PositionComponent}; -use crate::player; -use crate::player::InventoryComponent; -use crate::time::Time; -use crate::{chunkworker, entity}; -use crossbeam::Sender; -use feather_core::level::{save_level_file, LevelData, Root}; -use feather_core::prelude::ChunkMap; -use specs::{Join, World, WorldExt}; -use std::fs::File; -use std::sync::Arc; - -pub fn init(tx: Sender<()>) { - ctrlc::set_handler(move || { - tx.send(()).unwrap(); - }) - .unwrap(); -} - -pub fn save_chunks(world: &mut World) { - let mut chunk_map = world.fetch_mut::<ChunkMap>(); - let handle = world.fetch::<ChunkWorkerHandle>(); - let count = entity::save_chunks(&mut chunk_map, &world.fetch(), &world.fetch()); - - drop(chunk_map); - drop(handle); - - // Need to call `world.maintain()` for lazy chunk saving - // to take effect - world.maintain(); - - let handle = world.fetch::<ChunkWorkerHandle>(); - handle.sender.send(chunkworker::Request::ShutDown).unwrap(); - - let mut saved = 0; - // Wait for chunks to finish saving - while let Ok(msg) = handle.receiver.recv() { - if let chunkworker::Reply::SavedChunk(_) = msg { - saved += 1; - } - - if saved == count { - break; - } - } - - assert!( - count == saved, - "didn't save all chunks: {} != {}", - count, - saved - ); -} - -pub fn save_level(world: &World) { - let mut level = (*world.fetch::<LevelData>()).clone(); - - // Sync world time + level time - let time = world.fetch::<Time>(); - level.time = time.0 as i64; - - let config = world.fetch::<Arc<Config>>(); - - let level_path = format!("{}/{}", config.world.name, "level.dat"); - - let root = Root { data: level }; - save_level_file(&root, &mut File::create(&level_path).unwrap()) - .expect("Failed to save level file"); -} - -pub fn save_player_data(world: &World) { - let config = world.fetch::<Arc<Config>>(); - - let positions = world.read_component::<PositionComponent>(); - let nameds = world.read_component::<NamedComponent>(); - let players = world.read_component::<PlayerComponent>(); - let inventories = world.read_component::<InventoryComponent>(); - - let mut channels = vec![]; - - for (position, named, player, inventory) in (&positions, &nameds, &players, &inventories).join() - { - let rx = player::save_player_data( - &config, - position.current, - player.gamemode, - &inventory.inventory, - named.uuid, - ); - channels.push(rx); - } - - // Wait for saving to complete - channels.into_iter().for_each(|rx| rx.recv().unwrap()); -} diff --git a/server/src/systems.rs b/server/src/systems.rs deleted file mode 100644 index b5d6155c4..000000000 --- a/server/src/systems.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Constant string names for each system. -//! This file does not actually contain the systems -//! themselves. - -// Chunk logic -pub const CHUNK_LOAD: &str = "chunk_load"; -pub const CHUNK_OPTIMIZE: &str = "chunk_optimize"; - -pub const CHUNK_UNLOAD: &str = "chunk_unload"; -pub const CHUNK_HOLD_REMOVE: &str = "chunk_hold_remove"; - -// Player -pub const PLAYER_DIGGING: &str = "player_digging"; -pub const PLAYER_ANIMATION: &str = "player_animation"; -pub const CREATIVE_INVENTORY: &str = "creative_inventory"; -pub const HELD_ITEM_CHANGE: &str = "held_item_change"; -pub const PLAYER_MOVEMENT: &str = "player_movement"; -pub const PLAYER_CHAT: &str = "player_chat"; -pub const BLOCK_PLACEMENT: &str = "block_placement"; -pub const PLAYER_DATA_SAVE: &str = "player_data_save"; - -pub const CHUNK_CROSS: &str = "chunk_cross"; -pub const PLAYER_INIT: &str = "player_init"; -pub const CLIENT_CHUNK_UNLOAD: &str = "client_chunk_unload"; - -pub const VIEW_UPDATE: &str = "view_update"; -pub const HELD_ITEM_BROADCAST: &str = "held_item_broadcast"; -pub const JOIN_BROADCAST: &str = "join_broadcast"; -pub const DISCONNECT_BROADCAST: &str = "disconnect_broadcast"; -pub const ANIMATION_BROADCAST: &str = "animation_broadcast"; -pub const EQUIPMENT_SEND: &str = "equipment_send"; -pub const RESOURCE_PACK_SEND: &str = "resource_pack_send"; -pub const CHUNK_SEND: &str = "chunk_send"; -pub const BLOCK_BREAK_BROADCAST: &str = "block_break_broadcast"; -pub const BLOCK_UPDATE_PROPAGATE: &str = "block_update_propagate"; -pub const BLOCK_FALLING_CREATION: &str = "block_falling_creation"; -pub const SET_SLOT: &str = "set_slot"; -pub const CHAT_BROADCAST: &str = "chat_broadcast"; - -// Entity -pub const ITEM_COLLECT: &str = "item_collect"; - -pub const CHUNK_ENTITIES_UPDATE: &str = "chunk_entities_update"; -pub const CHUNK_ENTITIES_LOAD: &str = "chunk_entities_load"; -pub const ENTITY_DESTROY: &str = "entity_destroy"; -pub const ITEM_SPAWN: &str = "item_spawn"; -pub const ITEM_MERGE: &str = "item_merge"; -pub const SHOOT_ARROW: &str = "shoot_arrow"; -pub const CHUNK_SAVE: &str = "chunk_save"; - -pub const ENTITY_MOVE_BROADCAST: &str = "entity_move_broadcast"; -pub const ENTITY_SPAWN_BROADCAST: &str = "entity_spawn_broadcast"; -pub const ENTITY_VELOCITY_BROADCAST: &str = "entity_velocity_broadcast"; -pub const ENTITY_DESTROY_BROADCAST: &str = "entity_destroy_broadcast"; -pub const ENTITY_METADATA_BROADCAST: &str = "entity_metadata_broadcast"; -pub const BLOCK_FALLING_LANDING: &str = "block_falling_landing"; - -// Physics -pub const ENTITY_PHYSICS: &str = "entity_physics"; - -// Other -pub const JOIN_HANDLER: &str = "join_handler"; -pub const NETWORK: &str = "network"; - -pub const TIME_INCREMENT: &str = "time_increment"; -pub const TIME_SEND: &str = "time_send"; - -pub const BROADCASTER: &str = "broadcaster"; - -pub const LIGHTING: &str = "lighting"; diff --git a/server/src/testframework.rs b/server/src/testframework.rs deleted file mode 100644 index fef503cde..000000000 --- a/server/src/testframework.rs +++ /dev/null @@ -1,481 +0,0 @@ -//! Helper framework for writing unit tests. - -use std::net::TcpListener; -use std::sync::atomic::AtomicUsize; -use std::sync::Arc; - -use glm::DVec3; -use rand::Rng; -use shrev::EventChannel; -use specs::{Builder, Dispatcher, DispatcherBuilder, Entity, ReaderId, System, World, WorldExt}; -use uuid::Uuid; - -use feather_core::level::LevelData; -use feather_core::network::packet::{Packet, PacketType}; -use feather_core::world::block::Block; -use feather_core::world::chunk::Chunk; -use feather_core::world::{BlockPosition, ChunkMap, ChunkPosition, Position}; -use feather_core::Gamemode; - -use crate::chunk_logic::{ChunkHolders, ChunkLoadSystem}; -use crate::config::Config; -use crate::entity::metadata::{self, Metadata}; -use crate::entity::{ - ArrowComponent, ChunkEntities, EntityDestroyEvent, EntitySendEvent, EntitySpawnEvent, - ItemComponent, LastKnownPositionComponent, NamedComponent, PacketCreatorComponent, - PlayerComponent, PositionComponent, SerializerComponent, VelocityComponent, -}; -use crate::io::ServerToWorkerMessage; -use crate::network::{NetworkComponent, PacketQueue}; -use crate::physics::PhysicsComponent; -use crate::player::{InventoryComponent, PlayerDisconnectEvent}; -use crate::util::BroadcasterSystem; -use crate::worldgen::{EmptyWorldGenerator, WorldGenerator}; -use crate::{player, PlayerCount}; -use bitflags::_core::cell::RefCell; - -/// Initializes a Specs world and dispatcher -/// using default configuration options and an -/// available server port. -pub fn init_world<'a, 'b>() -> (World, Dispatcher<'a, 'b>) { - let mut config = Config::default(); - config.server.port = find_open_port().unwrap(); - - let config = Arc::new(config); - - let player_count = Arc::new(PlayerCount(AtomicUsize::new(0))); - let server_icon = Arc::new(None); - let ioman = super::init_io_manager( - Arc::clone(&config), - Arc::clone(&player_count), - Arc::clone(&server_icon), - ); - let level = LevelData::default(); - - let (mut world, dispatcher) = super::init_world(config, player_count, ioman, level); - register_components(&mut world); - (world, dispatcher) -} - -pub struct Player { - pub entity: Entity, - pub network_sender: crossbeam::Sender<ServerToWorkerMessage>, - pub network_receiver: RefCell<futures::channel::mpsc::UnboundedReceiver<ServerToWorkerMessage>>, -} - -/// Adds a player to the world, inserting -/// all the necessary components. Returns -/// a number of useful channels. -/// -/// # Notes -/// * A `ChunkHolders` and `ChunkEntities` entry -/// is created for the player. If this behavior is not -/// desired, use `add_player_without_holder`. -pub fn add_player(world: &mut World) -> Player { - let player = add_player_without_holder(world); - - let mut chunk_holders = world.fetch_mut::<ChunkHolders>(); - - let view_distance = i32::from(world.fetch::<Arc<Config>>().server.view_distance); - - for x in -view_distance..=view_distance { - for z in -view_distance..=view_distance { - chunk_holders.insert_holder(ChunkPosition::new(x, z), player.entity); - } - } - - let mut chunk_entities = world.fetch_mut::<ChunkEntities>(); - chunk_entities.add_to_chunk(ChunkPosition::new(0, 0), player.entity); - - player -} - -/// Adds a player to the world without adding the `ChunkHolders` -/// and `ChunkEntities` entries. -pub fn add_player_without_holder(world: &mut World) -> Player { - let (ns1, nr1) = futures::channel::mpsc::unbounded(); - let (ns2, nr2) = crossbeam::unbounded(); - let entity = world - .create_entity() - .with(NetworkComponent::new(ns1, nr2)) - .with(PlayerComponent { - gamemode: Gamemode::Creative, - profile_properties: vec![], - }) - .with(PositionComponent { - current: position!(0.0, 0.0, 0.0), - previous: position!(0.0, 0.0, 0.0), - }) - .with(NamedComponent { - display_name: "".to_string(), - uuid: Uuid::new_v4(), - }) - .with(InventoryComponent::default()) - .with(Metadata::Player(metadata::Player::default())) - .with(LastKnownPositionComponent::default()) - .with(PacketCreatorComponent(&player::create_packet)) - .build(); - - Player { - entity, - network_sender: ns2, - network_receiver: RefCell::new(nr1), - } -} - -/// Asserts that the given player has received -/// a packet of the given type, returning the packet. -pub fn assert_packet_received(player: &Player, ty: PacketType) -> Box<dyn Packet> { - while let Ok(Some(msg)) = player.network_receiver.borrow_mut().try_next() { - if let ServerToWorkerMessage::SendPacket(packet) = msg { - if packet.ty() == ty { - return packet; - } - } - } - - panic!(); -} - -/// Asserts that a player did not receive -/// any packets of the given type. -/// Panics if not. -pub fn assert_packet_not_received(player: &Player, ty: PacketType) { - while let Ok(Some(msg)) = player.network_receiver.borrow_mut().try_next() { - if let ServerToWorkerMessage::SendPacket(packet) = msg { - assert_ne!(packet.ty(), ty); - } - } -} - -/// Retrieves up to `cap` packets sent to a player, if any. -/// If `cap` is set to `None`, all packets will be read. -/// -/// Note that this function consumes messages in -/// the network channel until enough packets have been read. -pub fn received_packets(player: &Player, cap: Option<usize>) -> Vec<Box<dyn Packet>> { - let mut result = vec![]; - - while let Ok(Some(msg)) = player.network_receiver.borrow_mut().try_next() { - if let ServerToWorkerMessage::SendPacket(pack) = msg { - result.push(pack); - } - if let Some(cap) = cap.as_ref() { - if result.len() >= *cap { - break; - } - } - } - - result -} - -/// Adds a received packet to the packet queue -/// for a given player. -pub fn receive_packet<P: Packet + 'static>(player: &Player, world: &World, packet: P) { - let queue = world.fetch_mut::<PacketQueue>(); - queue.add_for_packet(player.entity, Box::new(packet)); -} - -/// Attempts to find an available port. -fn find_open_port() -> Option<u16> { - let start = rand::thread_rng().gen_range(10000, 30000); - (start..60000).find(|port| TcpListener::bind(("127.0.0.1", *port)).is_ok()) -} - -/// Asserts that a player was disconnected, panicking if not. -pub fn assert_disconnected(player: &Player) { - let mut disconnected = false; - for packet in received_packets(player, None) { - if packet.ty() == PacketType::DisconnectPlay { - disconnected = true; - } - } - - assert!(disconnected); -} - -/// Asserts that a player was not disconnected, panicking -/// if they were. -pub fn assert_not_disconnected(player: &Player) { - let mut disconnected = false; - for packet in received_packets(player, None) { - if packet.ty() == PacketType::DisconnectPlay { - disconnected = true; - } - } - - assert!(!disconnected); -} - -/// Sends a packet to the player. -pub fn send_packet<P: Packet + 'static>(player: &Player, packet: P) { - player - .network_sender - .send(ServerToWorkerMessage::NotifyPacketReceived(Box::new( - packet, - ))) - .unwrap(); -} - -/// Registers a reader for events of the given type. -pub fn reader<E: Send + Sync>(w: &World) -> ReaderId<E> { - let mut channel = w.fetch_mut::<EventChannel<E>>(); - channel.register_reader() -} - -/// Triggers the given event, writing it to -/// the corresponding `EventChannel`. -pub fn trigger_event<E: Send + Sync + 'static>(world: &World, event: E) { - let mut channel = world.fetch_mut::<EventChannel<E>>(); - channel.single_write(event); -} - -/// Returns all triggered events of a given type. -pub fn triggered_events<E: Send + Sync + Clone + 'static>( - world: &World, - reader: &mut ReaderId<E>, -) -> Vec<E> { - let channel = world.fetch::<EventChannel<E>>(); - channel.read(reader).cloned().collect() -} - -/// Populates a 15x15 area of chunks around the origin -/// with air. -pub fn populate_with_air(world: &mut World) { - for x in -15..=15 { - for z in -15..=15 { - let chunk = Chunk::new(ChunkPosition::new(x, z)); - world - .fetch_mut::<ChunkMap>() - .set_chunk_at(chunk.position(), chunk); - } - } -} - -/// Asserts that an entity was not removed. -pub fn assert_not_removed(world: &World, entity: Entity) { - assert!(world.entities().is_alive(entity)); -} - -/// Asserts that an entity was removed. -pub fn assert_removed(world: &World, entity: Entity) { - assert!(!world.entities().is_alive(entity)); -} - -/// Retrieves the position of an entity. -pub fn entity_pos(world: &World, entity: Entity) -> Position { - world - .read_component::<PositionComponent>() - .get(entity) - .unwrap() - .current -} - -/// Retrieves the velocity of an entity. -pub fn entity_vel(world: &World, entity: Entity) -> Option<DVec3> { - if let Some(comp) = world.read_component::<VelocityComponent>().get(entity) { - Some(comp.0) - } else { - None - } -} - -/// Sets an entity's position. -pub fn set_entity_pos(world: &World, entity: Entity, pos: Position) { - let mut storage = world.write_component::<PositionComponent>(); - storage.get_mut(entity).unwrap().current = pos; -} - -/// Sets an entity's velocity. -pub fn set_entity_velocity(world: &World, entity: Entity, vel: DVec3) { - let mut storage = world.write_component::<VelocityComponent>(); - storage.get_mut(entity).unwrap().0 = vel; -} - -/// Sets the block at the given position in the world. -pub fn set_block(x: i32, y: i32, z: i32, block: Block, world: &World) { - let mut chunk_map = world.fetch_mut::<ChunkMap>(); - chunk_map - .set_block_at(BlockPosition::new(x, y, z), block) - .unwrap(); -} - -/// A dispatcher builder for isolating tests. -pub struct TestBuilder<'a, 'b> { - world: World, - dispatcher: DispatcherBuilder<'a, 'b>, -} - -impl<'a, 'b> TestBuilder<'a, 'b> { - pub fn with<S>(mut self, system: S, name: &'static str) -> Self - where - S: for<'c> System<'c> + Send + 'a, - { - self.dispatcher.add(system, name, &[]); - self - } - - pub fn with_dep<S>(mut self, system: S, name: &'static str, deps: &[&'static str]) -> Self - where - S: for<'c> System<'c> + Send + 'a, - { - self.dispatcher.add(system, name, deps); - self - } - - pub fn build(mut self) -> (World, Dispatcher<'a, 'b>) { - self.world - .insert(Arc::new(PlayerCount(AtomicUsize::new(0)))); - self.world - .insert(EventChannel::<PlayerDisconnectEvent>::new()); - self.world.insert(EventChannel::<EntityDestroyEvent>::new()); - self.world.insert(EventChannel::<EntitySpawnEvent>::new()); - self.world.insert(crate::time::Time(0)); - self.world.insert(ChunkHolders::default()); - self.world.insert(ChunkEntities::default()); - self.world.insert(Arc::new(Config::default())); - - let generator: Arc<dyn WorldGenerator> = Arc::new(EmptyWorldGenerator {}); - self.world.insert(generator); - - let mut chunk_system = ChunkLoadSystem {}; - chunk_system.setup(&mut self.world); - - // Insert the broadcaster system, since it is so commonly - // used that it should be used for all tests. - self.dispatcher.add_barrier(); - self.dispatcher.add(BroadcasterSystem, "", &[]); - - let mut dispatcher = self.dispatcher.build(); - dispatcher.setup(&mut self.world); - - register_components(&mut self.world); - - (self.world, dispatcher) - } -} - -fn register_components(world: &mut World) { - world.register::<VelocityComponent>(); - world.register::<PositionComponent>(); - world.register::<NamedComponent>(); - world.register::<Metadata>(); - world.register::<ItemComponent>(); - world.register::<PlayerComponent>(); - world.register::<InventoryComponent>(); - world.register::<NetworkComponent>(); - world.register::<LastKnownPositionComponent>(); - world.register::<PhysicsComponent>(); - world.register::<ArrowComponent>(); - world.register::<PacketCreatorComponent>(); - world.register::<SerializerComponent>(); - - world - .entry() - .or_insert(EventChannel::<EntitySendEvent>::default()); -} - -pub fn builder<'a, 'b>() -> TestBuilder<'a, 'b> { - TestBuilder { - world: World::new(), - dispatcher: DispatcherBuilder::new(), - } -} - -/// Heh... tests for the testing framework. -/// Not sure what the point of this is, since -/// all other tests would fail if the testing -/// framework didn't work. -mod tests { - use feather_core::network::packet::implementation::{DisconnectPlay, LoginStart}; - - use crate::entity::{PlayerComponent, PositionComponent}; - use crate::network::{send_packet_to_player, NetworkComponent}; - - use super::*; - - #[test] - fn test_find_open_port() { - let port = find_open_port().unwrap(); - println!("Found open port: {}", port); - assert!(TcpListener::bind(("127.0.0.1", port)).is_ok()); - } - - #[test] - fn test_init_world() { - // Check that initializing the world doesn't cause - // a panic. - let (w, mut d) = init_world(); - - // Check that running the dispatcher works fine - d.dispatch(&w); - } - - #[test] - fn test_add_player() { - let (mut w, _) = init_world(); - - let entity = add_player(&mut w).entity; - - assert!(w.read_component::<PlayerComponent>().get(entity).is_some()); - assert!(w - .read_component::<PositionComponent>() - .get(entity) - .is_some()); - assert!(w.read_component::<NetworkComponent>().get(entity).is_some()); - } - - #[test] - fn test_received_packets() { - let (mut w, _) = init_world(); - - let player = add_player(&mut w); - - let cap = 1; - send_packet_to_player( - w.read_component().get(player.entity).unwrap(), - LoginStart::new("".to_string()), - ); - send_packet_to_player( - w.read_component().get(player.entity).unwrap(), - LoginStart::new("".to_string()), - ); - - let packets = received_packets(&player, Some(cap)); - assert_eq!(packets.len(), 1); - - let packets = received_packets(&player, Some(cap)); - assert_eq!(packets.len(), 1); - } - - #[test] - #[should_panic] - fn test_assert_packet_received() { - let (mut w, _) = init_world(); - - let player = add_player(&mut w); - assert_packet_received(&player, PacketType::Handshake); - } - - #[test] - #[should_panic] - fn test_assert_disconnected() { - let (mut w, _) = init_world(); - - let player = add_player(&mut w); - assert_disconnected(&player); - } - - #[test] - #[should_panic] - fn test_assert_not_disconnected() { - let (mut w, _) = init_world(); - - let disconnect = DisconnectPlay::new("bla".to_string()); - - let player = add_player(&mut w); - send_packet_to_player(w.read_component().get(player.entity).unwrap(), disconnect); - assert_not_disconnected(&player); - } -} diff --git a/server/src/time.rs b/server/src/time.rs deleted file mode 100644 index 450fc47e6..000000000 --- a/server/src/time.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Handles world time. - -use crate::joinhandler::PlayerJoinEvent; -use crate::network::{send_packet_to_player, NetworkComponent}; -use crate::systems::{TIME_INCREMENT, TIME_SEND}; -use feather_core::level::LevelData; -use feather_core::packet::TimeUpdate; -use shrev::EventChannel; -use specs::{DispatcherBuilder, Read, ReadStorage, ReaderId, System, World, Write}; - -/// The current time of the world. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deref, DerefMut, Default)] -pub struct Time(pub u64); - -impl Time { - /// Returns the time of day. This is calculated - /// as `time.0 % 24_000`. - pub fn time_of_day(self) -> u64 { - self.0 % 24_000 - } - - /// Returns the age of the world in ticks. Equivalent to `time.0`. - pub fn world_age(self) -> u64 { - self.0 - } -} - -/// Initializes systems for this module. -pub fn init_logic(dispatcher: &mut DispatcherBuilder) { - dispatcher.add(TimeIncrementSystem, TIME_INCREMENT, &[]); - dispatcher.add(TimeSendSystem::default(), TIME_SEND, &[]); -} - -/// Initializes the time for the world, given the -/// level file. -pub fn init_time(world: &mut World, level: &LevelData) { - world.insert(Time(level.time as u64)) -} - -/// System for incrementing time each tick. -pub struct TimeIncrementSystem; - -impl<'a> System<'a> for TimeIncrementSystem { - type SystemData = Write<'a, Time>; - - fn run(&mut self, mut time: Self::SystemData) { - time.0 += 1; - } -} - -/// System for sending world time to players -/// upon joining. -/// -/// This system listens to `PlayerJoinEvent`s. -#[derive(Default)] -pub struct TimeSendSystem { - reader: Option<ReaderId<PlayerJoinEvent>>, -} - -impl<'a> System<'a> for TimeSendSystem { - type SystemData = ( - ReadStorage<'a, NetworkComponent>, - Read<'a, EventChannel<PlayerJoinEvent>>, - Read<'a, Time>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (networks, join_events, time) = data; - - for event in join_events.read(self.reader.as_mut().unwrap()) { - let network = networks.get(event.player).unwrap(); - - // Send time to player. - let packet = TimeUpdate { - world_age: time.world_age() as i64, - time_of_day: time.time_of_day() as i64, - }; - - send_packet_to_player(network, packet); - } - } - - setup_impl!(reader); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::testframework as t; - use feather_core::{network::cast_packet, PacketType}; - use shrev::EventChannel; - use specs::WorldExt; - - #[test] - fn test_time_init() { - let mut level = LevelData::default(); - let time = 29456; - level.time = time as i64; - - let mut world = World::new(); - init_time(&mut world, &level); - - assert_eq!(*world.fetch::<Time>(), Time(time)); - } - - #[test] - fn test_time_increment_system() { - let (mut w, mut d) = t::builder().with(TimeIncrementSystem, "").build(); - - d.dispatch(&w); - w.maintain(); - - assert_eq!(*w.fetch::<Time>(), Time(1)); - } - - #[test] - fn test_time_send_system() { - let (mut w, mut d) = t::builder().with(TimeSendSystem::default(), "").build(); - - let player = t::add_player(&mut w); - - let event = PlayerJoinEvent { - player: player.entity, - }; - w.fetch_mut::<EventChannel<_>>().single_write(event); - - d.dispatch(&w); - w.maintain(); - - let packet = t::assert_packet_received(&player, PacketType::TimeUpdate); - let packet = cast_packet::<TimeUpdate>(&*packet); - - assert_eq!(packet.time_of_day, 0); - assert_eq!(packet.world_age, 0); - } -} diff --git a/server/src/util/broadcaster.rs b/server/src/util/broadcaster.rs deleted file mode 100644 index 7da99c586..000000000 --- a/server/src/util/broadcaster.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Implements a broadcaster, used to lazily broadcast -//! packets to players able to see a given entity. - -use crate::chunk_logic::ChunkHolders; -use crate::entity::PositionComponent; -use crate::network::{send_packet_boxed_to_player, NetworkComponent}; -use crate::util::Util; -use crossbeam::queue::SegQueue; -use feather_core::{ChunkPosition, Packet}; -use specs::{Entities, Entity, Read, ReadStorage, System}; - -/// Broadcaster used to lazily broadcast packets. -#[derive(Default)] -pub struct Broadcaster { - /// Internal queue of broadcasts to send. - queue: SegQueue<BroadcastRequest>, -} - -impl Broadcaster { - /// Lazily broadcasts a packet to all players - /// able to see a given entity. - pub fn broadcast_entity_update<P>(&self, entity: Entity, packet: P, neq: Option<Entity>) - where - P: Packet + 'static, - { - self.queue.push(BroadcastRequest { - condition: BroadcastCondition::Entity(entity), - packet: Box::new(packet), - neq, - }); - } - - /// Lazily broadcasts a packet to all players - /// able to see a given chunk. - pub fn broadcast_chunk_update<P>(&self, chunk: ChunkPosition, packet: P, neq: Option<Entity>) - where - P: Packet + 'static, - { - self.queue.push(BroadcastRequest { - condition: BroadcastCondition::Chunk(chunk), - packet: Box::new(packet), - neq, - }); - } - - /// Lazily sends a packet to a player. - pub fn lazy_send_packet_to_player<P>(&self, player: Entity, packet: P) - where - P: Packet + 'static, - { - self.queue.push(BroadcastRequest { - condition: BroadcastCondition::ToPlayer(player), - packet: Box::new(packet), - neq: None, // No effect - }); - } -} - -/// A broadcast request. -struct BroadcastRequest { - /// Packet will only be sent to players able to see - /// this entity or chunk. - condition: BroadcastCondition, - /// The packet to broadcast. - packet: Box<dyn Packet>, - /// Optional entity not to send to. - neq: Option<Entity>, -} - -#[derive(Debug, Clone, Copy)] -enum BroadcastCondition { - Entity(Entity), - Chunk(ChunkPosition), - ToPlayer(Entity), -} - -/// System for flushing the `Broadcaster` queue and broadcasting -/// the necessary packets. -pub struct BroadcasterSystem; - -impl<'a> System<'a> for BroadcasterSystem { - type SystemData = ( - ReadStorage<'a, PositionComponent>, - ReadStorage<'a, NetworkComponent>, - Read<'a, Util>, - Read<'a, ChunkHolders>, - Entities<'a>, - ); - - fn run(&mut self, data: Self::SystemData) { - let (positions, networks, util, chunk_holders, entities) = data; - - let broadcaster = &util.broadcaster; - - while let Ok(request) = broadcaster.queue.pop() { - // Broadcast packet. - // Iterate over entities in the chunk_holders - // entry for the chunk. If they are a player, - // send the packet. - // This works because any player able to see - // a chunk will always have a chunk holder on the chunk. - - let chunk = match request.condition { - BroadcastCondition::Entity(entity) => { - // Prevents a panic if the entity was destroyed. - if !entities.is_alive(entity) { - continue; - } - - positions.get(entity).unwrap().current.chunk_pos() - } - BroadcastCondition::Chunk(chunk) => chunk, - BroadcastCondition::ToPlayer(player) => { - if entities.is_alive(player) { - send_packet_boxed_to_player(networks.get(player).unwrap(), request.packet); - } - - continue; // Special case - no chunk - } - }; - if let Some(holders) = chunk_holders.holders_for(chunk) { - for holder in holders { - if let Some(neq) = request.neq.as_ref() { - if *holder == *neq { - continue; - } - } - - if let Some(network) = networks.get(*holder) { - send_packet_boxed_to_player(network, request.packet.box_clone()); - } - } - } - } - } -} diff --git a/server/src/util/macros.rs b/server/src/util/macros.rs deleted file mode 100644 index 66e6b841a..000000000 --- a/server/src/util/macros.rs +++ /dev/null @@ -1,70 +0,0 @@ -/// Asserts that a floating-point value is within -/// a certain range of the expected value. -#[cfg(test)] -macro_rules! assert_float_eq { - ($left:expr, $right:expr) => { - assert_float_eq!($left, $right, 0.001); - }; - ($left:expr, $right:expr, $range:expr) => { - let range = ($left - $range)..($left + $range); - assert!(range.contains(&$right)); - }; -} - -/// Checks that two positions are approximately equivalent. -#[cfg(test)] -macro_rules! assert_pos_eq { - ($left:expr, $right:expr) => { - assert_float_eq!($left.x, $right.x, 0.01); - assert_float_eq!($left.y, $right.y, 0.01); - assert_float_eq!($left.z, $right.z, 0.011); - }; -} - -/// Generates a setup() implementation for a system -/// which initializes an internal event reader. -macro_rules! setup_impl { - ($($reader:ident),+) => { - fn setup(&mut self, world: &mut specs::World) { - use specs::SystemData; - use shrev::EventChannel; - Self::SystemData::setup(world); - - $(self.$reader = Some(world.fetch_mut::<EventChannel<_>>().register_reader());)+ - } - }; -} - -macro_rules! flagged_setup_impl { - ($component:ident, $reader:ident) => { - fn setup(&mut self, world: &mut specs::World) { - use specs::{SystemData, WorldExt}; - Self::SystemData::setup(world); - - self.$reader = Some(world.write_component::<$component>().register_reader()); - } - } -} - -macro_rules! read_flagged_events { - ($storage:ident, $reader:expr, $dirty:expr) => { - for event in $storage.channel().read($reader.as_mut().unwrap()) { - match event { - ComponentEvent::Inserted(id) | ComponentEvent::Modified(id) => { - $dirty.add(*id); - } - _ => (), - } - } - }; -} - -macro_rules! continue_if_none { - ($option:expr) => { - if let Some(value) = $option { - value - } else { - continue; - } - }; -} diff --git a/server/src/util/mod.rs b/server/src/util/mod.rs deleted file mode 100644 index e3798445a..000000000 --- a/server/src/util/mod.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! Assorted utilities for use in Feather's codebase. -use bumpalo::Bump; -use feather_core::{ChunkPosition, Packet}; -use glm::DVec3; -use thread_local::ThreadLocal; - -#[macro_use] -mod macros; -mod broadcaster; - -use broadcaster::Broadcaster; -pub use broadcaster::BroadcasterSystem; -pub use macros::*; -use specs::Entity; - -/// Converts float-based velocity in blocks per tick -/// to the format used by the protocol. -pub fn protocol_velocity(vel: DVec3) -> (i16, i16, i16) { - // Apparently, these are in units of 1/8000 block per tick. - ( - (vel.x * 8000.0) as i16, - (vel.y * 8000.0) as i16, - (vel.z * 8000.0) as i16, - ) -} - -/// General-purpose utility resource, used to -/// ergonomically perform various actions without -/// specifying ridiculous amounts of system dependencies. -/// -/// This struct is thread-safe and should never be used -/// as a `Write` dependency. -/// -/// # Available functions -/// * `alloc` - used to allocate temporary values -/// using a bump allocator. When allocating values -/// which will only be used inside a function, for example, -/// this function should be used rather than allocating -/// directly on the heap. -/// * `broadcast` - lazily broadcasts a packet to all players -/// who are able to see a given chunk. This can be used -/// to broadcast movement updates, for example. -#[derive(Default)] -pub struct Util { - /// Thread-local bump allocator, reset - /// every tick. - /// - /// This is used to reduce allocation frequency. - bump: ThreadLocal<Bump>, - /// The broadcaster, used to lazily broadcast packets. - broadcaster: Broadcaster, -} - -impl Util { - /// Returns the thread-local bump allocator. - pub fn bump(&self) -> &Bump { - self.bump.get_or_default() - } - - /// Allocates a value using the bump allocator - /// for this thread. - /// - /// This is equivalent to `Util::bump().alloc(value)`. - #[allow(clippy::mut_from_ref)] // This is sound—it just redirects to `bumpalo`. - pub fn alloc<T>(&self, value: T) -> &mut T { - self.bump().alloc(value) - } - - /// This should be called at the end of every tick. - pub fn reset(&mut self) { - // Reset bump allocators - for bump in self.bump.iter_mut() { - bump.reset(); - } - } - - /// Broadcasts a packet to all players who - /// are able to see a given entity. - /// - /// The packet is sent lazily in a separate system. - /// - /// If `neq` is set to an entity, the packet - /// will not be sent to that player. - /// - /// This function runs in linear time with - /// regard to the number of players able to see - /// the entity. - pub fn broadcast_entity_update<P>(&self, entity: Entity, packet: P, neq: Option<Entity>) - where - P: Packet + 'static, - { - self.broadcaster - .broadcast_entity_update(entity, packet, neq); - } - - /// Broadcasts a packet to all players who - /// are able to see a given chunk. - /// - /// The packet is sent lazily in a separate system. - /// - /// If `neq` is set to an entity, the packet - /// will not be sent to that player. - /// - /// This function runs in linear time with - /// regard to the number of players able to see - /// the chunk. - pub fn broadcast_chunk_update<P>(&self, chunk: ChunkPosition, packet: P, neq: Option<Entity>) - where - P: Packet + 'static, - { - self.broadcaster.broadcast_chunk_update(chunk, packet, neq); - } - - /// Similar to `broadcast_*_update`, but only sends to the specified - /// player. - /// - /// This can be used when a packet needs to be sent to a specified - /// player before another packet is broadcasted. - pub fn lazy_send_packet_to_player<P>(&self, player: Entity, packet: P) - where - P: Packet + 'static, - { - self.broadcaster.lazy_send_packet_to_player(player, packet); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::chunk_logic::ChunkHolders; - use crate::testframework as t; - use crate::util::broadcaster::BroadcasterSystem; - use feather_core::network::packet::implementation::EntityHeadLook; - use feather_core::PacketType; - use specs::WorldExt; - - #[test] - fn test_broadcast() { - let mut chunk_holders = ChunkHolders::default(); - - let chunk = ChunkPosition::new(0, 0); - let other_chunk = ChunkPosition::new(10, 1); - - let (mut world, mut dispatcher) = t::builder().with(BroadcasterSystem, "").build(); - let player1 = t::add_player(&mut world); - let player2 = t::add_player(&mut world); - let player3 = t::add_player(&mut world); - - chunk_holders.insert_holder(chunk, player1.entity); - chunk_holders.insert_holder(chunk, player2.entity); - chunk_holders.insert_holder(other_chunk, player3.entity); - - let packet = EntityHeadLook::default(); - - let util = Util::default(); - - util.broadcast_entity_update(player1.entity, packet, Some(player2.entity)); - - world.insert(util); - world.insert(chunk_holders); - - dispatcher.dispatch(&world); - world.maintain(); - - t::assert_packet_received(&player1, PacketType::EntityHeadLook); - t::assert_packet_not_received(&player2, PacketType::EntityHeadLook); - t::assert_packet_not_received(&player3, PacketType::EntityHeadLook); - } -} diff --git a/server/src/worldgen/finishers/snow.rs b/server/src/worldgen/finishers/snow.rs deleted file mode 100644 index aa0ff6f68..000000000 --- a/server/src/worldgen/finishers/snow.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::worldgen::{ChunkBiomes, FinishingGenerator, TopBlocks}; -use feather_blocks::{Block, SnowData}; -use feather_core::{Biome, Chunk}; - -/// Finisher for generating snow on top of snow biomes. -#[derive(Default)] -pub struct SnowFinisher; - -impl FinishingGenerator for SnowFinisher { - fn generate_for_chunk( - &self, - chunk: &mut Chunk, - biomes: &ChunkBiomes, - top_blocks: &TopBlocks, - _seed: u64, - ) { - for x in 0..16 { - for z in 0..16 { - if !is_snowy_biome(biomes.biome_at(x, z)) { - continue; - } - - chunk.set_block_at( - x, - top_blocks.top_block_at(x, z) + 1, - z, - Block::Snow(SnowData { layers: 1 }), - ) - } - } - } -} - -fn is_snowy_biome(biome: Biome) -> bool { - match biome { - Biome::SnowyTundra - | Biome::IceSpikes - | Biome::SnowyTaiga - | Biome::SnowyTaigaMountains - | Biome::SnowyBeach => true, - _ => false, - } -} diff --git a/server/src/worldgen/superflat.rs b/server/src/worldgen/superflat.rs deleted file mode 100644 index c9039c5af..000000000 --- a/server/src/worldgen/superflat.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::worldgen::WorldGenerator; -use feather_blocks::Block; -use feather_core::level::SuperflatGeneratorOptions; -use feather_core::{Biome, Chunk, ChunkPosition}; - -pub struct SuperflatWorldGenerator { - pub options: SuperflatGeneratorOptions, -} - -impl WorldGenerator for SuperflatWorldGenerator { - fn generate_chunk(&self, position: ChunkPosition) -> Chunk { - let biome = Biome::from_identifier(self.options.biome.as_str()).unwrap_or(Biome::Plains); - let mut chunk = Chunk::new_with_default_biome(position, biome); - - let mut y_counter = 0; - for layer in self.options.clone().layers { - if layer.height == 0 { - continue; - } - let layer_block = Block::from_name_and_default_props(layer.block.as_str()); - if layer_block.is_none() { - // Skip this layer - debug!("Failed to generate layer: unknown block {}", layer.block); - y_counter += layer.height; - continue; - } - let layer_block = layer_block.unwrap(); - for y in y_counter..(y_counter + layer.height) { - for x in 0..16 { - for z in 0..16 { - chunk.set_block_at(x as usize, y as usize, z as usize, layer_block); - } - } - } - y_counter += layer.height; - } - chunk - } -} - -#[cfg(test)] -mod tests { - use super::*; - use feather_blocks::GrassBlockData; - - #[test] - pub fn test_worldgen_flat() { - let mut options = SuperflatGeneratorOptions::default(); - options.biome = Biome::Mountains.identifier().to_string(); - - let chunk_pos = ChunkPosition { x: 1, z: 2 }; - let generator = SuperflatWorldGenerator { options }; - let chunk = generator.generate_chunk(chunk_pos); - - assert_eq!(chunk.position(), chunk_pos); - for x in 0usize..16 { - for z in 0usize..16 { - for (y, block) in &[ - (0usize, Block::Bedrock), - (1usize, Block::Dirt), - (2usize, Block::Dirt), - (3usize, Block::GrassBlock(GrassBlockData { snowy: false })), - ] { - assert_eq!(chunk.block_at(x, *y, z), *block); - } - for y in 4..256 { - assert_eq!( - chunk.block_at(x as usize, y as usize, z as usize), - Block::Air - ); - } - assert_eq!(chunk.biome_at(x, z), Biome::Mountains); - } - } - } -} diff --git a/util/rand-legacy/src/lib.rs b/util/rand-legacy/src/lib.rs deleted file mode 100644 index 41891cf16..000000000 --- a/util/rand-legacy/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub use rand::*;